[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n*        text=auto\n\n*.cs     text diff=csharp\n*.java   text diff=java\n*.html   text diff=html\n*.py     text diff=python\n*.pl     text diff=perl\n*.pm     text diff=perl\n*.css    text\n*.js     text\n*.sql    text\n\n*.sh     text eol=lf\n\n*.bat    text eol=crlf\n*.cmd    text eol=crlf\n*.csproj text merge=union eol=crlf\n*.sln    text merge=union eol=crlf\n"
  },
  {
    "path": ".gitignore",
    "content": "# Java\nhs_err_pid*\n\n# Git\n*.orij\n*.rej\n\n# SVN\n.svn\n.revision\n\n# Eclipse\n.metadata\n.classpath\n.eclipse/\n.idea/\n.project\n.revision/\n.settings/\n.externalToolBuilders/\nlocal.properties\n.recommenders\n*.launch\nbuild/\ntarget/\nout/\n\n# Intellij\n*.ipr\n*.iws\n*.iml\n\n# NetBeans\n*~.nib\nnbbuild/\ndist/\nnbdist/\n.ndb-gradle/\n.cproject\n.buildpath\n\n# Other\n*~\nlogs/\n*.out\n*.log\n*.bak\n*.tmp\ntmp/**\ntmp/**/*\n.DS_Store\n.gradle\n*.patch\n*.swp\ngenerated\n\n# C\ntags\n.cproject\n.project\nobj\nsrc/c/core.*\nsrc/c/TEST-*.txt\nsrc/c/*.la\nsrc/c/*.lo\nsrc/c/*.o\nsrc/c/generated/\nsrc/java/generated/\nsrc/java/lib/ant-eclipse-*\nsrc/java/lib/ivy-*\nsrc/c/Makefile.in\nsrc/c/aclocal.m4\nsrc/c/autom4te.cache/\nsrc/c/compile\nsrc/c/config.guess\nsrc/c/config.h.in\nsrc/c/config.sub\nsrc/c/configure\nsrc/c/depcomp\nsrc/c/install-sh\nsrc/c/ltmain.sh\nsrc/c/missing\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "NOTICE.txt",
    "content": "Apache ZooKeeper\nCopyright 2009-2018 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n"
  },
  {
    "path": "README_packaging.txt",
    "content": "README file for Packaging Notes\n\nRequirement\n-----------\n\ngcc, cppunit and python-setuptools are required to build \nC and python bindings.\n\nOn RHEL machine:\n\nyum install cppunit\nyum install python-setuptools\n\nOn Ubuntu:\n\napt-get --install cppunit\napt-get --install python-setuptools\n\nPackage build command\n---------------------\n\nCommand to build Debian package: ant deb\nCommand to build RPM Package: ant rpm\n\nrpm and deb packages are generated and placed in:\n\nbuild/zookeeper*.[rpm|deb]\nbuild/contrib/**.[rpm|deb]\n\nDefault package file structure layout\n\n  /usr/bin                           - User executable\n  /usr/sbin                          - System executable\n  /usr/libexec                       - Configuration boot trap script\n  /usr/lib                           - Native libraries\n  /usr/share/doc/zookeeper           - Documents\n  /usr/share/zookeeper               - Project files\n  /usr/share/zookeeper/template/conf - Configuration template files\n  /etc/zookeeper                     - Configuration files\n  /etc/init.d/zookeeper              - OS startup script\n\nSource file structure layout\n---------------------\n\nsrc/packages/update-zookeeper-env.sh \n  - setup environment variables and symlink $PREFIX/etc/zookeeper to \n    /etc/zookeeper.\n  - This script is designed to run in post installation, and pre-remove \n    phase of ZooKeeper package.\n  - Run update-zookeeper-env.sh -h to get a list of supported parameters.\n\nsrc/packages/template\n  - Standard configuration template\n\nsrc/packages/deb \n  Meta data for creating Debian package\n\nsrc/packages/deb/init.d\n  Daemon start/stop script for Debian flavor of Linux\n\nsrc/packages/rpm \n  Meta data for creating RPM package\n\nsrc/packages/rpm/init.d\n  Daemon start/stop script for Redhat flavor of Linux\n"
  },
  {
    "path": "bin/README.txt",
    "content": "This directory contain scripts that allow easy access (classpath in particular)\nto the ZooKeeper server and command line client.\n\nFiles ending in .sh are unix and cygwin compatible\n\nFiles ending in .cmd are msdos/windows compatible\n"
  },
  {
    "path": "bin/zkCleanup.sh",
    "content": "#!/usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#\n# This script cleans up old transaction logs and snapshots\n#\n\n#\n# If this scripted is run out of /usr/bin or some other system bin directory\n# it should be linked to and not copied. Things like java jar files are found\n# relative to the canonical path of this script.\n#\n\n# use POSTIX interface, symlink is followed automatically\nZOOBIN=\"${BASH_SOURCE-$0}\"\nZOOBIN=\"$(dirname \"${ZOOBIN}\")\"\nZOOBINDIR=\"$(cd \"${ZOOBIN}\"; pwd)\"\n\nif [ -e \"$ZOOBIN/../libexec/zkEnv.sh\" ]; then\n  . \"$ZOOBINDIR\"/../libexec/zkEnv.sh\nelse\n  . \"$ZOOBINDIR\"/zkEnv.sh\nfi\n\nZOODATADIR=\"$(grep \"^[[:space:]]*dataDir=\" \"$ZOOCFG\" | sed -e 's/.*=//')\"\nZOODATALOGDIR=\"$(grep \"^[[:space:]]*dataLogDir=\" \"$ZOOCFG\" | sed -e 's/.*=//')\"\n\nif [ \"x$ZOODATALOGDIR\" = \"x\" ]\nthen\n\"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n     -cp \"$CLASSPATH\" $JVMFLAGS \\\n     org.apache.zookeeper.server.PurgeTxnLog \"$ZOODATADIR\" $*\nelse\n\"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n     -cp \"$CLASSPATH\" $JVMFLAGS \\\n     org.apache.zookeeper.server.PurgeTxnLog \"$ZOODATALOGDIR\" \"$ZOODATADIR\" $*\nfi\n"
  },
  {
    "path": "bin/zkCli.cmd",
    "content": "@echo off\r\nREM Licensed to the Apache Software Foundation (ASF) under one or more\r\nREM contributor license agreements.  See the NOTICE file distributed with\r\nREM this work for additional information regarding copyright ownership.\r\nREM The ASF licenses this file to You under the Apache License, Version 2.0\r\nREM (the \"License\"); you may not use this file except in compliance with\r\nREM the License.  You may obtain a copy of the License at\r\nREM\r\nREM     http://www.apache.org/licenses/LICENSE-2.0\r\nREM\r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\n\r\nsetlocal\r\ncall \"%~dp0zkEnv.cmd\"\r\n\r\nset ZOOMAIN=org.apache.zookeeper.ZooKeeperMain\r\ncall %JAVA% \"-Dzookeeper.log.dir=%ZOO_LOG_DIR%\" \"-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%\" -cp \"%CLASSPATH%\" %ZOOMAIN% %*\r\n\r\nendlocal\r\n\r\n"
  },
  {
    "path": "bin/zkCli.sh",
    "content": "#!/usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#\n# This script cleans up old transaction logs and snapshots\n#\n\n#\n# If this scripted is run out of /usr/bin or some other system bin directory\n# it should be linked to and not copied. Things like java jar files are found\n# relative to the canonical path of this script.\n#\n\n# use POSTIX interface, symlink is followed automatically\nZOOBIN=\"${BASH_SOURCE-$0}\"\nZOOBIN=\"$(dirname \"${ZOOBIN}\")\"\nZOOBINDIR=\"$(cd \"${ZOOBIN}\"; pwd)\"\n\nif [ -e \"$ZOOBIN/../libexec/zkEnv.sh\" ]; then\n  . \"$ZOOBINDIR\"/../libexec/zkEnv.sh\nelse\n  . \"$ZOOBINDIR\"/zkEnv.sh\nfi\n\n\"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n     -cp \"$CLASSPATH\" $CLIENT_JVMFLAGS $JVMFLAGS \\\n     org.apache.zookeeper.ZooKeeperMain \"$@\"\n"
  },
  {
    "path": "bin/zkEnv.cmd",
    "content": "@echo off\r\nREM Licensed to the Apache Software Foundation (ASF) under one or more\r\nREM contributor license agreements.  See the NOTICE file distributed with\r\nREM this work for additional information regarding copyright ownership.\r\nREM The ASF licenses this file to You under the Apache License, Version 2.0\r\nREM (the \"License\"); you may not use this file except in compliance with\r\nREM the License.  You may obtain a copy of the License at\r\nREM\r\nREM     http://www.apache.org/licenses/LICENSE-2.0\r\nREM\r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\n\r\nset ZOOCFGDIR=%~dp0%..\\conf\r\nset ZOO_LOG_DIR=%~dp0%..\r\nset ZOO_LOG4J_PROP=INFO,CONSOLE\r\n\r\nREM for sanity sake assume Java 1.6\r\nREM see: http://java.sun.com/javase/6/docs/technotes/tools/windows/java.html\r\n\r\nREM add the zoocfg dir to classpath\r\nset CLASSPATH=%ZOOCFGDIR%\r\n\r\nREM make it work in the release\r\nSET CLASSPATH=%~dp0..\\*;%~dp0..\\lib\\*;%CLASSPATH%\r\n\r\nREM make it work for developers\r\nSET CLASSPATH=%~dp0..\\build\\classes;%~dp0..\\build\\lib\\*;%CLASSPATH%\r\n\r\nset ZOOCFG=%ZOOCFGDIR%\\zoo.cfg\r\n\r\n@REM setup java environment variables\r\n\r\nif not defined JAVA_HOME (\r\n  echo Error: JAVA_HOME is not set.\r\n  goto :eof\r\n)\r\n\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\n\r\nif not exist \"%JAVA_HOME%\"\\bin\\java.exe (\r\n  echo Error: JAVA_HOME is incorrectly set.\r\n  goto :eof\r\n)\r\n\r\nREM strip off trailing \\ from JAVA_HOME or java does not start\r\nif \"%JAVA_HOME:~-1%\" EQU \"\\\" set \"JAVA_HOME=%JAVA_HOME:~0,-1%\"\r\n \r\nset JAVA=\"%JAVA_HOME%\"\\bin\\java\r\n"
  },
  {
    "path": "bin/zkEnv.sh",
    "content": "#!/usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This script should be sourced into other zookeeper\n# scripts to setup the env variables\n\n# We use ZOOCFGDIR if defined,\n# otherwise we use /etc/zookeeper\n# or the conf directory that is\n# a sibling of this script's directory\n\nZOOBINDIR=\"${ZOOBINDIR:-/usr/bin}\"\nZOOKEEPER_PREFIX=\"${ZOOBINDIR}/..\"\n\nif [ \"x$ZOOCFGDIR\" = \"x\" ]\nthen\n  if [ -e \"${ZOOKEEPER_PREFIX}/conf\" ]; then\n    ZOOCFGDIR=\"$ZOOBINDIR/../conf\"\n  else\n    ZOOCFGDIR=\"$ZOOBINDIR/../etc/zookeeper\"\n  fi\nfi\n\nif [ -f \"${ZOOCFGDIR}/zookeeper-env.sh\" ]; then\n  . \"${ZOOCFGDIR}/zookeeper-env.sh\"\nfi\n\nif [ \"x$ZOOCFG\" = \"x\" ]\nthen\n    ZOOCFG=\"zoo.cfg\"\nfi\n\nZOOCFG=\"$ZOOCFGDIR/$ZOOCFG\"\n\nif [ -f \"$ZOOCFGDIR/java.env\" ]\nthen\n    . \"$ZOOCFGDIR/java.env\"\nfi\n\nif [ \"x${ZOO_LOG_DIR}\" = \"x\" ]\nthen\n    ZOO_LOG_DIR=\".\"\nfi\n\nif [ \"x${ZOO_LOG4J_PROP}\" = \"x\" ]\nthen\n    ZOO_LOG4J_PROP=\"INFO,CONSOLE\"\nfi\n\nif [ \"$JAVA_HOME\" != \"\" ]; then\n  JAVA=\"$JAVA_HOME/bin/java\"\nelse\n  JAVA=java\nfi\n\n#add the zoocfg dir to classpath\nCLASSPATH=\"$ZOOCFGDIR:$CLASSPATH\"\n\nfor i in \"$ZOOBINDIR\"/../src/java/lib/*.jar\ndo\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\n#make it work in the binary package\n#(use array for LIBPATH to account for spaces within wildcard expansion)\nif [ -e \"${ZOOKEEPER_PREFIX}\"/share/zookeeper/zookeeper-*.jar ]; then\n  LIBPATH=(\"${ZOOKEEPER_PREFIX}\"/share/zookeeper/*.jar)\nelse\n  #release tarball format\n  for i in \"$ZOOBINDIR\"/../zookeeper-*.jar\n  do\n    CLASSPATH=\"$i:$CLASSPATH\"\n  done\n  LIBPATH=(\"${ZOOBINDIR}\"/../lib/*.jar)\nfi\n\nfor i in \"${LIBPATH[@]}\"\ndo\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\n#make it work for developers\nfor d in \"$ZOOBINDIR\"/../build/lib/*.jar\ndo\n   CLASSPATH=\"$d:$CLASSPATH\"\ndone\n\n#make it work for developers\nCLASSPATH=\"$ZOOBINDIR/../build/classes:$CLASSPATH\"\n\ncase \"`uname`\" in\n    CYGWIN*) cygwin=true ;;\n    *) cygwin=false ;;\nesac\n\nif $cygwin\nthen\n    CLASSPATH=`cygpath -wp \"$CLASSPATH\"`\nfi\n\n#echo \"CLASSPATH=$CLASSPATH\""
  },
  {
    "path": "bin/zkServer.cmd",
    "content": "@echo off\r\nREM Licensed to the Apache Software Foundation (ASF) under one or more\r\nREM contributor license agreements.  See the NOTICE file distributed with\r\nREM this work for additional information regarding copyright ownership.\r\nREM The ASF licenses this file to You under the Apache License, Version 2.0\r\nREM (the \"License\"); you may not use this file except in compliance with\r\nREM the License.  You may obtain a copy of the License at\r\nREM\r\nREM     http://www.apache.org/licenses/LICENSE-2.0\r\nREM\r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\n\r\nsetlocal\r\ncall \"%~dp0zkEnv.cmd\"\r\n\r\nset ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain\r\necho on\r\ncall %JAVA% \"-Dzookeeper.log.dir=%ZOO_LOG_DIR%\" \"-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%\" -cp \"%CLASSPATH%\" %ZOOMAIN% \"%ZOOCFG%\" %*\r\n\r\nendlocal\r\n"
  },
  {
    "path": "bin/zkServer.sh",
    "content": "#!/usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#\n# If this scripted is run out of /usr/bin or some other system bin directory\n# it should be linked to and not copied. Things like java jar files are found\n# relative to the canonical path of this script.\n#\n\n\n\n# use POSTIX interface, symlink is followed automatically\nZOOBIN=\"${BASH_SOURCE-$0}\"\nZOOBIN=\"$(dirname \"${ZOOBIN}\")\"\nZOOBINDIR=\"$(cd \"${ZOOBIN}\"; pwd)\"\n\nif [ -e \"$ZOOBIN/../libexec/zkEnv.sh\" ]; then\n  . \"$ZOOBINDIR/../libexec/zkEnv.sh\"\nelse\n  . \"$ZOOBINDIR/zkEnv.sh\"\nfi\n\n# See the following page for extensive details on setting\n# up the JVM to accept JMX remote management:\n# http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html\n# by default we allow local JMX connections\nif [ \"x$JMXLOCALONLY\" = \"x\" ]\nthen\n    JMXLOCALONLY=false\nfi\n\nif [ \"x$JMXDISABLE\" = \"x\" ] || [ \"$JMXDISABLE\" = 'false' ]\nthen\n  echo \"ZooKeeper JMX enabled by default\" >&2\n  if [ \"x$JMXPORT\" = \"x\" ]\n  then\n    # for some reason these two options are necessary on jdk6 on Ubuntu\n    #   accord to the docs they are not necessary, but otw jconsole cannot\n    #   do a local attach\n    ZOOMAIN=\"-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain\"\n  else\n    if [ \"x$JMXAUTH\" = \"x\" ]\n    then\n      JMXAUTH=false\n    fi\n    if [ \"x$JMXSSL\" = \"x\" ]\n    then\n      JMXSSL=false\n    fi\n    if [ \"x$JMXLOG4J\" = \"x\" ]\n    then\n      JMXLOG4J=true\n    fi\n    echo \"ZooKeeper remote JMX Port set to $JMXPORT\" >&2\n    echo \"ZooKeeper remote JMX authenticate set to $JMXAUTH\" >&2\n    echo \"ZooKeeper remote JMX ssl set to $JMXSSL\" >&2\n    echo \"ZooKeeper remote JMX log4j set to $JMXLOG4J\" >&2\n    ZOOMAIN=\"-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMXPORT -Dcom.sun.management.jmxremote.authenticate=$JMXAUTH -Dcom.sun.management.jmxremote.ssl=$JMXSSL -Dzookeeper.jmx.log4j.disable=$JMXLOG4J org.apache.zookeeper.server.quorum.QuorumPeerMain\"\n  fi\nelse\n    echo \"JMX disabled by user request\" >&2\n    ZOOMAIN=\"org.apache.zookeeper.server.quorum.QuorumPeerMain\"\nfi\n\nif [ \"x$SERVER_JVMFLAGS\"  != \"x\" ]\nthen\n    JVMFLAGS=\"$SERVER_JVMFLAGS $JVMFLAGS\"\nfi\n\nif [ \"x$2\" != \"x\" ]\nthen\n    ZOOCFG=\"$ZOOCFGDIR/$2\"\nfi\n\n# if we give a more complicated path to the config, don't screw around in $ZOOCFGDIR\nif [ \"x$(dirname \"$ZOOCFG\")\" != \"x$ZOOCFGDIR\" ]\nthen\n    ZOOCFG=\"$2\"\nfi\n\nif $cygwin\nthen\n    ZOOCFG=`cygpath -wp \"$ZOOCFG\"`\n    # cygwin has a \"kill\" in the shell itself, gets confused\n    KILL=/bin/kill\nelse\n    KILL=kill\nfi\n\necho \"Using config: $ZOOCFG\" >&2\n\ncase \"$OSTYPE\" in\n*solaris*)\n  GREP=/usr/xpg4/bin/grep\n  ;;\n*)\n  GREP=grep\n  ;;\nesac\nif [ -z \"$ZOOPIDFILE\" ]; then\n    ZOO_DATADIR=\"$($GREP \"^[[:space:]]*dataDir\" \"$ZOOCFG\" | sed -e 's/.*=//')\"\n    if [ ! -d \"$ZOO_DATADIR\" ]; then\n        mkdir -p \"$ZOO_DATADIR\"\n    fi\n    ZOOPIDFILE=\"$ZOO_DATADIR/zookeeper_server.pid\"\nelse\n    # ensure it exists, otw stop will fail\n    mkdir -p \"$(dirname \"$ZOOPIDFILE\")\"\nfi\n\nif [ ! -w \"$ZOO_LOG_DIR\" ] ; then\nmkdir -p \"$ZOO_LOG_DIR\"\nfi\n\n_ZOO_DAEMON_OUT=\"$ZOO_LOG_DIR/zookeeper.out\"\n\ncase $1 in\nstart)\n    echo  -n \"Starting zookeeper ... \"\n    if [ -f \"$ZOOPIDFILE\" ]; then\n      if kill -0 `cat \"$ZOOPIDFILE\"` > /dev/null 2>&1; then\n         echo $command already running as process `cat \"$ZOOPIDFILE\"`. \n         exit 0\n      fi\n    fi\n    nohup \"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n    -cp \"$CLASSPATH\" $JVMFLAGS $ZOOMAIN \"$ZOOCFG\" > \"$_ZOO_DAEMON_OUT\" 2>&1 < /dev/null &\n    if [ $? -eq 0 ]\n    then\n      case \"$OSTYPE\" in\n      *solaris*)\n        /bin/echo \"${!}\\\\c\" > \"$ZOOPIDFILE\"\n        ;;\n      *)\n        /bin/echo -n $! > \"$ZOOPIDFILE\"\n        ;;\n      esac\n      if [ $? -eq 0 ];\n      then\n        sleep 1\n        echo STARTED\n      else\n        echo FAILED TO WRITE PID\n        exit 1\n      fi\n    else\n      echo SERVER DID NOT START\n      exit 1\n    fi\n    ;;\nstart-foreground)\n    ZOO_CMD=(exec \"$JAVA\")\n    if [ \"${ZOO_NOEXEC}\" != \"\" ]; then\n      ZOO_CMD=(\"$JAVA\")\n    fi\n    \"${ZOO_CMD[@]}\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n    -cp \"$CLASSPATH\" $JVMFLAGS $ZOOMAIN \"$ZOOCFG\"\n    ;;\nprint-cmd)\n    echo \"\\\"$JAVA\\\" -Dzookeeper.log.dir=\\\"${ZOO_LOG_DIR}\\\" -Dzookeeper.root.logger=\\\"${ZOO_LOG4J_PROP}\\\" -cp \\\"$CLASSPATH\\\" $JVMFLAGS $ZOOMAIN \\\"$ZOOCFG\\\" > \\\"$_ZOO_DAEMON_OUT\\\" 2>&1 < /dev/null\"\n    ;;\nstop)\n    echo -n \"Stopping zookeeper ... \"\n    if [ ! -f \"$ZOOPIDFILE\" ]\n    then\n      echo \"no zookeeper to stop (could not find file $ZOOPIDFILE)\"\n    else\n      $KILL -9 $(cat \"$ZOOPIDFILE\")\n      rm \"$ZOOPIDFILE\"\n      echo STOPPED\n    fi\n    exit 0\n    ;;\nupgrade)\n    shift\n    echo \"upgrading the servers to 3.*\"\n    \"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n    -cp \"$CLASSPATH\" $JVMFLAGS org.apache.zookeeper.server.upgrade.UpgradeMain ${@}\n    echo \"Upgrading ... \"\n    ;;\nrestart)\n    shift\n    \"$0\" stop ${@}\n    sleep 3\n    \"$0\" start ${@}\n    ;;\nstatus)\n    # -q is necessary on some versions of linux where nc returns too quickly, and no stat result is output\n    clientPortAddress=`$GREP \"^[[:space:]]*clientPortAddress[^[:alpha:]]\" \"$ZOOCFG\" | sed -e 's/.*=//'`\n    if ! [ $clientPortAddress ]\n    then\n\tclientPortAddress=\"localhost\"\n    fi\n    clientPort=`$GREP \"^[[:space:]]*clientPort[^[:alpha:]]\" \"$ZOOCFG\" | sed -e 's/.*=//'`\n    STAT=`\"$JAVA\" \"-Dzookeeper.log.dir=${ZOO_LOG_DIR}\" \"-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}\" \\\n             -cp \"$CLASSPATH\" $JVMFLAGS org.apache.zookeeper.client.FourLetterWordMain \\\n             $clientPortAddress $clientPort srvr 2> /dev/null    \\\n          | $GREP Mode`\n    if [ \"x$STAT\" = \"x\" ]\n    then\n        echo \"Error contacting service. It is probably not running.\"\n        exit 1\n    else\n        echo $STAT\n        exit 0\n    fi\n    ;;\n*)\n    echo \"Usage: $0 {start|start-foreground|stop|restart|status|upgrade|print-cmd}\" >&2\n\nesac\n"
  },
  {
    "path": "build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"ZooKeeper\" default=\"jar\" \nxmlns:ivy=\"antlib:org.apache.ivy.ant\"\nxmlns:artifact=\"antlib:org.apache.maven.artifact.ant\"\nxmlns:maven=\"antlib:org.apache.maven.artifact.ant\"\nxmlns:cs=\"antlib:com.puppycrawl.tools.checkstyle\">\n\n    <!-- read build.properties from the basedir if any -->\n    <property file=\"${basedir}/build.properties\" />\n\n    <property name=\"Name\" value=\"ZooKeeper\" />\n    <property name=\"name\" value=\"zookeeper\" />\n\n    <property environment=\"env\"/>\n    \n    <property name=\"version\" value=\"3.4.12\" />\n    <property name=\"final.name\" value=\"${name}-${version}\"/>\n    <property name=\"revision.dir\" value=\"${basedir}/.revision\" />\n    <property name=\"revision.properties\" value=\"revision.properties\" />\n    <property file=\"${basedir}/src/java/${revision.properties}\" />\n    \n    <property name=\"javac.target\" value=\"1.6\" />\n    <property name=\"javac.source\" value=\"1.6\" />\n\n    <property name=\"src.dir\" value=\"${basedir}/src\" />\n    <property name=\"java.src.dir\" value=\"${src.dir}/java/main\" />\n\n    <property name=\"lib.dir\" value=\"${src.dir}/java/lib\" />\n    <property name=\"lib.dir.includes\" value=\"**/*.jar\" />\n    <property name=\"lib.dir.excludes\" value=\"**/excluded/\" />\n\n    <!-- prior to ant 1.7.1 fileset always fails if dir doesn't exist\n         so just point to bin directory and provide settings that exclude\n         everything - user can change as appropriate -->\n    <property name=\"additional.lib.dir\" value=\"bin\" />\n    <property name=\"additional.lib.dir.includes\" value=\"**/*.jar\" />\n    <property name=\"additional.lib.dir.excludes\" value=\"**/*.jar\" />\n\n    <property name=\"build.dir\" value=\"${basedir}/build\" />\n    <property name=\"distribution\" value=\"${basedir}/distribution\" />\n    <property name=\"src_generated.dir\" value=\"${src.dir}/java/generated\" />\n    <property name=\"c.src.dir\" value=\"${src.dir}/c\" />    \n    <property name=\"csrc_generated.dir\" value=\"${c.src.dir}/generated\" />\n    <property name=\"csharp.src.dir\" value=\"${src.dir}/csharp/src\"/>\n    <property name=\"csharpsrc_generated.dir\" value=\"${csharp.src.dir}/ZooKeeperNetEx/Generated\"/>\n\n    <property name=\"jute.file\" value=\"${src.dir}/zookeeper.jute\" />\n\n    <property name=\"build.classes\" value=\"${build.dir}/classes\"/>\n    <property name=\"build.docs\" value=\"${build.dir}/docs\" />\n    <property name=\"build.javadoc\" value=\"${build.docs}/api\" />\n    <property name=\"build.javadoc.dev\" value=\"${build.docs}/dev-api\"/>\n\n    <property name=\"test.java.build.dir\" value=\"${build.dir}/test\"/>\n    <property name=\"test.java.classes\" value=\"${test.java.build.dir}/classes\"/>\n    <property name=\"test.src.dir\" value=\"${src.dir}/java/test\"/>\n    <property name=\"systest.src.dir\" value=\"${src.dir}/java/systest\"/>\n    <property name=\"test.log.dir\" value=\"${test.java.build.dir}/logs\" />\n    <property name=\"test.data.dir\" value=\"${test.java.build.dir}/data\" />\n    <property name=\"test.data.upgrade.dir\" value=\"${test.data.dir}/upgrade\" />\n    <property name=\"test.data.invalid.dir\" value=\"${test.data.dir}/invalidsnap\" />\n    <property name=\"test.data.buffersize.dir\" value=\"${test.data.dir}/buffersize\" />\n    <property name=\"test.data.kerberos.dir\" value=\"${test.data.dir}/kerberos\" />\n    <property name=\"test.cppunit.dir\" value=\"${test.java.build.dir}/test-cppunit\"/>\n    <property name=\"test.tmp.dir\" value=\"${test.java.build.dir}/tmp\" />\n    <property name=\"test.output\" value=\"no\" />\n    <property name=\"test.timeout\" value=\"900000\" />\n    <property name=\"test.junit.output.format\" value=\"plain\" />\n    <property name=\"test.junit.fork.mode\" value=\"perTest\" />\n    <property name=\"test.junit.printsummary\" value=\"yes\" />\n    <property name=\"test.junit.haltonfailure\" value=\"no\" />\n    <property name=\"test.junit.failbuild.ontestfailure\" value=\"true\" />\n    <property name=\"config.dir\" value=\"${src.dir}/java/test/config\" />\n    <property name=\"test.junit.maxmem\" value=\"512m\" />\n    <property name=\"test.quick\" value=\"no\" />\n    <property name=\"conf.dir\" value=\"${basedir}/conf\"/>\n    <property name=\"docs.dir\" value=\"${basedir}/docs\"/>\n    <property name=\"docs.src\" value=\"${basedir}/src/docs\"/>\n    <property name=\"javadoc.link.java\"\n              value=\"http://docs.oracle.com/javase/6/docs/api/\" />\n    <property name=\"javadoc.packages\" value=\"org.apache.*\" />\n\n    <property name=\"dist.dir\" value=\"${build.dir}/${final.name}\"/>\n    <property name=\"dist.maven.dir\" value=\"${dist.dir}/dist-maven\"/>\n\n    <property name=\"clover.home\" location=\"${env.CLOVER_HOME}\"/>\n    <property name=\"clover.jar\" location=\"${clover.home}/lib/clover.jar\" />\n    <property name=\"clover.db.dir\" location=\"${test.java.build.dir}/clover/db\"/>\n    <property name=\"clover.report.dir\"\n              location=\"${test.java.build.dir}/clover/reports\"/>\n\n    <property name=\"contrib.dir\" value=\"${src.dir}/contrib\"/>\n    <property name=\"recipes.dir\" value=\"${src.dir}/recipes\"/>\n\n    <property name=\"ivy.version\" value=\"2.4.0\"/>\n    <property name=\"ivy.url\"\n              value=\"https://repo1.maven.org/maven2/org/apache/ivy/ivy\" />\n    <property name=\"ivy.home\" value=\"${user.home}/.ant\" />\n    <property name=\"ivy.lib\" value=\"${build.dir}/lib\"/>\n    <property name=\"ivy.package.lib\" value=\"${build.dir}/package/lib\"/>\n    <property name=\"ivy.test.lib\" value=\"${build.dir}/test/lib\"/>\n    <property name=\"ivy.jdiff.lib\" value=\"${build.dir}/jdiff/lib\"/>\n    <property name=\"ivy.releaseaudit.lib\" value=\"${build.dir}/releaseaudit/lib\"/>\n    <property name=\"ivy.owasp.lib\" value=\"${build.dir}/owasp/lib\"/>\n    <property name=\"ivysettings.xml\" value=\"${basedir}/ivysettings.xml\"/>\n\n    <property name=\"mvnrepo\" value=\"https://repo1.maven.org/maven2\"/>\n    <property name=\"tsk.org\" value=\"/org/apache/maven/maven-ant-tasks/\"/>\n    <property name=\"ant-task.version\" value=\"2.1.3\"/>\n    <property name=\"ant_task_repo_url\"\n        value=\"${mvnrepo}${tsk.org}${ant-task.version}/maven-ant-tasks-${ant-task.version}.jar\"/>\n    <property name=\"ant_task.jar\" location=\"${ivy.lib}/maven-ant-tasks-${ant-task.version}.jar\"/>\n    \n    <available property=\"clover.present\"\n               classname=\"com.cenqua.clover.CloverInstr\"\n               classpath=\"${clover.home}/lib/clover.jar\"/>\n\n    <available file=\"${c.src.dir}/Makefile\" property=\"Makefile.present\"/>\n\n    <!-- check if clover reports should be generated -->\n    <condition property=\"clover.enabled\">\n      <and>\n        <isset property=\"run.clover\"/>\n        <isset property=\"clover.present\"/>\n      </and>\n    </condition>\n\n\n    <property name=\"test.cobertura.output.format\" value=\"html\" />\n    <property name=\"coveragereport.dir\" value=\"${build.dir}/cobertura\" />\n\n    <!-- rats properties -->\n    <property name=\"rats_url\" value=\"http://arat.googlecode.com/files/rat-lib-all-0.5.1.jar\" />\n    <property name=\"rat.reporting.classname\" value=\"rat.Report\"/>\n\n        <!-- test patch properties -->\n    <property name=\"scratch.dir\" value=\"${user.home}/tmp\"/>\n    <property name=\"svn.cmd\" value=\"svn\"/>\n    <property name=\"grep.cmd\" value=\"grep\"/>\n    <property name=\"patch.cmd\" value=\"patch\"/>\n    <property name=\"make.cmd\" value=\"make\"/>\n    <property name=\"test_patch_sh\" value=\"${test.src.dir}/bin/test-patch.sh\"/>\n    <property name=\"test_pullrequest_sh\" value=\"${test.src.dir}/bin/test-github-pr.sh\"/>\n\n\t<!-- jdiff.home property set -->\n    <property name=\"jdiff.home\" value=\"${ivy.jdiff.lib}\"/>\n    <property name=\"jdiff.build.dir\" value=\"${build.docs}/jdiff\"/>\n    <property name=\"jdiff.xml.dir\" value=\"${lib.dir}/jdiff\"/>\n    <property name=\"jdiff.stable\" value=\"3.1.1\"/>\n    <property name=\"jdiff.stable.javadoc\" \n            value=\"http://hadoop.apache.org/zookeeper/docs/r${jdiff.stable}/api/\"/>\n\n    <!-- eclipse property set -->\n    <property name=\"build.dir.eclipse\" value=\".eclipse\"/>\n    <property name=\"build.dir.eclipse-main-classes\" value=\"${build.dir.eclipse}/classes-main\"/>\n    <property name=\"build.dir.eclipse-test-classes\" value=\"${build.dir.eclipse}/classes-test\"/>\n\n    <!-- cppunit property set -->\n    <property name=\"cppunit.lib\" value=\"/usr/lib\"/>\n    <property name=\"cppunit.m4\" value=\"/usr/share/aclocal\"/>\n\n    <!-- packaging property set -->\n    <property name=\"package.release\" value=\"1\"/>\n    <property name=\"package.prefix\" value=\"/usr\"/>\n    <property name=\"package.conf.dir\" value=\"/etc/zookeeper\"/>\n    <property name=\"package.log.dir\" value=\"/var/log/zookeeper\"/>\n    <property name=\"package.pid.dir\" value=\"/var/run/zookeeper\"/>\n    <property name=\"package.var.dir\" value=\"/var/lib/zookeeper\"/>\n    <property name=\"package.share.dir\" value=\"/share/zookeeper\"/>\n    <property name=\"package.buildroot\" value=\"/tmp/zookeeper_package_build_${user.name}\"/>\n    <property name=\"package.build.dir\" value=\"/tmp/zookeeper_package_build_${user.name}/BUILD\"/>\n\n    <!-- artifact publishing property set -->\n    <property name=\"staging_repo_id\" value=\"apache.staging.https\"/>\n    <property name=\"wagon-http.version\" value=\"2.4\"/>\n    <property name=\"snapshots_repo_id\" value=\"apache.snapshots.https\"/>\n    <property name=\"asfrepo\" value=\"https://repository.apache.org\"/> \n    <property name=\"snapshots_repo_url\" \n      value=\"${asfrepo}/content/repositories/snapshots\"/> \n    <property name=\"staging_repo_url\"\n      value=\"${asfrepo}/service/local/staging/deploy/maven2\"/> \n    <property name=\"gpg-plugin\" \n      value=\"org.apache.maven.plugins:maven-gpg-plugin:1.4:sign-and-deploy-file\"/>\n    <property name=\"deploy-plugin\" \n      value=\"org.apache.maven.plugins:maven-deploy-plugin:2.8.1:deploy-file\"/>\n    <property name=\"main-jar\" value=\"${dist.maven.dir}/${final.name}.jar\"/>\n    <property name=\"tests-jar\" value=\"${dist.maven.dir}/${final.name}-tests.jar\"/>\n    <property name=\"sources-jar\" value=\"${dist.maven.dir}/${final.name}-sources.jar\"/>\n    <property name=\"javadoc-jar\" value=\"${dist.maven.dir}/${final.name}-javadoc.jar\"/>\n\n    <!-- ====================================================== -->\n    <!-- Dependency versions                                    -->\n    <!-- ====================================================== -->\n    <property name=\"slf4j.version\" value=\"1.7.25\"/>\n\n    <property name=\"wagon-http.version\" value=\"2.4\"/>\n    <property name=\"maven-ant-tasks.version\" value=\"2.1.3\"/>\n    <property name=\"log4j.version\" value=\"1.2.17\"/>\n    <property name=\"jline.version\" value=\"0.9.94\"/>\n\n    <property name=\"jdeb.version\" value=\"0.8\"/>\n\n    <property name=\"audience-annotations.version\" value=\"0.5.0\" />\n\n    <property name=\"netty.version\" value=\"3.10.6.Final\"/>\n\n    <property name=\"junit.version\" value=\"4.8.1\"/>\n    <property name=\"mockito.version\" value=\"1.8.5\"/>\n    <property name=\"checkstyle.version\" value=\"6.1.1\"/>\n    <property name=\"commons-collections.version\" value=\"3.2.2\"/>\n    <property name=\"commons-io.version\" value=\"2.4\"/>\n\n    <property name=\"apache-directory-server.version\" value=\"2.0.0-M15\"/>\n    <property name=\"apache-directory-api.version\" value=\"1.0.0-M20\"/>\n\n    <property name=\"jdiff.version\" value=\"1.0.9\"/>\n    <property name=\"xerces.version\" value=\"1.4.4\"/>\n\n    <property name=\"apache-rat-tasks.version\" value=\"0.6\"/>\n    <property name=\"commons-lang.version\" value=\"2.4\"/>\n\n    <property name=\"dependency-check-ant.version\" value=\"2.1.0\"/>\n\n    <!-- ====================================================== -->\n    <!-- Macro definitions                                      -->\n    <!-- ====================================================== -->\n    <macrodef name=\"macro_tar\" description=\"Worker Macro for tar\">\n      <attribute name=\"param.destfile\"/>\n      <element name=\"param.listofitems\"/>\n      <sequential>\n        <tar compression=\"gzip\" longfile=\"gnu\"\n             destfile=\"@{param.destfile}\">\n          <param.listofitems/>\n        </tar>\n      </sequential>\n    </macrodef>\n\n    <path id=\"base.classpath\">\n      <pathelement location=\"${build.classes}\"/>\n      <!-- allow the user to override (e.g. if there are local versions) -->\n      <fileset dir=\"${additional.lib.dir}\">\n          <include name=\"${additional.lib.dir.includes}\" />\n          <exclude name=\"${additional.lib.dir.excludes}\" />\n      </fileset>\n      <fileset dir=\"${lib.dir}\">\n          <include name=\"${lib.dir.includes}\" />\n          <exclude name=\"${lib.dir.excludes}\" />\n      </fileset>\n      <fileset dir=\"${ant.home}/lib\">\n          <include name=\"ant.jar\" />\n      </fileset>\n      <pathelement path=\"${clover.jar}\" />\n    </path>\n\n    <!-- the normal classpath -->\n    <path id=\"java.classpath\">\n      <path refid=\"base.classpath\"/>\n      <fileset dir=\"${ivy.lib}\">\n        <include name=\"**/*.jar\" />\n      </fileset>\n    </path>\n\n    <path id=\"test.java.classpath\">\n      <path refid=\"base.classpath\"/>\n      <pathelement location=\"${test.java.classes}\" />\n      <fileset dir=\"${ivy.test.lib}\">\n        <include name=\"**/*.jar\" />\n      </fileset>\n    </path>\n\n    <path id=\"package.classpath\">\n      <fileset dir=\"${ivy.package.lib}\">\n        <include name=\"**/jdeb*.jar\" />\n      </fileset>\n    </path>\n\n    <!-- ====================================================== -->\n    <!-- Generate and compile the Java files                    -->\n    <!-- ====================================================== -->\n    <target name=\"init\">    \n        <mkdir dir=\"${build.classes}\" />\n\n        <mkdir dir=\"${ivy.lib}\"/>\n        <mkdir dir=\"${ivy.package.lib}\"/>\n        <mkdir dir=\"${ivy.test.lib}\"/>\n        <condition property=\"ivy.jar.exists\">\n          <available file=\"${lib.dir}/ivy-${ivy.version}.jar\"/>\n        </condition>\n\n        <tstamp>\n            <format property=\"build.time\" pattern=\"MM/dd/yyyy HH:mm zz\" timezone=\"GMT\"/>\n            <format property=\"year\" pattern=\"yyyy\" timezone=\"GMT\"/>\n        </tstamp>\n    </target>\n    \n    <target name=\"jute\" depends=\"init\">\n        <javac srcdir=\"${java.src.dir}\" destdir=\"${build.classes}\" includeantruntime=\"false\"\n            target=\"${javac.target}\" source=\"${javac.source}\"\n            includes=\"org/apache/jute/**\" debug=\"on\" classpath=\"${ivy.lib}/audience-annotations-${audience-annotations.version}.jar\" />\n    </target>\n\n    <target name=\"compile_jute_uptodate\">\n        <uptodate property=\"juteBuild.notRequired\"\n                  srcfile=\"${jute.file}\"\n                  targetfile=\"${src_generated.dir}/.generated\"/>\n    </target>\n\n    <target name=\"compile_jute\" depends=\"jute,compile_jute_uptodate\" unless=\"juteBuild.notRequired\">\n        <mkdir dir=\"${src_generated.dir}\" />\n        <mkdir dir=\"${csrc_generated.dir}\" />\n        <mkdir dir=\"${csharpsrc_generated.dir}\"/>\n        <java classname=\"org.apache.jute.compiler.generated.Rcc\" fork=\"true\" dir=\"${src_generated.dir}\">\n            <arg value=\"-l\" />\n            <arg value=\"java\" />\n            <arg value=\"../../zookeeper.jute\" /> \n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n            </classpath>\n        </java>\n        \n        <java classname=\"org.apache.jute.compiler.generated.Rcc\" fork=\"true\" dir=\"${csrc_generated.dir}\">\n            <arg value=\"-l\" />\n            <arg value=\"c\" />\n            <arg value=\"../../zookeeper.jute\" />\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n            </classpath>\n        </java>\n      <java dir=\"${csharpsrc_generated.dir}\" classname=\"org.apache.jute.compiler.generated.Rcc\" fork=\"true\">\n        <arg value=\"-l\"/>\n        <arg value=\"csharp\"/>\n        <arg value=\"../../../../zookeeper.jute\"/>\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n            </classpath>\n        </java>\n\n        <touch file=\"${src_generated.dir}/.generated\"/>\n    </target>\n\n    <target name=\"ver-gen\" depends=\"init\">\n        <javac srcdir=\"${java.src.dir}\" destdir=\"${build.classes}\" includeantruntime=\"false\"\n            target=\"${javac.target}\" source=\"${javac.source}\"\n            includes=\"org/apache/zookeeper/version/util/**\" debug=\"on\" />\n    </target>\n    \n    <target name=\"git-revision\" unless=\"lastRevision\">\n        <mkdir dir=\"${revision.dir}\" />\n        <condition property=\"shell.name\" value=\"cmd\" else=\"sh\">\n      \t    <os family=\"windows\"/>\n        </condition>\n        <condition property=\"revision.cmd.line\" \n        \tvalue=\"/c ${src.dir}\\lastRevision.bat\" else=\"${src.dir}/lastRevision.sh\">\n      \t    <os family=\"windows\"/>\n        </condition>\n        <exec executable=\"${shell.name}\">\n           <arg line=\"${revision.cmd.line} ${revision.dir}${file.separator}${revision.properties}\"/>\n        </exec>\n        <property file=\"${revision.dir}/${revision.properties}\" />\n    </target>\n    \n    <target name=\"version-info\" depends=\"ver-gen,git-revision\">\n        <mkdir dir=\"${src_generated.dir}\" />\n        <java classname=\"org.apache.zookeeper.version.util.VerGen\" fork=\"true\" \n                dir=\"${src_generated.dir}\">\n            <arg value=\"${version}\" />\n            <arg value=\"${lastRevision}\" />\n            <arg value=\"${build.time}\" />\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n            </classpath>\n        </java>\n    </target>\n    \n    <target name=\"build-generated\" depends=\"compile_jute,version-info,ivy-retrieve\" >\n        <javac srcdir=\"${src_generated.dir}\" destdir=\"${build.classes}\" includeantruntime=\"false\"\n            target=\"${javac.target}\" source=\"${javac.source}\" debug=\"on\" classpath=\"${ivy.lib}/audience-annotations-${audience-annotations.version}.jar\" />\n    </target>\n    \n    <target name=\"ivy-download\" unless=\"ivy.jar.exists\" depends=\"init\">\n      <delete dir=\"${lib.dir}\"\n              includes=\"ivy-*.jar\" excludes=\"ivy-${ivy.version}.jar\"/>\n      <get src=\"${ivy.url}/${ivy.version}/ivy-${ivy.version}.jar\"\n           dest=\"${lib.dir}/ivy-${ivy.version}.jar\" usetimestamp=\"true\"/>\n    </target>\n\n    <target name=\"ivy-taskdef\" unless=\"ivy.initialized\">\n      <taskdef resource=\"org/apache/ivy/ant/antlib.xml\"\n               uri=\"antlib:org.apache.ivy.ant\" classpathref=\"java.classpath\"/>\n      <!-- ensure that ivy taskdef is only run once, otw ant will error -->\n      <property name=\"ivy.initialized\" value=\"true\"/> \n    </target>\n\n    <target name=\"ivy-init\" depends=\"ivy-download,ivy-taskdef\">\n      <ivy:settings id=\"${ant.project.name}\" file=\"${ivysettings.xml}\"/>\n    </target>\n\n    <target name=\"ivy-retrieve\" depends=\"init,ivy-init\">\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"default\"\n                    pattern=\"${ivy.lib}/[artifact]-[revision].[ext]\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-test\" depends=\"init,ivy-init\">\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"test\"\n                    pattern=\"${ivy.test.lib}/[artifact]-[revision].[ext]\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-package\" depends=\"init,ivy-init\">\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"package\"\n                    pattern=\"${ivy.package.lib}/[artifact]-[revision].[ext]\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-jdiff\" depends=\"init,ivy-init\">\n      <mkdir dir=\"${ivy.jdiff.lib}\"/>\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"jdiff\"\n                    pattern=\"${ivy.jdiff.lib}/[artifact]-[revision].[ext]\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-releaseaudit\" depends=\"init,ivy-init\">\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"releaseaudit\"\n                    pattern=\"${ivy.releaseaudit.lib}/[artifact]-[revision].[ext]\"/>\n      <ivy:cachepath pathid=\"releaseaudit-classpath\" conf=\"releaseaudit\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-owasp\" depends=\"init,ivy-init\">\n        <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"owasp\"\n                      pattern=\"${ivy.owasp.lib}/[artifact]-[revision].[ext]\"/>\n        <ivy:cachepath pathid=\"owasp-classpath\" conf=\"owasp\"/>\n    </target>\n\n    <target name=\"ivy-retrieve-mvn-ant-task\" depends=\"init,ivy-init\">\n      <ivy:retrieve settingsRef=\"${ant.project.name}\" conf=\"mvn-ant-task\"\n                    pattern=\"${ivy.lib}/[artifact]-[revision].[ext]\"/>\n      <ivy:cachepath pathid=\"mvn-ant-task-classpath\" conf=\"mvn-ant-task\"/>\n    </target>\n\n    <target name=\"dependency-report\" depends=\"init,ivy-init\">\n        <ivy:resolve conf=\"*\"/>\n        <ivy:report conf=\"*\" todir=\"${build.dir}/dependency-report\"/>\n    </target>\n\n    <target name=\"compile\" depends=\"ivy-retrieve,clover,build-generated\">\n        <javac srcdir=\"${java.src.dir}\" destdir=\"${build.classes}\" includeantruntime=\"false\"\n               target=\"${javac.target}\" source=\"${javac.source}\" debug=\"on\">\n            <classpath refid=\"java.classpath\"/>\n            <compilerarg value=\"-Xlint:all\"/>\n            <compilerarg value=\"-Xlint:-path\"/>\n        </javac>\n    </target>\n\n    <target name=\"compile-test\" depends=\"ivy-retrieve-test,compile\">\n      <mkdir dir=\"${test.java.classes}\"/>\n      <javac srcdir=\"${test.src.dir}\" destdir=\"${test.java.classes}\" includeantruntime=\"false\"\n             target=\"${javac.target}\" source=\"${javac.source}\" debug=\"on\">\n        <classpath refid=\"test.java.classpath\"/>\n      </javac>\n      <javac srcdir=\"${systest.src.dir}\" destdir=\"${test.java.classes}\" includeantruntime=\"false\"\n             target=\"${javac.target}\" source=\"${javac.source}\" debug=\"on\">\n        <classpath refid=\"test.java.classpath\"/>\n      </javac>\n    </target>\n\n    <target name=\"compile-native\" depends=\"compile_jute\" description=\"Make C binding\">\n      <exec executable=\"autoreconf\" dir=\"${c.src.dir}\" searchpath=\"yes\"\n            failonerror=\"yes\">\n        <arg value=\"-if\"/>\n        <env key=\"ACLOCAL\" value=\"aclocal -I ${cppunit.m4}\"/>\n      </exec>\n      <mkdir dir=\"${build.dir}/c\" />\n      <exec executable=\"${c.src.dir}/configure\" dir=\"${build.dir}/c\"\n            failonerror=\"yes\">\n        <env key=\"base_dir\" value=\"${basedir}\"/>\n        <env key=\"CALLER\" value=\"ANT\"/>\n        <arg value=\"--prefix=${build.dir}/c/build/${package.prefix}\"/>\n      </exec>\n      <property name=\"c.build\" value=\"${build.dir}/c/build\"/>\n      <exec dir=\"${build.dir}/c\" executable=\"make\" failonerror=\"true\">\n        <arg value=\"install\"/>\n        <env key=\"LD_LIBRARY_PATH\" value=\"${env.LD_LIBRARY_PATH};${c.build}\"/>\n        <env key=\"PATH\" path=\"${env.PATH};${c.src.dir};\"/>\n        <env key=\"CALLER\" value=\"ANT\"/>\n        <env key=\"base_dir\" value=\"${basedir}\"/>\n      </exec>\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- Documentation                                          -->\n    <!-- ====================================================== -->\n    <target name=\"docs\" depends=\"forrest.check\" description=\"Generate forrest-based documentation. To use, specify -Dforrest.home=&lt;base of Apache Forrest installation&gt; on the command line.\" if=\"forrest.home\">\n      <condition property=\"forrest.exec\" value=\"forrest.bat\" else=\"forrest\">\n      \t<os family=\"windows\"/>\n      </condition>\n      <exec dir=\"${docs.src}\" executable=\"${forrest.home}/bin/${forrest.exec}\"\n            failonerror=\"true\">\n      </exec>\n      <copy todir=\"${docs.dir}\">\n        <fileset dir=\"${docs.src}/build/site/\" />\n      </copy>\n      <style basedir=\"${conf.dir}\" destdir=\"${docs.dir}\"\n             includes=\"zookeeper-default.xml\" style=\"conf/configuration.xsl\"/>\n    </target>\n\n    <target name=\"forrest.check\" unless=\"forrest.home\">\n      <fail message=\"'forrest.home' is not defined. Please pass -Dforrest.home=&lt;base of Apache Forrest installation&gt; to Ant on the command-line.\" />\n    </target>\n\n    <!-- Javadoc -->\n    <target name=\"javadoc-dev\" depends=\"jar\"\n            description=\"Generate javadoc for zookeeper developers\">\n      <mkdir dir=\"${build.javadoc.dev}\"/>\n      <javadoc\n         overview=\"${java.src.dir}/overview.html\"\n         packagenames=\"org.apache.zookeeper.*\"\n         destdir=\"${build.javadoc.dev}\"\n         author=\"true\"\n         version=\"true\"\n         use=\"true\"\n         windowtitle=\"${Name} ${version} API\"\n         doctitle=\"${Name} ${version} API\"\n         bottom=\"Copyright &amp;copy; ${year} The Apache Software Foundation\"\n         >\n    \t<packageset dir=\"${java.src.dir}\">\n          <include name=\"org/apache/**\"/>\n          <exclude name=\"org/apache/jute/**\"/>\n    \t</packageset>\n    \t<packageset dir=\"${src_generated.dir}\"/>\n        <link href=\"${javadoc.link.java}\"/>\n        <classpath refid=\"java.classpath\"/>\n      </javadoc>\n    </target>\t\n\n    <target name=\"javadoc\" depends=\"jar\" description=\"Generate javadoc\">\n      <mkdir dir=\"${build.javadoc}\"/>\n      <javadoc\n         overview=\"${java.src.dir}/overview.html\"\n         packagenames=\"org.apache.zookeeper.*\"\n         destdir=\"${build.javadoc}\"\n         author=\"true\"\n         version=\"true\"\n         use=\"true\"\n         Public=\"yes\"\n         windowtitle=\"${Name} ${version} API\"\n         doctitle=\"${Name} ${version} API\"\n         bottom=\"Copyright &amp;copy; ${year} The Apache Software Foundation\"\n         doclet=\"org.apache.yetus.audience.tools.IncludePublicAnnotationsStandardDoclet\"\n         docletpath=\"${ivy.lib}/audience-annotations-${audience-annotations.version}.jar\"\n         >\n\n        <fileset dir=\"${java.src.dir}\">\n          <include name=\"org/apache/zookeeper/server/quorum/QuorumPeerMain.java\"/>\n          <include name=\"org/apache/zookeeper/server/ZooKeeperServerMain.java\"/>\n          <include name=\"org/apache/zookeeper/server/LogFormatter.java\"/>\n          <include name=\"org/apache/zookeeper/server/PurgeTxnLog.java\"/>\n          <include name=\"org/apache/zookeeper/server/SnapshotFormatter.java\"/>\n          <include name=\"org/apache/zookeeper/server/upgrade/UpgradeMain.java\"/>\n        </fileset>\n    \t<packageset dir=\"${java.src.dir}\">\n          <include name=\"org/apache/**\"/>\n          <exclude name=\"org/apache/zookeeper/server/**\"/>\n    \t</packageset>\n    \t<packageset dir=\"${src_generated.dir}\">\n          <include name=\"org/apache/**\"/>\n          <exclude name=\"org/apache/zookeeper/proto\"/>\n          <exclude name=\"org/apache/zookeeper/txn\"/>\n          <exclude name=\"org/apache/zookeeper/version\"/>\n          <exclude name=\"org/apache/zookeeper/server/**\"/>\n    \t</packageset>\n        <link href=\"${javadoc.link.java}\"/>\n        <classpath>\n\t\t<fileset dir=\"${basedir}\">\n\t\t\t<include name=\"${jar.name}\"/>\n\t\t</fileset> \n        <path refid=\"java.classpath\"/>\n\t</classpath>\n      </javadoc>\n    </target>\t\n\n    <!-- ====================================================== -->\n    <!-- Make zookeeper.jar                                     -->\n    <!-- ====================================================== -->\n    <target name=\"jar\" depends=\"compile\">\n        <java classname=\"org.apache.zookeeper.Version\" fork=\"true\"\n              outputproperty=\"revision\" errorproperty=\"revision.error\" failonerror=\"true\">\n            <arg value=\"--revision\" />\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n                <pathelement path=\"${clover.jar}\" />\n            </classpath>\n        </java>\n        <exec executable=\"hostname\" outputproperty=\"host.name\"/>\n        <jar jarfile=\"${build.dir}/${final.name}.jar\">\n            <fileset file=\"LICENSE.txt\" />\n            <fileset dir=\"${build.classes}\" excludes=\"**/.generated\"/>\n            <fileset dir=\"${java.src.dir}\"/>\n            <fileset dir=\"${src_generated.dir}\" excludes=\"**/.generated\"/>\n            <manifest>\n                <attribute name=\"Main-Class\" value=\"org.apache.zookeeper.server.quorum.QuorumPeerMain\" />\n                <attribute name=\"Built-By\" value=\"${user.name}\"/>\n                <attribute name=\"Built-At\" value=\"${build.time}\"/>\n                <attribute name=\"Built-On\" value=\"${host.name}\" />\n                <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n                <attribute name=\"Implementation-Version\" value=\"${revision}\"/> \n                <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n            \t\n            \t<!-- The following are OSGi manifest headers -->\n            \t<!-- currently hardcoded, when things get more complicated we could use BND \n            \thttp://www.aqute.biz/Code/Bnd to generate them -->\n                <attribute name=\"Bundle-Vendor\" value=\"The Apache Software Foundation\"/>\n                <attribute name=\"Bundle-Name\" value=\"ZooKeeper Bundle\"/>\n                <attribute name=\"Bundle-SymbolicName\" value=\"org.apache.hadoop.zookeeper\"/>\n                <attribute name=\"Bundle-ManifestVersion\" value=\"2\"/>\n                <attribute name=\"Bundle-Version\" value=\"${version}\"/>\n                <attribute name=\"Bundle-License\" value=\"http://www.apache.org/licenses/LICENSE-2.0.txt\"/>\n                <attribute name=\"Bundle-DocURL\" value=\"http://hadoop.apache.org/zookeeper\"/>\n                <attribute name=\"Import-Package\" value='javax.management;resolution:=optional,javax.security.auth.callback,javax.security.auth.login,javax.security.sasl,org.slf4j;version=\"[1.6,2)\",org.jboss.netty.buffer;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel.group;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel.socket.nio;resolution:=optional;version=\"[3.2,4)\",org.osgi.framework;resolution:=optional;version=\"[1.5,2)\",org.osgi.util.tracker;resolution:=optional;version=\"[1.4,2)\",org.ietf.jgss'/>\n                <attribute name=\"Export-Package\" value='org.apache.zookeeper;version=\"${version}\",org.apache.zookeeper.client;version=\"${version}\",org.apache.zookeeper.data;version=\"${version}\",org.apache.zookeeper.version;version=\"${version}\",org.apache.zookeeper.server;version=\"${version}\",org.apache.zookeeper.server.auth;version=\"${version}\",org.apache.zookeeper.server.persistence;version=\"${version}\",org.apache.zookeeper.server.quorum;version=\"${version}\",org.apache.zookeeper.common;version=\"${version}\"'/>\n            </manifest>\n        </jar>\n    </target>\n    \n    <!-- ====================================================== -->\n    <!-- Make zookeeper-bin.jar                                 -->\n    <!-- ====================================================== -->\n    <target name=\"bin-jar\" depends=\"compile\">\n        <java classname=\"org.apache.zookeeper.Version\" fork=\"true\"\n              outputproperty=\"revision\" failonerror=\"true\">\n            <arg value=\"--revision\" />\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n                <pathelement path=\"${clover.jar}\" />\n            </classpath>\n        </java>\n        <exec executable=\"hostname\" outputproperty=\"host.name\"/>\n        <jar jarfile=\"${build.dir}/${final.name}-bin.jar\">\n            <fileset file=\"LICENSE.txt\" />\n            <fileset dir=\"${build.classes}\" excludes=\"**/.generated\"/>\n            <manifest>\n                <attribute name=\"Main-Class\" value=\"org.apache.zookeeper.server.quorum.QuorumPeerMain\" />\n                <attribute name=\"Built-By\" value=\"${user.name}\"/>\n                <attribute name=\"Built-At\" value=\"${build.time}\"/>\n                <attribute name=\"Built-On\" value=\"${host.name}\" />\n                <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n                <attribute name=\"Implementation-Version\" value=\"${revision}\"/> \n                <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n            \t\n            \t<!-- The following are OSGi manifest headers -->\n            \t<!-- currently hardcoded, when things get more complicated we could use BND \n            \thttp://www.aqute.biz/Code/Bnd to generate them -->\n                <attribute name=\"Bundle-Vendor\" value=\"The Apache Software Foundation\"/>\n                <attribute name=\"Bundle-Name\" value=\"ZooKeeper Bundle\"/>\n                <attribute name=\"Bundle-SymbolicName\" value=\"org.apache.hadoop.zookeeper\"/>\n                <attribute name=\"Bundle-ManifestVersion\" value=\"2\"/>\n                <attribute name=\"Bundle-Version\" value=\"${version}\"/>\n                <attribute name=\"Bundle-License\" value=\"http://www.apache.org/licenses/LICENSE-2.0.txt\"/>\n                <attribute name=\"Bundle-DocURL\" value=\"http://hadoop.apache.org/zookeeper\"/>\n                <attribute name=\"Import-Package\" value='javax.management;resolution:=optional,javax.security.auth.callback,javax.security.auth.login,javax.security.sasl,org.slf4j;version=\"[1.6,2)\",org.jboss.netty.buffer;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel.group;resolution:=optional;version=\"[3.2,4)\",org.jboss.netty.channel.socket.nio;resolution:=optional;version=\"[3.2,4)\",org.osgi.framework;resolution:=optional;version=\"[1.5,2)\",org.osgi.util.tracker;resolution:=optional;version=\"[1.4,2)\",org.ietf.jgss'/>\n                <attribute name=\"Export-Package\" value='org.apache.zookeeper;version=\"${version}\",org.apache.zookeeper.client;version=\"${version}\",org.apache.zookeeper.data;version=\"${version}\",org.apache.zookeeper.version;version=\"${version}\",org.apache.zookeeper.server;version=\"${version}\",org.apache.zookeeper.server.auth;version=\"${version}\",org.apache.zookeeper.server.persistence;version=\"${version}\",org.apache.zookeeper.server.quorum;version=\"${version}\",org.apache.zookeeper.common;version=\"${version}\"'/>\n            </manifest>\n        </jar>\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- Make zookeeper-sources.jar                                 -->\n    <!-- ====================================================== -->\n    <target name=\"src-jar\" depends=\"build-generated\">\n        <jar jarfile=\"${build.dir}/${final.name}-sources.jar\">\n            <fileset file=\"LICENSE.txt\" />\n            <fileset dir=\"${java.src.dir}\"/>\n            <fileset dir=\"${src_generated.dir}\" excludes=\"**/.generated\"/>\n            <manifest>\n                <attribute name=\"Built-By\" value=\"${user.name}\"/>\n                <attribute name=\"Built-At\" value=\"${build.time}\"/>\n                <attribute name=\"Built-On\" value=\"${host.name}\" />\n                <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n                <attribute name=\"Implementation-Version\" value=\"${revision}\"/> \n                <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n            </manifest>\n        </jar>\n    </target>\n\n\t<!-- ====================================================== -->\n    <!-- Make zookeeper-javadoc.jar                                 -->\n    <!-- ====================================================== -->\n    <target name=\"javadoc-jar\" depends=\"javadoc\">\n        <jar jarfile=\"${build.dir}/${final.name}-javadoc.jar\">\n            <fileset file=\"LICENSE.txt\" />\n            <fileset dir=\"${build.javadoc}\"/>\n            <manifest>\n                <attribute name=\"Built-By\" value=\"${user.name}\"/>\n                <attribute name=\"Built-At\" value=\"${build.time}\"/>\n                <attribute name=\"Built-On\" value=\"${host.name}\" />\n                <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n                <attribute name=\"Implementation-Version\" value=\"${revision}\"/> \n                <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n            </manifest>\n        </jar>\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- Make zookeeper-test.jar                                -->\n    <!-- ====================================================== -->\n    <target name=\"test-jar\" depends=\"compile-test\">\n        <jar jarfile=\"${build.dir}/${final.name}-test.jar\">\n            <fileset file=\"LICENSE.txt\" />\n            <fileset dir=\"${test.java.classes}\"/>\n            <manifest>\n                <attribute name=\"Built-By\" value=\"${user.name}\"/>\n                <attribute name=\"Built-At\" value=\"${build.time}\"/>\n                <attribute name=\"Built-On\" value=\"${host.name}\" />\n                <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n                <attribute name=\"Implementation-Version\" value=\"${revision}\"/> \n                <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n            </manifest>\n        </jar>\n    </target>\n\n\t<!-- ================================================================== -->\n    <!-- D I S T R I B U T I O N                                            -->\n    <!-- ================================================================== -->\n    <!--                                                                    -->\n    <!-- ================================================================== -->\n    <target name=\"package\" \n            depends=\"jar,bin-jar,src-jar,javadoc-jar,test-jar,api-report,create-cppunit-configure,compile-test\"\n            description=\"Build distribution\">\n      <mkdir dir=\"${dist.dir}\"/>\n      <mkdir dir=\"${dist.dir}/lib\"/>\n      <mkdir dir=\"${dist.dir}/contrib\"/>\n      <mkdir dir=\"${dist.dir}/recipes\"/>\n      <mkdir dir=\"${dist.dir}/bin\"/>\n      <mkdir dir=\"${dist.dir}/docs\"/>\n      <mkdir dir=\"${dist.dir}/docs/jdiff\"/>\n      <mkdir dir=\"${dist.dir}/docs/api\"/>\n\n      <copy todir=\"${dist.dir}/lib\" includeEmptyDirs=\"false\">\n        <fileset dir=\"${lib.dir}\">\n          <exclude name=\"**/ivy*.jar\" />\n        </fileset>\n        <fileset dir=\"${ivy.lib}\"/>\n      </copy>\n\n      <subant target=\"package\">\n        <!--Pass down the version in case its needed again and the target\n            distribution directory so contribs know where to install to.-->\n        <property name=\"version\" value=\"${version}\"/>\n        <property name=\"dist.dir\" value=\"${dist.dir}\"/>\n        <property name=\"package.share\" value=\"\"/>\n        <fileset file=\"${contrib.dir}/build.xml\"/>\n        <fileset file=\"${recipes.dir}/build.xml\"/>\n      </subant>  \t\n\n      <copy todir=\"${dist.dir}\"> \n        <fileset file=\"${build.dir}/${final.name}.jar\"/>\n      </copy>\n\n      <checksum file=\"${dist.dir}/${final.name}.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.dir}/${final.name}.jar\" algorithm=\"sha1\"/>\n\n      <mkdir dir=\"${dist.maven.dir}\"/>\n\n      <copy file=\"${build.dir}/${final.name}-bin.jar\"\n            tofile=\"${dist.maven.dir}/${final.name}.jar\"/> \n      <copy todir=\"${dist.maven.dir}\"> \n        <fileset file=\"${build.dir}/${final.name}-sources.jar\"/>\n        <fileset file=\"${build.dir}/${final.name}-javadoc.jar\"/>\n      </copy>\n\n      <checksum file=\"${dist.maven.dir}/${final.name}.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-sources.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-sources.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-javadoc.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-javadoc.jar\" algorithm=\"sha1\"/>\n\n      <ivy:makepom settingsRef=\"${ant.project.name}\" ivyfile=\"${basedir}/ivy.xml\"\n                   pomfile=\"${dist.maven.dir}/${final.name}.pom\"\n                   templatefile=\"${basedir}/src/pom.template\">\n        <mapping conf=\"default\" scope=\"compile\"/>\n        <mapping conf=\"test\" scope=\"test\"/>\n      </ivy:makepom>\n      <checksum file=\"${dist.maven.dir}/${final.name}.pom\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}.pom\" algorithm=\"sha1\"/>\n\n      <copy file=\"${build.dir}/${final.name}-test.jar\"\n            tofile=\"${dist.maven.dir}/${final.name}-tests.jar\"/> \n      <checksum file=\"${dist.maven.dir}/${final.name}-tests.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-tests.jar\" algorithm=\"md5\"/>\n\n      <copy todir=\"${dist.dir}/bin\">\n        <fileset dir=\"bin\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/conf\">\n        <fileset dir=\"${conf.dir}\" excludes=\"**/*.template\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/docs\">\n        <fileset dir=\"${docs.dir}\" />\n        <fileset dir=\"${build.docs}\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}\">\n        <fileset file=\"CHANGES.txt\"/>\n        <fileset file=\"README.md\"/>\n        <fileset file=\"README_packaging.txt\"/>\n        <fileset file=\"build.xml\"/>\n        <fileset file=\"ivy.xml\"/>\n        <fileset file=\"ivysettings.xml\"/>\n        <fileset file=\"src/NOTICE.txt\"/>\n        <fileset file=\"src/LICENSE.txt\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/src\" includeEmptyDirs=\"true\">\n        <fileset dir=\"src\" excludes=\"**/*.template **/docs/build/**/* **/ivy*.jar\"/>\n        <fileset file=\"src/pom.template\"/>\n      </copy>\n  \t  \n      <chmod perm=\"ugo+x\" type=\"file\" parallel=\"false\">\n        <fileset dir=\"${dist.dir}/bin\"/>\n        <fileset dir=\"${dist.dir}/src/contrib/\">\n          <include name=\"*/bin/*\" />\n        </fileset>\n      </chmod>\n    </target>\n\n    <target name=\"bin-package\"\n            depends=\"jar,bin-jar,src-jar,javadoc-jar,test-jar,api-report,create-cppunit-configure,compile-test\"\n            description=\"Build binary distribution\">\n      <delete dir=\"${dist.dir}\"/>\n      <mkdir dir=\"${dist.dir}\"/>\n      <mkdir dir=\"${dist.dir}/lib\"/>\n      <mkdir dir=\"${dist.dir}/libexec\"/>\n      <mkdir dir=\"${dist.dir}/share/zookeeper/contrib\"/>\n      <mkdir dir=\"${dist.dir}/share/zookeeper/recipes\"/>\n      <mkdir dir=\"${dist.dir}/bin\"/>\n      <mkdir dir=\"${dist.dir}/docs\"/>\n      <mkdir dir=\"${dist.dir}/docs/jdiff\"/>\n      <mkdir dir=\"${dist.dir}/docs/api\"/>\n      <mkdir dir=\"${dist.dir}/share/zookeeper/templates/conf\"/>\n      <mkdir dir=\"${dist.dir}/sbin\"/>\n\n      <copy todir=\"${dist.dir}/share/zookeeper\" includeEmptyDirs=\"false\">\n        <fileset dir=\"${lib.dir}\">\n          <exclude name=\"**/ivy*.jar\" />\n          <exclude name=\"**/deb*.jar\" />\n        </fileset>\n        <fileset dir=\"${ivy.lib}\"/>\n      </copy>\n\n      <copy file=\"${basedir}/src/packages/update-zookeeper-env.sh\" tofile=\"${dist.dir}/sbin/update-zookeeper-env.sh\"/>\n      <subant target=\"package\">\n        <!--Pass down the version in case its needed again and the target\n            distribution directory so contribs know where to install to.-->\n        <property name=\"version\" value=\"${version}\"/>\n        <property name=\"dist.dir\" value=\"${dist.dir}\"/>\n        <property name=\"package.share\" value=\"/share/zookeeper\"/>\n        <fileset file=\"${contrib.dir}/build.xml\"/>\n        <fileset file=\"${recipes.dir}/build.xml\"/>\n      </subant>\n\n      <copy todir=\"${dist.dir}/share/zookeeper\"> \n        <fileset file=\"${build.dir}/${final.name}.jar\"/>\n      </copy>\n\n      <checksum file=\"${dist.dir}/share/zookeeper/${final.name}.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.dir}/share/zookeeper/${final.name}.jar\" algorithm=\"sha1\"/>\n\n      <mkdir dir=\"${dist.maven.dir}\"/>\n\n      <copy file=\"${build.dir}/${final.name}-bin.jar\"\n            tofile=\"${dist.maven.dir}/${final.name}.jar\"/> \n      <copy todir=\"${dist.maven.dir}\"> \n        <fileset file=\"${build.dir}/${final.name}-sources.jar\"/>\n        <fileset file=\"${build.dir}/${final.name}-javadoc.jar\"/>\n      </copy>\n      \n      <checksum file=\"${dist.maven.dir}/${final.name}.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-sources.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-sources.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-javadoc.jar\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-javadoc.jar\" algorithm=\"sha1\"/>\n\n      <ivy:makepom settingsRef=\"${ant.project.name}\" ivyfile=\"${basedir}/ivy.xml\"\n                   pomfile=\"${dist.maven.dir}/${name}.pom\"\n                   templatefile=\"${basedir}/src/pom.template\">\n        <mapping conf=\"default\" scope=\"compile\"/>\n        <mapping conf=\"test\" scope=\"test\"/>\n      </ivy:makepom>\n      <checksum file=\"${dist.maven.dir}/${name}.pom\" algorithm=\"md5\"/>\n      <checksum file=\"${dist.maven.dir}/${name}.pom\" algorithm=\"sha1\"/>\n      \n      \n      <copy file=\"${build.dir}/${final.name}-test.jar\"\n            tofile=\"${dist.maven.dir}/${final.name}-tests.jar\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-tests.jar\" algorithm=\"sha1\"/>\n      <checksum file=\"${dist.maven.dir}/${final.name}-tests.jar\" algorithm=\"md5\"/>\n\n\n      <copy todir=\"${dist.dir}/bin\">\n        <fileset dir=\"bin\" includes=\"zkCli*\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/libexec\">\n        <fileset dir=\"bin\" includes=\"zkEnv*\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/sbin\">\n        <fileset dir=\"bin\" includes=\"zkServer*\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/conf\">\n        <fileset dir=\"${conf.dir}\" excludes=\"**/*.template\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/docs\">\n        <fileset dir=\"${docs.dir}\" />\n        <fileset dir=\"${build.docs}\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}\">\n        <fileset file=\"CHANGES.txt\"/>\n        <fileset file=\"README.md\"/>\n        <fileset file=\"README_packaging.txt\"/>\n        <fileset file=\"build.xml\"/>\n        <fileset file=\"ivy.xml\"/>\n        <fileset file=\"ivysettings.xml\"/>\n        <fileset file=\"src/NOTICE.txt\"/>\n        <fileset file=\"src/LICENSE.txt\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/src\" includeEmptyDirs=\"true\">\n        <fileset dir=\"src\" excludes=\"**/*.template **/docs/build/**/* **/ivy*.jar\"/>\n        <fileset file=\"src/pom.template\"/>\n      </copy>\n\n      <copy todir=\"${dist.dir}/${package.share.dir}/templates/conf\">\n        <fileset dir=\"src/packages/templates/conf\"/>\n      </copy>\n\n      <copy file=\"${basedir}/conf/zoo_sample.cfg\" tofile=\"${dist.dir}/${package.share.dir}/templates/conf/zoo.cfg\" />\n      <replace file=\"${dist.dir}/${package.share.dir}/templates/conf/zoo.cfg\">\n        <replacetoken>/tmp/zookeeper</replacetoken>\n        <replacevalue>${VAR_DIR}/data</replacevalue>\n      </replace>\n  \t  \n      <chmod perm=\"ugo+x\" type=\"file\" parallel=\"false\">\n        <fileset dir=\"${dist.dir}/bin\"/>\n        <fileset dir=\"${dist.dir}/sbin\"/>\n        <fileset dir=\"${dist.dir}/src/contrib/\">\n          <include name=\"*/bin/*\" />\n        </fileset>\n      </chmod>\n    </target>\n\n    <!-- ================================================================== -->\n    <!-- Make release tarball                                               -->\n    <!-- ================================================================== -->\n    <target name=\"tar\" depends=\"package\" description=\"Make release tarball\">\n      <macro_tar param.destfile=\"${build.dir}/${final.name}.tar.gz\">\n        <param.listofitems>\n          <!-- it's unfortunate that the binaries have to be duplicated\n               however that's the only way ant currently supports afaik -->\n          <tarfileset dir=\"${build.dir}\" mode=\"664\">\n            <exclude name=\"${final.name}/bin/*\" />\n            <exclude name=\"${final.name}/contrib/*/bin/*\" />\n\n            <exclude name=\"${final.name}/**/compile\" />\n            <exclude name=\"${final.name}/**/config.guess\" />\n            <exclude name=\"${final.name}/**/config.sub\" />\n            <exclude name=\"${final.name}/**/configure\" />\n            <exclude name=\"${final.name}/**/depcomp\" />\n            <exclude name=\"${final.name}/**/install-sh\" />\n            <exclude name=\"${final.name}/**/ltmain.sh\" />\n            <exclude name=\"${final.name}/**/missing\" />\n\n            <exclude name=\"${final.name}/**/*.sh\" />\n\n            <include name=\"${final.name}/**\" />\n          </tarfileset>\n          <tarfileset dir=\"${build.dir}\" mode=\"755\">\n            <!-- be sure to add to exclude list above if you add here -->\n            <include name=\"${final.name}/bin/*\" />\n            <include name=\"${final.name}/contrib/*/bin/*\" />\n\n            <!-- autotools related commands -->\n            <include name=\"${final.name}/**/compile\" />\n            <include name=\"${final.name}/**/config.guess\" />\n            <include name=\"${final.name}/**/config.sub\" />\n            <include name=\"${final.name}/**/configure\" />\n            <include name=\"${final.name}/**/depcomp\" />\n            <include name=\"${final.name}/**/install-sh\" />\n            <include name=\"${final.name}/**/ltmain.sh\" />\n            <include name=\"${final.name}/**/missing\" />\n\n            <!-- any shell scripts -->\n            <include name=\"${final.name}/**/*.sh\" />\n          </tarfileset>\n        </param.listofitems>\n      </macro_tar>\n    </target>\n\n    <target name=\"binary\" depends=\"bin-package\"\n            description=\"Make tarball without source and documentation\">\n      <macro_tar param.destfile=\"${build.dir}/${final.name}-bin.tar.gz\">\n        <param.listofitems>\n          <tarfileset dir=\"${build.dir}\" mode=\"664\">\n            <include name=\"${final.name}/src/c/**\" />\n            <exclude name=\"${final.name}/src/c/generated/**\" />\n          </tarfileset>\n          <tarfileset dir=\"${build.dir}\" mode=\"664\">\n            <exclude name=\"${final.name}/bin/*\" />\n            <exclude name=\"${final.name}/src/**\" />\n            <exclude name=\"${final.name}/docs/**\" />\n            <include name=\"${final.name}/**\" />\n          </tarfileset>\n          <tarfileset dir=\"${build.dir}\" mode=\"755\">\n            <include name=\"${final.name}/bin/*\" />\n          </tarfileset>\n        </param.listofitems>\n      </macro_tar>\n    </target>\n\n    <target name=\"package-native\" depends=\"compile-native, bin-package\" description=\"Make C binding tarball\">\n      <!-- For Unix platforms only, use OS native tar to preserve symlinks -->\n      <exec executable=\"tar\" dir=\"${build.dir}/c/build\">\n        <arg value=\"cfzv\" />\n        <arg value=\"${build.dir}/${final.name}-lib.tar.gz\" />\n        <arg value=\".\" />\n      </exec>\n      <subant target=\"package\">\n        <!--Pass down the version in case its needed again and the target\n            distribution directory so contribs know where to install to.-->\n        <property name=\"version\" value=\"${version}\"/>\n        <property name=\"dist.dir\" value=\"${dist.dir}\"/>\n        <fileset file=\"${contrib.dir}/build.xml\"/>\n        <fileset file=\"${recipes.dir}/build.xml\"/>\n      </subant>\n    </target>\n\n    <target name=\"rpm\" depends=\"package-native, tar\" description=\"Make rpm package\">\n      <!--The RPM spec file format disallows hyphen in the version.  Replace with\n          underscore to support version tags like -alpha or -SNAPSHOT.-->\n      <loadresource property=\"rpm.version\">\n        <propertyresource name=\"version\" />\n        <filterchain>\n          <tokenfilter>\n            <replacestring from=\"-\" to=\"_\" />\n          </tokenfilter>\n        </filterchain>\n      </loadresource>\n      <subant target=\"rpm\">\n        <!--Pass down the version in case its needed again and the target\n            distribution directory so contribs know where to install to.-->\n        <property name=\"version\" value=\"${version}\"/>\n        <property name=\"rpm.version\" value=\"${rpm.version}\"/>\n        <property name=\"dist.dir\" value=\"${dist.dir}\"/>\n        <fileset file=\"${contrib.dir}/build.xml\"/>\n        <fileset file=\"${recipes.dir}/build.xml\"/>\n      </subant>  \t\n      <path id=\"c.lib\">\n        <fileset dir=\"${build.dir}\">\n          <include name=\"${final.name}-lib.tar.gz\"/>\n        </fileset>\n      </path>\n      <property name=\"c.lib\" refid=\"c.lib\"/>\n      <mkdir dir=\"${package.buildroot}/BUILD\" />\n      <mkdir dir=\"${package.buildroot}/RPMS\" />\n      <mkdir dir=\"${package.buildroot}/SRPMS\" />\n      <mkdir dir=\"${package.buildroot}/SOURCES\" />\n      <mkdir dir=\"${package.buildroot}/SPECS\" />\n      <copy todir=\"${package.buildroot}/SOURCES\">\n        <fileset dir=\"${build.dir}\">\n          <include name=\"${final.name}.tar.gz\" />\n        </fileset>\n        <fileset file=\"${c.lib}\" />\n      </copy>\n      <copy file=\"${src.dir}/packages/rpm/spec/zookeeper.spec\" todir=\"${package.buildroot}/SPECS\">\n        <filterchain>\n          <replacetokens>\n            <token key=\"final.name\" value=\"${final.name}\" />\n            <token key=\"version\" value=\"${rpm.version}\" />\n            <token key=\"package.release\" value=\"${package.release}\" />\n            <token key=\"package.build.dir\" value=\"${package.build.dir}\" />\n            <token key=\"package.prefix\" value=\"${package.prefix}\" />\n            <token key=\"package.conf.dir\" value=\"${package.conf.dir}\" />\n            <token key=\"package.log.dir\" value=\"${package.log.dir}\" />\n            <token key=\"package.pid.dir\" value=\"${package.pid.dir}\" />\n            <token key=\"package.var.dir\" value=\"${package.var.dir}\" />\n            <token key=\"c.lib\" value=\"${c.lib}\" />\n          </replacetokens>\n        </filterchain>\n      </copy>\n      <rpm specFile=\"zookeeper.spec\" command=\"-ba --buildroot=${package.buildroot}/BUILD\" topDir=\"${package.buildroot}\" cleanBuildDir=\"true\" failOnError=\"true\"\n/>\n      <copy todir=\"${build.dir}/\" flatten=\"true\">\n        <fileset dir=\"${package.buildroot}/RPMS\">\n          <include name=\"**/${name}*.rpm\" />\n        </fileset>\n        <fileset dir=\"${package.buildroot}/SRPMS\">\n          <include name=\"**/${name}*.rpm\" />\n        </fileset>\n      </copy>\n      <delete dir=\"${package.buildroot}\" quiet=\"true\" verbose=\"false\"/>\n    </target>\n\n    <target name=\"deb\" depends=\"ivy-retrieve-package, package-native, tar\" description=\"Make deb package\">\n      <subant target=\"deb\">\n        <!--Pass down the version in case its needed again and the target\n            distribution directory so contribs know where to install to.-->\n        <property name=\"version\" value=\"${version}\"/>\n        <property name=\"dist.dir\" value=\"${dist.dir}\"/>\n        <fileset file=\"${contrib.dir}/build.xml\"/>\n        <fileset file=\"${recipes.dir}/build.xml\"/>\n      </subant>\n      <taskdef name=\"deb\" classname=\"org.vafer.jdeb.ant.DebAntTask\">\n        <classpath refid=\"java.classpath\"/>\n        <classpath refid=\"package.classpath\"/>\n      </taskdef>\n\n      <mkdir dir=\"${package.build.dir}/zookeeper.control\" />\n      <copy todir=\"${package.buildroot}/${package.prefix}\">\n        <fileset dir=\"${build.dir}/${final.name}\">\n          <include name=\"bin/**\" />\n          <include name=\"conf/**\" />\n          <include name=\"sbin/**\" />\n          <include name=\"share/**\" />\n        </fileset>\n      </copy>\n      <copy todir=\"${package.build.dir}/zookeeper.control\">\n        <fileset dir=\"${src.dir}/packages/deb/zookeeper.control\">\n          <exclude name=\"control\" />\n        </fileset>\n      </copy>\n      <copy file=\"${src.dir}/packages/deb/zookeeper.control/control\" todir=\"${package.build.dir}/zookeeper.control\">\n        <filterchain>\n          <replacetokens>\n            <token key=\"final.name\" value=\"${final.name}\" />\n            <token key=\"version\" value=\"${version}\" />\n            <token key=\"package.release\" value=\"${package.release}\" />\n            <token key=\"package.build.dir\" value=\"${package.build.dir}\" />\n            <token key=\"package.prefix\" value=\"${package.prefix}\" />\n            <token key=\"package.conf.dir\" value=\"${package.conf.dir}\" />\n            <token key=\"package.log.dir\" value=\"${package.log.dir}\" />\n            <token key=\"package.pid.dir\" value=\"${package.pid.dir}\" />\n            <token key=\"package.var.dir\" value=\"${package.var.dir}\" />\n          </replacetokens>\n        </filterchain>\n      </copy>\n      <deb destfile=\"${package.buildroot}/${name}_${version}-${package.release}_${os.arch}.deb\" control=\"${package.build.dir}/zookeeper.control\">\n        <tarfileset dir=\"${build.dir}/${final.name}/share/zookeeper\" filemode=\"644\" prefix=\"${package.prefix}/share/zookeeper\">\n          <include name=\"**\" />\n        </tarfileset>\n        <tarfileset dir=\"${build.dir}/${final.name}/bin\" filemode=\"755\" prefix=\"${package.prefix}/bin\">\n          <include name=\"zkCli.sh\" />\n        </tarfileset>\n        <tarfileset dir=\"${build.dir}/${final.name}/sbin\" filemode=\"755\" prefix=\"${package.prefix}/sbin\">\n          <include name=\"**.sh\" />\n        </tarfileset>\n        <tarfileset dir=\"${build.dir}/${final.name}/libexec\" filemode=\"755\" prefix=\"${package.prefix}/libexec\">\n          <include name=\"zkEnv.sh\" />\n        </tarfileset>\n        <tarfileset dir=\"${build.dir}/c/build/${package.prefix}/include\" prefix=\"${package.prefix}/include\">\n          <include name=\"**\" />\n        </tarfileset> \n        <tarfileset dir=\"${build.dir}/c/build/${package.prefix}/lib\" filemode=\"755\" prefix=\"${package.prefix}/lib\">\n          <include name=\"**\" />\n        </tarfileset> \n        <tarfileset dir=\"${build.dir}/${final.name}/conf\" filemode=\"644\" prefix=\"${package.conf.dir}\">\n          <include name=\"**\" />\n        </tarfileset>\n        <tarfileset dir=\"${build.dir}/${final.name}/src/packages/deb/init.d\" filemode=\"755\" prefix=\"/etc/init.d\">\n          <include name=\"**\" />\n        </tarfileset>\n      </deb>\n\n      <copy todir=\"${build.dir}/\" flatten=\"true\">\n        <fileset dir=\"${package.buildroot}\">\n          <include name=\"**/${name}*.deb\" />\n        </fileset>\n      </copy>\n      <delete dir=\"${package.buildroot}\" quiet=\"true\" verbose=\"false\"/>\n\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- mvn-deploy. Publishing jars to nexus -->\n    <!-- ====================================================== -->\n\n    <macrodef name=\"deploy\" description=\"macro definition for publishing artifacts to nexus snapshots\">\n      <attribute name=\"jars\" default=\"${tests-jar},${sources-jar},${javadoc-jar}\"/>\n      <attribute name=\"maven-jar\" default=\"${main-jar}\"/>\n      <attribute name=\"repo-url\" default=\"${snapshots_repo_url}\"/>\n      <attribute name=\"repo-id\" default=\"${snapshots_repo_id}\"/>\n      <attribute name=\"profile\" default=\"-P!gpg\"/>\n      <attribute name=\"plugin\" default=\"${deploy-plugin}\"/>\n      <attribute name=\"attachas\" default=\"tests,sources,javadoc\"/>\n      <sequential>\n\t<artifact:mvn>\n\t  <arg value=\"@{plugin}\"/>\n\t  <arg value=\"-Durl=@{repo-url}\"/>\n\t  <arg value=\"-DrepositoryId=@{repo-id}\"/>\n\t  <arg value=\"-Dfiles=@{jars}\"/>\n\t  <arg value=\"-Dfile=@{maven-jar}\"/>\n\t  <arg value=\"-Dpackaging=jar\"/>\n\t  <arg value=\"-DpomFile=${dist.maven.dir}/${name}.pom\"/>\n\t  <arg value=\"-Dclassifiers=@{attachas}\"/>\n\t  <arg value=\"-Dtype=jar\"/>\n\t  <arg value=\"-Dtypes=jar,jar,jar\"/>\n\t  <arg value=\"@{profile}\"/>\n\t</artifact:mvn>\n      </sequential>\n    </macrodef>\n\n    <target name=\"mvn-deploy\" depends=\"mvn-taskdef, bin-package, simpledeploy, signanddeploy\"\n     description=\"To deploy jar's to a maven repository\"/>\n\n    <target name=\"signanddeploy\" if=\"staging\">\n      <deploy repo-url=\"${staging_repo_url}\" repo-id=\"${staging_repo_id}\" plugin=\"${gpg-plugin}\" profile=\"-Pgpg\"/>\n    </target> \n\n    <target name=\"simpledeploy\" unless=\"staging\">\n      <deploy plugin=\"${deploy-plugin}\"/>\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- mvn-install. Installing the jar and pom file to .m2    -->\n    <!-- ====================================================== -->\n     \n     <target name=\"mvn-taskdef\" depends=\"ivy-retrieve-mvn-ant-task\">\n        <typedef resource=\"org/apache/maven/artifact/ant/antlib.xml\"\n        uri=\"antlib:org.apache.maven.artifact.ant\" classpathref=\"mvn-ant-task-classpath\"/>\n     </target>\n\n     <target name=\"mvn-install\" depends=\"bin-package, mvn-taskdef\">\n       <echo message=\"${dist.maven.dir}/${final.name}.pom\" />\n       <echo message=\"${dist.maven.dir}/${final.name}.jar\" />\n       <echo message=\"${dist.maven.dir}/${final.name}-sources.jar\" />\n       <echo message=\"${dist.maven.dir}/${final.name}-javadoc.jar\" />\n       <echo message=\"${dist.maven.dir}/${final.name}-tests.jar\" />\n  \n       <artifact:pom id=\"zookeeper-pom\" file=\"${dist.maven.dir}/${name}.pom\"/>\n       <echo>The version is ${zookeeper-pom.version}</echo>\n       <echo message=\"${dist.maven.dir}/${final.name}.jar\" />\n     \n       <artifact:install file=\"${dist.maven.dir}/${final.name}.jar\">\n         <pom refid=\"zookeeper-pom\" />\n         <attach file=\"${dist.maven.dir}/${final.name}.jar\" type=\"jar\"/>\n         <attach file=\"${dist.maven.dir}/${final.name}-sources.jar\" type=\"jar\" classifier=\"sources\"/>\n         <attach file=\"${dist.maven.dir}/${final.name}-javadoc.jar\" type=\"jar\" classifier=\"javadoc\"/>\n         <attach file=\"${dist.maven.dir}/${final.name}-tests.jar\" type=\"jar\" classifier=\"tests\"/>\n       </artifact:install>\n    </target>\n\n    <!-- ====================================================== -->\n    <!-- Clean.  Delete the build files, and their directories  -->\n    <!-- ====================================================== -->\n    <target name=\"clean\" depends=\"clean-contrib,clean-recipes\"\n            description=\"Clean.  Delete the build files, and their directories\">\n      <delete dir=\"${build.dir}\"/>\n      <delete dir=\"${docs.src}/build\"/>\n      <delete dir=\"${src_generated.dir}\" />\n      <delete dir=\"${csrc_generated.dir}\" />\n      <delete dir=\"${csharpsrc_generated.dir}\"/>\n      <delete file=\"${lib.dir}/Null.java\"/>\n      <delete file=\"${lib.dir}/rats.jar\" />\n      <delete file=\"${jdiff.xml.dir}/${name}_${version}.xml\"/>\t\n      <delete file=\"${jar.name}\" />\n      <delete dir=\"${distribution}\"/>\n      <delete dir=\"${revision.dir}\"/>\n      <delete>\n        <fileset dir=\"${basedir}\" includes=\"*.jar,*.tar.gz\"/>\n      </delete>\n      <delete dir=\"${package.buildroot}\" />\n    </target>\n\n    <target name=\"clean-contrib\">\n      <subant target=\"clean\">        \n        <fileset file=\"${contrib.dir}/build.xml\"/>\n      </subant>  \t\n    </target>\n\n   <target name=\"clean-recipes\">\n     <subant target=\"clean\">\n       <fileset file=\"${recipes.dir}/build.xml\"/>\n     </subant>\n   </target>\n\n    <!-- ====================================================== -->\n    <!-- Run unit tests                                         -->\n    <!-- ====================================================== -->\n    <target name=\"test-init\" depends=\"jar,compile-test\">\n        <delete dir=\"${test.log.dir}\" />\n        <delete dir=\"${test.tmp.dir}\" />\n        <delete dir=\"${test.data.upgrade.dir}\" />\n        <delete dir=\"${test.data.invalid.dir}\" />\n        <delete dir=\"${test.data.buffersize.dir}\" />\n        <delete dir=\"${test.data.kerberos.dir}\" />\n        <delete dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.tmp.dir}\" />\n        <mkdir dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.data.upgrade.dir}\" />\n        <mkdir dir=\"${test.data.invalid.dir}\" />\n        <copy todir=\"${test.data.upgrade.dir}\">\n            <fileset dir=\"${basedir}/src/java/test/data/upgrade\"/>\n        </copy>\n        <copy todir=\"${test.data.invalid.dir}\">\n            <fileset dir=\"${basedir}/src/java/test/data/invalidsnap\"/>\n        </copy>\n        <mkdir dir=\"${test.data.buffersize.dir}\" />\n        <copy todir=\"${test.data.buffersize.dir}\">\n            <fileset dir=\"${basedir}/src/java/test/data/buffersize\"/>\n        </copy>\n        <mkdir dir=\"${test.data.kerberos.dir}\" />\n        <copy todir=\"${test.data.kerberos.dir}\">\n            <fileset dir=\"${basedir}/src/java/test/data/kerberos\"/>\n        </copy>\n    </target>\n\n    <condition property=\"quicktest\">\n      <and>\n        <equals arg1=\"${test.quick}\" arg2=\"yes\"/>\n        <not>\n          <isset property=\"testcase\"/>\n        </not>\n      </and>\n    </condition>\n    <condition property=\"fulltest\">\n      <and>\n        <equals arg1=\"${test.quick}\" arg2=\"no\"/>\n        <not>\n          <isset property=\"testcase\"/>\n        </not>\n      </and>\n    </condition>\n\n    <target name=\"junit.run\">\n        <junit showoutput=\"${test.output}\"\n               printsummary=\"${test.junit.printsummary}\"\n               haltonfailure=\"${test.junit.haltonfailure}\"\n               fork=\"yes\"\n               forkmode=\"${test.junit.fork.mode}\"\n               maxmemory=\"${test.junit.maxmem}\"\n               dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n          <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n          <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n          <sysproperty key=\"log4j.configuration\"\n                       value=\"file:${basedir}/conf/log4j.properties\" />\n          <!-- superDigest is used by the tests/main code. If this is not set\n               as part of starting the jvm there is no guarantee that the static\n               initializers in the java code will see this (esp when running\n               with junit fork mode set to \"once\")-->\n          <sysproperty key=\"zookeeper.DigestAuthenticationProvider.superDigest\"\n                       value=\"super:D/InIHSb7yEEbrWz8b9l71RjZJU=\" />\n          <classpath refid=\"test.java.classpath\"/>\n          <classpath>\n            <pathelement path=\"${test.java.classes}\" />\n          </classpath>\n          <formatter type=\"${test.junit.output.format}\" />\n          <batchtest todir=\"${test.log.dir}\" if=\"quicktest\">\n            <fileset dir=\"${test.src.dir}\">\n              <include name=\"**/*${test.category}Test.java\"/>\n              <exclude name=\"**/*HammerTest.java\"/>\n            </fileset>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"fulltest\">\n            <fileset dir=\"${test.src.dir}\">\n              <include name=\"**/*${test.category}Test.java\"/>\n            </fileset>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n            <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n          </batchtest>\n        </junit>\n        <antcall target=\"fail.build.on.test.failure\"/>\n    </target>\n    <target name=\"fail.build.on.test.failure\" if=\"${test.junit.failbuild.ontestfailure}\" >\n        <fail if=\"tests.failed\">Tests failed!</fail>\n    </target>\n\n    <target name=\"check-cppunit-configure\" depends=\"init\" >\n      <condition property=\"need.cppunit.configure\">\n        <not> <available file=\"${c.src.dir}/configure\"/> </not>\n      </condition>\n    </target>\t\n\n    <target name=\"check-cppunit-makefile\" depends=\"init\" >\n    \t<condition property=\"need.cppunit.makefile\">\n       \t\t<not> <available file=\"${test.cppunit.dir}/Makefile\"/> </not>\n    \t</condition>\n    </target>\n\n    <!--\n       1. If we have a Makefile it will handle up-to-date check and also\n          regenerate the configure script if missing. (done)\n       2. If we don't have a Makefile use the configure script to \n          regenerate it. (done)\n       3. If we don't have a Makefile nor a configure script then it's\n          last resort and run autoreconf, then configure (done)\n      -->\n\n    <target name=\"create-cppunit-configure\" depends=\"check-cppunit-configure\"\n            if=\"need.cppunit.configure\">\n      <exec executable=\"autoreconf\" dir=\"${c.src.dir}\" searchpath=\"yes\"\n            failonerror=\"yes\">\n        <arg value=\"-if\"/>\n        <env key=\"ACLOCAL\" value=\"aclocal -I ${cppunit.m4}\"/>\n      </exec>\n    </target>\n\n    <target name=\"create-cppunit-makefile\" depends=\"check-cppunit-makefile\" \n                                           if=\"need.cppunit.makefile\">\n      <antcall target=\"create-cppunit-configure\">\n        <param name=\"cppunit\" value=\"true\"/>\n      </antcall>\n    \t<mkdir dir=\"${test.cppunit.dir}\"/>\n    \t<exec executable=\"${c.src.dir}/configure\" dir=\"${test.cppunit.dir}\"\n          \tfailonerror=\"yes\">\n                <env key=\"base_dir\" value=\"${basedir}\"/>\n                <env key=\"CALLER\" value=\"ANT\"/>\n      \t\t<arg value=\"--prefix=${test.cppunit.dir}\"/>\n    \t</exec>\n    </target>\n\n    <target name=\"call-test-cppunit\" description=\"to execute cppunit tests\">\n\t<antcall target=\"create-cppunit-makefile\"/>\n\t<antcall target=\"test-cppunit\">\n\t\t<param name=\"cppunit\" value=\"true\"/>\n\t</antcall>\n    </target>\t\t\t\n\n\n    <target name=\"test-cppunit\"\n            depends=\"compile_jute, jar, create-cppunit-makefile\"\n            if=\"cppunit\"\n\t\tdescription=\"to run cppunit test cases\">\n        <exec dir=\"${test.cppunit.dir}\" executable=\"make\" failonerror=\"true\">\n\t\t<env key=\"LD_LIBRARY_PATH\" value=\"${env.LD_LIBRARY_PATH};${cppunit.lib}\"/>\n\t\t<env key=\"PATH\" path=\"${env.PATH};${c.src.dir};\"/>\n                <env key=\"CALLER\" value=\"ANT\"/>\n                <env key=\"CLOVER_HOME\" value=\"${clover.home}\"/>\n                <env key=\"base_dir\" value=\"${basedir}\"/>\n\t\t<arg line=\"clean run-check\"/>\n\t</exec>\n    </target>\n   \n    <target name=\"test-unit-category\">\n      <property name=\"test.category\" value=\"Unit\"/>\n    </target>\n    <target name=\"test-unit\" depends=\"test-init,test-unit-category,junit.run\"/>\n\n    <target name=\"test-func-category\">\n      <property name=\"test.category\" value=\"Func\"/>\n    </target>\n    <target name=\"test-func\" depends=\"test-init,test-func-category,junit.run\"/>\n\n    <target name=\"test-perf-category\">\n      <property name=\"test.category\" value=\"Perf\"/>\n    </target>\n    <target name=\"test-perf\" depends=\"test-init,test-perf-category,junit.run\"/>\n\n    <target name=\"test-category\">\n      <property name=\"test.category\" value=\"\"/>\n    </target>\n\n    <target name=\"test\" description=\"to run core and contrib tests\">\n\t<antcall target=\"test-core\"/>\n\t<antcall target=\"test-contrib\"/>\n    </target>\n \n    <target name=\"test-contrib\" description=\"to run contrib tests\">\n\t<!-- yet to implement -->\n    </target>\n    \n    <target name=\"test-core-java\" depends=\"test-init, test-category, junit.run\"/> \n\n    <target name=\"test-core-cppunit\" depends=\"test-init, test-category, call-test-cppunit\"/> \n\n    <target name=\"test-core\" depends=\"test-core-java, test-core-cppunit\"/> \n\n    <!-- ====================================================== -->\n    <!-- Run optional third-party tool targets                  -->\n    <!-- ====================================================== -->\n\n    <!-- clover code coverage -->\n    <target name=\"clover\" depends=\"clover.setup, clover.info\" \n            description=\"Instrument the Unit tests using Clover.  Requires a Clover license and CLOVER_HOME environment variable set appropriately.  To use, specify -Drun.clover=true on the command line.\"/>\n\n    <target name=\"clover.setup\" if=\"clover.enabled\">\n      <taskdef resource=\"cloverlib.xml\" classpath=\"${clover.jar}\"/>\n      <mkdir dir=\"${clover.db.dir}\"/>\n      <clover-setup initString=\"${clover.db.dir}/zookeeper_coverage.db\">\n        <fileset dir=\"${java.src.dir}\"\n                 includes=\"org/apache/zookeeper/**/*\"\n                 excludes=\"org/apache/zookeeper/version/**/*\"/>\n      </clover-setup>\n    </target>\n\n    <target name=\"clover.info\" if=\"run.clover\" unless=\"clover.present\">\n      <echo>\n        Clover not found. Code coverage reports disabled.\n      </echo>\n    </target>\n\n    <target name=\"clover.check\">\n      <fail unless=\"clover.present\">\n        ##################################################################\n        Clover not found.\n        Please make sure clover.jar is in ANT_HOME/lib, or made available\n        to Ant using other mechanisms like -lib or CLASSPATH.\n        ##################################################################\n      </fail>\n    </target>\n\n    <target name=\"generate-clover-reports\" depends=\"clover.check, clover\">\n      <mkdir dir=\"${clover.report.dir}\"/>\n      <taskdef resource=\"cloverlib.xml\" classpath=\"${clover.jar}\"/> \n      \n      <clover-report initString=\"${clover.db.dir}/zookeeper_coverage.db\">\n        <current outfile=\"${clover.report.dir}\" title=\"${final.name}\">\n          <format type=\"html\"/>\n        </current>\n      </clover-report>\n      <clover-report initString=\"${clover.db.dir}/zookeeper_coverage.db\">\n        <current outfile=\"${clover.report.dir}/clover.xml\" title=\"${final.name}\">\n          <format type=\"xml\"/>\n        </current>\n      </clover-report>\n    </target>\n\n    <!-- Run with 'ant -Dfindbugs.home=\"path to Findbugs directory\" findbugs -->\n    <property name=\"findbugs.home\" value=\"\" />\n    <target name=\"findbugs\" depends=\"check-for-findbugs, jar\" if=\"findbugs.present\">\n        <property name=\"findbugs.out.dir\" value=\"${test.java.build.dir}/findbugs\" />\n        <property name=\"findbugs.exclude.file\" value=\"${config.dir}/findbugsExcludeFile.xml\" />\n        <property name=\"findbugs.report.htmlfile\" value=\"${findbugs.out.dir}/zookeeper-findbugs-report.html\" />\n        <property name=\"findbugs.report.xmlfile\" value=\"${findbugs.out.dir}/zookeeper-findbugs-report.xml\" />\n        <taskdef name=\"findbugs\" classname=\"edu.umd.cs.findbugs.anttask.FindBugsTask\" \n                classpath=\"${findbugs.home}/lib/findbugs-ant.jar\" />\n        <mkdir dir=\"${findbugs.out.dir}\" />\n        <findbugs home=\"${findbugs.home}\" output=\"xml:withMessages\" excludeFilter=\"${findbugs.exclude.file}\" \n                outputFile=\"${findbugs.report.xmlfile}\" effort=\"max\" jvmargs=\"-Xmx512M\">\n            <auxClasspath>\n                <fileset dir=\"${ivy.lib}\">\n                    <include name=\"**/*.jar\" />\n                </fileset>\n            </auxClasspath>\n            <sourcePath path=\"${java.src.dir}\" />\n            <class location=\"${build.dir}/${final.name}.jar\" />\n        </findbugs>\n        <xslt style=\"${findbugs.home}/src/xsl/default.xsl\" in=\"${findbugs.report.xmlfile}\" \n                out=\"${findbugs.report.htmlfile}\" />\n    </target>\n\n    <target name=\"check-for-findbugs\">\n        <available property=\"findbugs.present\" file=\"${findbugs.home}/lib/findbugs.jar\" />\n    </target>\n\n    <!-- Code coverage -->\n    <target name=\"cobertura-instrument\" depends=\"compile-test\">\n      <taskdef resource=\"tasks.properties\">\n        <classpath>\n          <pathelement path=\"${lib.dir}/cobertura/cobertura.jar\" />\n          <fileset dir=\"${lib.dir}/cobertura/lib\">\n            <include name=\"*.jar\"/>\n          </fileset>\n          <fileset dir=\"${lib.dir}\">\n            <include name=\"*.jar\"/>\n          </fileset>\n          <fileset dir=\"${ivy.lib}\">\n            <include name=\"**/*.jar\" />\n          </fileset>\n        </classpath>\n      </taskdef>\n\n      <cobertura-instrument todir=\"${build.dir}/cobertura\">\n        <fileset dir=\"${build.classes}\">\n          <include name=\"org/apache/zookeeper/**/*.class\"/>\n        </fileset>\n      </cobertura-instrument>\n    </target>\n\n    <target name=\"cobertura-test\" depends=\"test-init,cobertura-instrument\">\n        <junit showoutput=\"${test.output}\" printsummary=\"yes\" haltonfailure=\"no\" fork=\"yes\" \n               maxmemory=\"${test.junit.maxmem}\" dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n            <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n            <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n            <sysproperty key=\"log4j.configuration\"\n                         value=\"file:${basedir}/conf/log4j.properties\" />\n            <classpath>\n                <pathelement path=\"${build.dir}/cobertura\" />\n                <pathelement path=\"${lib.dir}/cobertura/cobertura.jar\" />\n                <fileset dir=\"${lib.dir}/cobertura/lib\">\n                    <include name=\"*.jar\"/>\n                </fileset>\n                <fileset dir=\"${lib.dir}\">\n                    <include name=\"*.jar\"/>\n                </fileset>\n                <fileset dir=\"${ivy.lib}\">\n                  <include name=\"**/*.jar\" />\n                </fileset>\n            </classpath>\n            <classpath>\n                <pathelement path=\"${test.java.classes}\" />\n            </classpath>\n            <classpath refid=\"test.java.classpath\"/>\n            <classpath>\n                <pathelement path=\"${build.classes}\" />\n            </classpath>\n\n            <formatter type=\"${test.junit.output.format}\" />\n            <batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n                <fileset dir=\"${test.src.dir}\"\n                         includes=\"**/*Test.java\"/>\n            </batchtest>\n            <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n                <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n            </batchtest>\n        </junit>\n        <antcall target=\"fail.build.on.test.failure\"/>\n    </target>\n\n    <target name=\"cobertura-report\" depends=\"cobertura-test\">\n        <cobertura-report format=\"${test.cobertura.output.format}\"\n                          destdir=\"${coveragereport.dir}\" > \n            <fileset dir=\"${java.src.dir}\">\n                <include name=\"**/*.java\" />\n            </fileset>\n            <fileset dir=\"${src_generated.dir}\">\n                <include name=\"**/*.java\" />\n            </fileset>\n        </cobertura-report>\n    </target>\n\n    <target name=\"checkstyle\" depends=\"ivy-retrieve-test\" description=\"Run Checkstyle coding standard checks\">\n      <taskdef resource=\"checkstyletask.properties\" uri=\"antlib:com.puppycrawl.tools.checkstyle\">\n        <classpath>\n          <fileset dir=\"${ivy.test.lib}\" includes=\"*.jar\" />\n        </classpath>\n      </taskdef>\n      <mkdir dir=\"${test.java.build.dir}\"/>\n      <cs:checkstyle config=\"${test.src.dir}/checkstyle.xml\" failOnViolation=\"false\">\n        <fileset dir=\"${src.dir}/java\" includes=\"**/*.java\" excludes=\"**/generated/**\"/>\n        <formatter type=\"xml\" toFile=\"${test.java.build.dir}/checkstyle-errors.xml\"/>\n      </cs:checkstyle>\n      <xslt style=\"${test.src.dir}/checkstyle-noframes-sorted.xsl\" in=\"${test.java.build.dir}/checkstyle-errors.xml\"\n            out=\"${test.java.build.dir}/checkstyle-errors.html\"/>\n    </target>\n\n    <!-- ================================================================== -->\n    <!-- Perform audit activities for the release                           -->\n    <!-- ================================================================== -->\n    <target name=\"rats-taskdef\" depends=\"ivy-retrieve-releaseaudit\">\n      <typedef format=\"xml\" resource=\"org/apache/rat/anttasks/antlib.xml\" uri=\"antlib:org.apache.rat.anttasks\"\n               classpathref=\"releaseaudit-classpath\"/>\n    </target>\n\n    <target name=\"owasp-taskdef\" depends=\"ivy-retrieve-owasp\">\n        <typedef format=\"properties\" resource=\"dependency-check-taskdefs.properties\" uri=\"antlib:org.owasp.dependencycheck.anttasks\" classpathref=\"owasp-classpath\"/>\n    </target>\n\n    <target name=\"owasp\" depends=\"owasp-taskdef,ivy-retrieve\" description=\"OWASP dependency check\">\n        <property name=\"owasp.out.dir\" value=\"${test.java.build.dir}/owasp\" />\n\n        <owasp:dependency-check xmlns:owasp=\"antlib:org.owasp.dependencycheck.anttasks\"\n                          projectname=\"ZooKeeper\"\n                          reportoutputdirectory=\"${owasp.out.dir}\"\n                          reportformat=\"ALL\"\n                          failBuildOnCVSS=\"0\">\n\n            <fileset dir=\"${ivy.lib}\">\n                <include name=\"**/*.jar\"/>\n            </fileset>\n\n            <fileset dir=\"${lib.dir}\">\n                <include name=\"**/*.jar\"/>\n            </fileset>\n        </owasp:dependency-check>\n    </target>\n\n    <target name=\"releaseaudit\" depends=\"package,rats-taskdef\" description=\"Release Audit activities\">\n      <rat:report xmlns:rat=\"antlib:org.apache.rat.anttasks\">\n        <fileset dir=\"${dist.dir}\">\n          <exclude name=\"**/*.m4\"/>\n          <exclude name=\"**/*.md5\"/>\n          <exclude name=\"**/*.pom\"/>\n          <exclude name=\"**/*.sha1\"/>\n          <exclude name=\"**/.gitignore\"/>\n          <exclude name=\"**/Makefile**\"/>\n          <exclude name=\"**/winconfig.h\"/>\n          <exclude name=\"**/configure**\"/>\n          <exclude name=\"**/*Doxyfile\"/>\n          <exclude name=\"**/*.am\"/>\n          <exclude name=\"**/compile\"/>\n          <exclude name=\"**/depcomp\"/>\n          <exclude name=\"**/install-sh\"/>\n          <exclude name=\"**/ltmain.sh\"/>\n          <exclude name=\"**/missing\"/>\n          <exclude name=\"**/wrappers*.opt\"/>\n          <exclude name=\"CHANGES.txt\"/>\n          <exclude name=\"**/VERSION\"/>\n          <exclude name=\"**/ChangeLog\"/>\n          <exclude name=\"**/OldChangeLog\"/>\n          <exclude name=\"**/Changes\"/>\n          <exclude name=\"**/contrib/zkperl/MANIFEST\"/>\n          <exclude name=\"**/conf/*\"/>\n          <exclude name=\"**/docs/\"/>\n          <exclude name=\"**/lib/jdiff/\"/>\n          <exclude name=\"src/c/autom4te.cache/**\"/>\n          <exclude name=\"src/c/config**\"/>\n          <exclude name=\"src/c/src/hashtable/\"/>\n          <exclude name=\"src/java/generated/.generated/\"/>\n          <exclude name=\"src/java/test/checkstyle*.xml\"/>\n          <exclude name=\"src/java/test/checkstyle*.xsl\"/>\n          <exclude name=\"src/java/test/config/findbugs*.xml\"/>\n          <exclude name=\"src/**/*.vcproj\"/>\n          <exclude name=\"src/**/*.sln\"/>\n        </fileset>\n      </rat:report>\n    </target>\n\n    <target name=\"findbugs.check\" depends=\"check-for-findbugs\" unless=\"findbugs.present\">\n    \t<fail message=\"'findbugs.home' is not defined. Please pass -Dfindbugs.home=&lt;base of Findbugs installation&gt; \n\t\tto Ant on the command-line.\" />\n    </target>\n\n    <target name=\"patch.check\" unless=\"patch.file\">\n  \t<fail message=\"'patch.file' is not defined. Please pass -Dpatch.file=&lt;location of patch file&gt; \n\t\tto Ant on the command-line.\" />\n    </target>\n\n    <target name=\"test-patch\" depends=\"patch.check,findbugs.check,forrest.check\">\n  \t<exec executable=\"bash\" failonerror=\"true\">\n    \t\t<arg value=\"${test_patch_sh}\"/>\n    \t\t<arg value=\"DEVELOPER\"/>\n    \t\t<arg value=\"${patch.file}\"/>\n    \t\t<arg value=\"${scratch.dir}\"/>\n    \t\t<arg value=\"${svn.cmd}\"/>\n    \t\t<arg value=\"${grep.cmd}\"/>\n    \t\t<arg value=\"${patch.cmd}\"/>\n    \t\t<arg value=\"${findbugs.home}\"/>\n    \t\t<arg value=\"${forrest.home}\"/>\n    \t\t<arg value=\"${basedir}\"/>\n    \t\t<arg value=\"${java5.home}\"/>\n  \t</exec>\n    </target>\n\n    <target name=\"hudson-test-patch\" depends=\"findbugs.check,forrest.check\">\n  \t<exec executable=\"bash\" failonerror=\"true\">\n    \t\t<arg value=\"${test_patch_sh}\"/>\n    \t\t<arg value=\"HUDSON\"/>\n    \t\t<arg value=\"${scratch.dir}\"/>\n    \t\t<arg value=\"${ps.cmd}\"/>\n    \t\t<arg value=\"${wget.cmd}\"/>\n    \t\t<arg value=\"${jiracli.cmd}\"/>\n    \t\t<arg value=\"${svn.cmd}\"/>\n    \t\t<arg value=\"${grep.cmd}\"/>\n    \t\t<arg value=\"${patch.cmd}\"/>\n    \t\t<arg value=\"${findbugs.home}\"/>\n    \t\t<arg value=\"${forrest.home}\"/>\n    \t\t<arg value=\"${basedir}\"/>\n    \t\t<arg value=\"${jira.passwd}\"/>\n    \t\t<arg value=\"${java5.home}\"/>\n    \t\t<arg value=\"${curl.cmd}\"/>\n    \t\t<arg value=\"${defect}\"/>\n    \t</exec>\n     </target>\n\n   <target name=\"qa-test-pullrequest\" depends=\"findbugs.check,forrest.check\">\n        <exec executable=\"bash\" failonerror=\"true\">\n                <arg value=\"${test_pullrequest_sh}\"/>\n                <arg value=\"QABUILD\"/>\n                <arg value=\"${scratch.dir}\"/>\n                <arg value=\"${ps.cmd}\"/>\n                <arg value=\"${wget.cmd}\"/>\n                <arg value=\"${jiracli.cmd}\"/>\n                <arg value=\"${git.cmd}\"/>\n                <arg value=\"${grep.cmd}\"/>\n                <arg value=\"${patch.cmd}\"/>\n                <arg value=\"${findbugs.home}\"/>\n                <arg value=\"${forrest.home}\"/>\n                <arg value=\"${basedir}\"/>\n                <arg value=\"${jira.passwd}\"/>\n                <arg value=\"${java5.home}\"/>\n                <arg value=\"${curl.cmd}\"/>\n        </exec>\n     </target>\n\n\n     <!-- this target runs the hudson trunk build -->\n     <target name=\"hudson-test-trunk\" depends=\"docs,tar,findbugs\"/>\n\n     <target name=\"api-xml\" depends=\"ivy-retrieve-jdiff, javadoc, write-null\">\n       <javadoc>\n         <doclet name=\"jdiff.JDiff\"\n                 path=\"${ivy.jdiff.lib}/jdiff-1.0.9.jar:${ivy.jdiff.lib}/xerces-1.4.4.jar\">\n           <param name=\"-apidir\" value=\"${jdiff.xml.dir}\"/>\n           <param name=\"-apiname\" value=\"${name} ${version}\"/>\n         </doclet>\n         <packageset dir=\"${java.src.dir}\">\n           <include name=\"org/apache/zookeeper\"/>\n           <exclude name=\"org/apache/jute\"/>\n         </packageset>\n         <classpath>\n           <pathelement location=\"${build.classes}\"/>\n           <fileset dir=\"${lib.dir}\">\n             <include name=\"**/*.jar\" />\n             <exclude name=\"**/excluded/\" />\n           </fileset>\n           <fileset dir=\"${ivy.lib}\">\n             <include name=\"**/*.jar\" />\n           </fileset>\n         </classpath>\n       </javadoc>\n     </target>\n     \n     <target name=\"write-null\">\n       <exec executable=\"touch\">\n         <arg value=\"${jdiff.home}/Null.java\"/>\n       </exec>\n     </target> \n\n     <target name=\"api-report\" depends=\"api-xml\">\n       <mkdir dir=\"${jdiff.build.dir}\"/>\n       <javadoc sourcepath=\"${java.src.dir}\"\n                destdir=\"${jdiff.build.dir}\"\n                excludepackagenames=\"org.apache.jute\"\t\n                sourceFiles=\"${jdiff.home}/Null.java\">\n         <doclet name=\"jdiff.JDiff\"\n                 path=\"${ivy.jdiff.lib}/jdiff-1.0.9.jar:${ivy.jdiff.lib}/xerces-1.4.4.jar\">\n           <param name=\"-oldapi\" value=\"${name} ${jdiff.stable}\"/>\n           <param name=\"-newapi\" value=\"${name} ${version}\"/>\n           <param name=\"-oldapidir\" value=\"${jdiff.xml.dir}\"/>\n           <param name=\"-newapidir\" value=\"${jdiff.xml.dir}\"/>\n           <param name=\"-javadocold\" value=\"${jdiff.stable.javadoc}\"/>\n           <param name=\"-javadocnew\" value=\"../../api/\"/>\n           <param name=\"-stats\"/>\n         </doclet>\n         <classpath>\n           <pathelement location=\"${build.classes}\"/>\n           <fileset dir=\"${lib.dir}\">\n             <include name=\"**/*.jar\" />\n             <exclude name=\"**/excluded/\" />\n           </fileset>\n           <fileset dir=\"${ivy.lib}\">\n             <include name=\"**/*.jar\" />\n           </fileset>\n         </classpath>\n       </javadoc>\n     </target>\n\n     <condition property=\"ant-eclipse.jar.exists\">\n       <available file=\"${lib.dir}/ant-eclipse-1.0-jvm1.2.jar\"/>\n     </condition>\n\n     <target name=\"ant-eclipse-download\" unless=\"ant-eclipse.jar.exists\">\n       <get src=\"https://downloads.sourceforge.net/project/ant-eclipse/ant-eclipse/1.0/ant-eclipse-1.0.bin.tar.bz2\"\n            dest=\"${src.dir}/java/ant-eclipse-1.0.bin.tar.bz2\" usetimestamp=\"false\" />\n\n       <bunzip2 src=\"${src.dir}/java/ant-eclipse-1.0.bin.tar.bz2\"/>\n\n       <untar src=\"${src.dir}/java/ant-eclipse-1.0.bin.tar\"\n              dest=\"${src.dir}/java\">\n         <patternset>\n           <include name=\"lib/ant-eclipse-1.0-jvm1.2.jar\"/>\n         </patternset>\n       </untar>\n\n       <delete file=\"${src.dir}/java/ant-eclipse-1.0.bin.tar\" />\n       <delete file=\"${src.dir}/java/ant-eclipse-1.0.bin.tar.bz2\" />\n     </target>\n\n     <target name=\"eclipse\"\n             depends=\"ant-eclipse-download,init,ivy-retrieve,build-generated,ivy-retrieve-test\"\n             description=\"Create eclipse project files\">\n       <ivy:resolve useOrigin=\"true\" conf=\"test\"/>\n       <ivy:cachepath pathid=\"default.path.id\" conf=\"default\" />\n       <ivy:cachepath pathid=\"junit.path.id\" conf=\"test\" />\n       <taskdef name=\"eclipse\"\n                classname=\"prantl.ant.eclipse.EclipseTask\"\n                classpathref=\"java.classpath\" />\n       <eclipse updatealways=\"true\">\n         <settings>\n           <jdtcore compilercompliance=\"6.0\" />\n           <resources encoding=\"UTF-8\" />\n         </settings>\n         <project name=\"${ant.project.name}\" />\n         <classpath>\n           <source path=\"${java.src.dir}\"\n                   output=\"${build.dir.eclipse-main-classes}\" />\n           <source path=\"${src_generated.dir}\"\n                   output=\"${build.dir.eclipse-main-classes}\" />\n           <source path=\"${test.src.dir}\"\n                   output=\"${build.dir.eclipse-test-classes}\" />\n           <source path=\"${systest.src.dir}\"\n                   output=\"${build.dir.eclipse-test-classes}\" />\n\n           <output path=\"${build.dir.eclipse-main-classes}\" />\n           <library pathref=\"default.path.id\" exported=\"true\" />\n           <library pathref=\"junit.path.id\" exported=\"false\" />\n         </classpath>\n       </eclipse>\n     </target>\n\n     <target name=\"clean-eclipse\" description=\"Clean eclipse files\">\n       <delete file=\".classpath\" />\n       <delete file=\".eclipse\" />\n       <delete file=\".project\" />\n       <delete dir=\".settings\" />\n       <delete dir=\"${build.dir.eclipse}\" />\n     </target>\n\n</project>\n"
  },
  {
    "path": "conf/configuration.xsl",
    "content": "<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n<xsl:output method=\"html\"/>\n<xsl:template match=\"configuration\">\n<html>\n<body>\n<table border=\"1\">\n<tr>\n <td>name</td>\n <td>value</td>\n <td>description</td>\n</tr>\n<xsl:for-each select=\"property\">\n<tr>\n  <td><a name=\"{name}\"><xsl:value-of select=\"name\"/></a></td>\n  <td><xsl:value-of select=\"value\"/></td>\n  <td><xsl:value-of select=\"description\"/></td>\n</tr>\n</xsl:for-each>\n</table>\n</body>\n</html>\n</xsl:template>\n</xsl:stylesheet>\n"
  },
  {
    "path": "conf/log4j.properties",
    "content": "# Define some default values that can be overridden by system properties\nzookeeper.root.logger=INFO, CONSOLE\nzookeeper.console.threshold=INFO\nzookeeper.log.dir=.\nzookeeper.log.file=zookeeper.log\nzookeeper.log.threshold=DEBUG\nzookeeper.tracelog.dir=.\nzookeeper.tracelog.file=zookeeper_trace.log\n\n#\n# ZooKeeper Logging Configuration\n#\n\n# Format is \"<default threshold> (, <appender>)+\n\n# DEFAULT: console appender only\nlog4j.rootLogger=${zookeeper.root.logger}\n\n# Example with rolling log file\n#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE\n\n# Example with rolling log file and tracing\n#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE\n\n#\n# Log INFO level and above messages to the console\n#\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold}\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n\n\n#\n# Add ROLLINGFILE to rootLogger to get log file output\n#    Log DEBUG level and above messages to a log file\nlog4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender\nlog4j.appender.ROLLINGFILE.Threshold=${zookeeper.log.threshold}\nlog4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/${zookeeper.log.file}\n\n# Max log file size of 10MB\nlog4j.appender.ROLLINGFILE.MaxFileSize=10MB\n# uncomment the next line to limit number of backup files\n#log4j.appender.ROLLINGFILE.MaxBackupIndex=10\n\nlog4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n\n\n\n#\n# Add TRACEFILE to rootLogger to get log file output\n#    Log DEBUG level and above messages to a log file\nlog4j.appender.TRACEFILE=org.apache.log4j.FileAppender\nlog4j.appender.TRACEFILE.Threshold=TRACE\nlog4j.appender.TRACEFILE.File=${zookeeper.tracelog.dir}/${zookeeper.tracelog.file}\n\nlog4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout\n### Notice we are including log4j's NDC here (%x)\nlog4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L][%x] - %m%n\n"
  },
  {
    "path": "conf/zoo_sample.cfg",
    "content": "# The number of milliseconds of each tick\ntickTime=2000\n# The number of ticks that the initial \n# synchronization phase can take\ninitLimit=10\n# The number of ticks that can pass between \n# sending a request and getting an acknowledgement\nsyncLimit=5\n# the directory where the snapshot is stored.\n# do not use /tmp for storage, /tmp here is just \n# example sakes.\ndataDir=/tmp/zookeeper\n# the port at which the clients will connect\nclientPort=2181\n# the maximum number of client connections.\n# increase this if you need to handle more clients\n#maxClientCnxns=60\n#\n# Be sure to read the maintenance section of the \n# administrator guide before turning on autopurge.\n#\n# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance\n#\n# The number of snapshots to retain in dataDir\n#autopurge.snapRetainCount=3\n# Purge task interval in hours\n# Set to \"0\" to disable auto purge feature\n#autopurge.purgeInterval=1\n"
  },
  {
    "path": "docs/bookkeeperConfig.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>BookKeeper Administrator's Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.3', 'skin/')\" id=\"menu_selected_1.3Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">BookKeeper</div>\n<div id=\"menu_selected_1.3\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Setup guide</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"bookkeeperConfig.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>BookKeeper Administrator's Guide</h1>\n<h3>Setup Guide</h3>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_deployment\">Deployment</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_sysReq\">System requirements</a>\n</li>\n<li>\n<a href=\"#bk_runningBookies\">Running bookies</a>\n</li>\n<li>\n<a href=\"#bk_zkMetadata\">ZooKeeper Metadata</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n\n  \n<a name=\"bk_deployment\"></a>\n<h2 class=\"h3\">Deployment</h2>\n<div class=\"section\">\n<p>This section contains information about deploying BookKeeper and\n    covers these topics:</p>\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#bk_sysReq\">System requirements</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#bk_runningBookies\">Running bookies</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#bk_zkMetadata\">ZooKeeper Metadata</a>\n</p>\n      \n</li>\n    \n</ul>\n<p> The first section tells you how many machines you need. The second explains how to bootstrap bookies\n     (BookKeeper storage servers). The third section explains how we use ZooKeeper and our requirements with\n     respect to ZooKeeper.\n    </p>\n<a name=\"bk_sysReq\"></a>\n<h3 class=\"h4\">System requirements</h3>\n<p> A typical BookKeeper installation comprises a set of bookies and a set of ZooKeeper replicas. The exact number of bookies\n \t   depends on the quorum mode, desired throughput, and number of clients using this installation simultaneously. The minimum number of\n \t   bookies is three for self-verifying (stores a message authentication code along with each entry) and four for generic (does not\n \t   store a message authentication codewith each entry), and there is no upper limit on the number of bookies. Increasing the number of \n \t   bookies, in fact, enables higher throughput.\n \t   </p>\n<p> For performance, we require each server to have at least two disks. It is possible to run a bookie with a single disk, but \n \t   performance will be significantly lower in this case. Of course, it works with one disk, but performance is significantly lower. \n \t   </p>\n<p> For ZooKeeper, there is no constraint with respect to the number of replicas. Having a single machine running ZooKeeper\n \t   in standalone mode is sufficient for BookKeeper. For resilience purposes, it might be a good idea to run ZooKeeper in quorum \n \t   mode with multiple servers. Please refer to the ZooKeeper documentation for detail on how to configure ZooKeeper with multiple\n \t   replicas\n \t   </p>\n<a name=\"bk_runningBookies\"></a>\n<h3 class=\"h4\">Running bookies</h3>\n<p>\n \t   To run a bookie, we execute the following command:\n \t   </p>\n<p>\n<span class=\"codefrag computeroutput\">\n\t\tjava -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\\\n\t\t:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\\ \n\t\torg.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\\\n\t\t/path_to_ledger_device/\n\t   </span>\n</p>\n<p>\n \t   The parameters are:\n \t   </p>\n<ul>\n \t   \t\n<li>\n \t   \t\n<p>\n \t   \t\tPort number that the bookie listens on;\n \t   \t</p>\n \t   \t\n</li>\n \t   \t\n \t   \t\n<li>\n \t   \t\n<p>\n \t   \t\tComma separated list of ZooKeeper servers with a hostname:port format;\n \t   \t</p>\n \t   \t\n</li>\n \t   \t\n \t   \t\n<li>\n \t   \t\n<p>\n \t   \t\tPath for Log Device (stores bookie write-ahead log);\n \t   \t</p>\n \t   \t\n</li>\n \t   \t\n \t   \t\n<li>\n \t   \t\n<p>\n \t   \t\tPath for Ledger Device (stores ledger entries);\n \t   \t</p>\n \t   \t\n</li>\n \t   \n</ul>\n<p>\n \t   Ideally, <span class=\"codefrag computeroutput\">/path_to_log_device/ </span> and <span class=\"codefrag computeroutput\">/path_to_ledger_device/ </span> are each\n \t   in a different device. \n \t   </p>\n<a name=\"bk_zkMetadata\"></a>\n<h3 class=\"h4\">ZooKeeper Metadata</h3>\n<p>\n \t   For BookKeeper, we require a ZooKeeper installation to store metadata, and to pass the list\n \t   of ZooKeeper servers as parameter to the constructor of the BookKeeper class (<span class=\"codefrag computeroutput\">\n \t   org.apache.bookkeeper.client,BookKeeper</span>).\n \t   To setup ZooKeeper, please check the <a href=\"index.html\">\n          ZooKeeper documentation</a>.\n \t   </p>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/bookkeeperOverview.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>BookKeeper overview</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.3', 'skin/')\" id=\"menu_selected_1.3Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">BookKeeper</div>\n<div id=\"menu_selected_1.3\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Overview</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"bookkeeperOverview.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>BookKeeper overview</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_Overview\">BookKeeper overview</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_Intro\">BookKeeper introduction</a>\n</li>\n<li>\n<a href=\"#bk_moreDetail\">In slightly more detail...</a>\n</li>\n<li>\n<a href=\"#bk_basicComponents\">Bookkeeper elements and concepts</a>\n</li>\n<li>\n<a href=\"#bk_initialDesign\">Bookkeeper initial design</a>\n</li>\n<li>\n<a href=\"#bk_metadata\">Bookkeeper metadata management</a>\n</li>\n<li>\n<a href=\"#bk_closingOut\">Closing out ledgers</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n  \n<a name=\"bk_Overview\"></a>\n<h2 class=\"h3\">BookKeeper overview</h2>\n<div class=\"section\">\n<a name=\"bk_Intro\"></a>\n<h3 class=\"h4\">BookKeeper introduction</h3>\n<p>\n\tBookKeeper is a replicated service to reliably log streams of records. In BookKeeper, \n\tservers are \"bookies\", log streams are \"ledgers\", and each unit of a log (aka record) is a \n\t\"ledger entry\". BookKeeper is designed to be reliable; bookies, the servers that store \n\tledgers, can crash, corrupt data, discard data, but as long as there are enough bookies \n\tbehaving correctly the service as a whole behaves correctly.\n\t</p>\n<p>\n    The initial motivation for BookKeeper comes from the namenode of HDFS. Namenodes have to \n    log operations in a reliable fashion so that recovery is possible in the case of crashes. \n    We have found the applications for BookKeeper extend far beyond HDFS, however. Essentially, \n    any application that requires an append storage can replace their implementations with\n    BookKeeper. BookKeeper has the advantage of scaling throughput with the number of servers. \n    </p>\n<p>\n    At a high level, a bookkeeper client receives entries from a client application and stores it to\n    sets of bookies, and there are a few advantages in having such a service:\n\t</p>\n<ul>\n    \n<li>\n    \n<p>\n    \tWe can use hardware that is optimized for such a service. We currently believe that such a\n      \tsystem has to be optimized only for disk I/O;\n    </p>\n    \n</li>\n    \n    \n<li>\n    \n<p>\n    \tWe can have a pool of servers implementing such a log system, and shared among a number of servers;\n    </p>\n    \n</li>\n    \n    \n<li>\n    \n<p>\n    \tWe can have a higher degree of replication with such a pool, which makes sense if the hardware necessary for it is cheaper compared to the one the application uses. \n\t</p>\n\t\n</li>\n\t\n</ul>\n<a name=\"bk_moreDetail\"></a>\n<h3 class=\"h4\">In slightly more detail...</h3>\n<p> BookKeeper implements highly available logs, and it has been designed with write-ahead logging in mind. Besides high availability\n    due to the replicated nature of the service, it provides high throughput due to striping. As we write entries in a subset of bookies of an\n    ensemble and rotate writes across available quorums, we are able to increase throughput with the number of servers for both reads and writes. \n    Scalability is a property that is possible to achieve in this case due to the use of quorums. Other replication techniques, such as \n    state-machine replication, do not enable such a property. \n    </p>\n<p> An application first creates a ledger before writing to bookies through a local BookKeeper client instance.   \n  \tUpon creating a ledger, a BookKeeper client writes metadata about the ledger to ZooKeeper. Each ledger currently \n  \thas a single writer. This writer has to execute a close ledger operation before any other client can read from it. \n  \tIf the writer of a ledger does not close a ledger properly because, for example, it has crashed before having the \n  \topportunity of closing the ledger, then the next client that tries to open a ledger executes a procedure to recover\n  \tit. As closing a ledger consists essentially of writing the last entry written to a ledger to ZooKeeper, the recovery\n  \tprocedure simply finds the last entry written correctly and writes it to ZooKeeper.\t\n\t</p>\n<p>\n\tNote that currently this recovery procedure is executed automatically upon trying to open a ledger and no explicit action is necessary. \n\tAlthough two clients may try to recover a ledger concurrently, only one will succeed, the first one that is able to create the close znode\n\tfor the ledger.\n\t</p>\n<a name=\"bk_basicComponents\"></a>\n<h3 class=\"h4\">Bookkeeper elements and concepts</h3>\n<p> \n\tBookKeeper uses four basic elements:\n\t</p>\n<ul>\n      \n<li>\n      \n<p> \n\t\t\n<strong>Ledger</strong>: A ledger is a sequence of entries, and each entry is a sequence of bytes. Entries are\n\t\twritten sequentially to a ledger and at most once. Consequently, ledgers have an append-only semantics;\n\t  </p>\n\t  \n</li>\n\t\n\t  \n<li>\n\t  \n<p> \n\t\t\n<strong>BookKeeper client</strong>: A client runs along with a BookKeeper application, and it enables applications\n\t\tto execute operations on ledgers, such as creating a ledger and writing to it; \n\t  </p>\n\t  \n</li> \n\t\n\t  \n<li>\n\t  \n<p>\n\t\t\n<strong>Bookie</strong>: A bookie is a BookKeeper storage server. Bookies store the content of ledgers. For any given\n\t\tledger L, we call an <em>ensemble</em> the group of bookies storing the content of L. For performance, we store on\n\t\teach bookie of an ensemble only a fragment of a ledger. That is, we stripe when writing entries to a ledger such that\n\t\teach entry is written to sub-group of bookies of the ensemble.\n\t  </p>\n\t  \n</li>\n\n\t  \n<li>\n\t  \n<p> \t\n\t\t\n<strong>Metadata storage service</strong>: BookKeeper requires a metadata storage service to store information related \n\t\tto ledgers and available bookies. We currently use ZooKeeper for such a task.     \n   \t  </p>\n   \t  \n</li>\n    \n</ul>\n<a name=\"bk_initialDesign\"></a>\n<h3 class=\"h4\">Bookkeeper initial design</h3>\n<p>\n    A set of bookies implements BookKeeper, and we use a quorum-based protocol to replicate data across the bookies. \n    There are basically two operations to an existing ledger: read and append. Here is the complete API list \n    (mode detail <a href=\"bookkeeperProgrammer.html\">\n    \t      here</a>):\n\t</p>\n<ul>\n\t\n<li>\n\t\n<p>\n    \tCreate ledger: creates a new empty ledger; \n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    \tOpen ledger: opens an existing ledger for reading;\n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    \tAdd entry: adds a record to a ledger either synchronously or asynchronously;\n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    Read entries: reads a sequence of entries from a ledger either synchronously or asynchronously \n\t</p>\n    \n</li>\n\t\n</ul>\n<p>\n\tThere is only a single client that can write to a ledger. Once that ledger is closed or the client fails, \n\tno more entries can be added. (We take advantage of this behavior to provide our strong guarantees.) \n\tThere will not be gaps in the ledger. Fingers get broken, people get roughed up or end up in prison when\n\tbooks are manipulated, so there is no deleting or changing of entries.\n\t</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>BookKeeper Overview</td>\n</tr>\n<tr>\n<td>\n        \n            <img alt=\"\" src=\"images/bk-overview.jpg\">\n        \n        </td>\n</tr>\n</table>\n<p>\n    A simple use of BooKeeper is to implement a write-ahead transaction log. A server maintains an in-memory data structure\n    (with periodic snapshots for example) and logs changes to that structure before it applies the change. The application \n    server creates a ledger at startup and store the ledger id and password in a well known place (ZooKeeper maybe). When \n    it needs to make a change, the server adds an entry with the change information to a ledger and apply the change when \n    BookKeeper adds the entry successfully. The server can even use asyncAddEntry to queue up many changes for high change\n    throughput. BooKeeper meticulously logs the changes in order and call the completion functions in order.\n\t</p>\n<p>\n    When the application server dies, a backup server will come online, get the last snapshot and then it will open the \n    ledger of the old server and read all the entries from the time the snapshot was taken. (Since it doesn't know the \n    last entry number it will use MAX_INTEGER). Once all the entries have been processed, it will close the ledger and \n    start a new one for its use. \n\t</p>\n<p>\n\tA client library takes care of communicating with bookies and managing entry numbers. An entry has the following fields:\n\t</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<caption>Entry fields</caption>\n<title>Entry fields</title>\n\t\n\t\n<tr>\n  \t\n<th>Field</th>\n  \t<th>Type</th>\n  \t<th>Description</th>\n\t\n</tr>\n\t\n\t\n<tr>\n  \t\n<td>Ledger number</td>\n  \t<td>long</td>\n  \t<td>The id of the ledger of this entry</td>\n\t\n</tr>\n\t\n<tr>\n  \t\n<td>Entry number</td>\n  \t<td>long</td>\n  \t<td>The id of this entry</td>\n\t\n</tr>\n\t\n\t\n<tr>\n  \t\n<td>last confirmed (<em>LC</em>)</td>\n  \t<td>long</td>\n  \t<td>id of the last recorded entry</td>\n\t\n</tr>\n\t\n<tr>\n  \t\n<td>data</td>\n  \t<td>byte[]</td>\n  \t<td>the entry data (supplied by application)</td>\n\t\n</tr>\n\t\n<tr>\n  \t\n<td>authentication code</td>\n  \t<td>byte[]</td>\n  \t<td>Message authentication code that includes all other fields of the entry</td>\n\t\n</tr>\n\t\n\t\n\t\n</table>\n<p>\n\tThe client library generates a ledger entry. None of the fields are modified by the bookies and only the first three \n\tfields are interpreted by the bookies.\n\t</p>\n<p>\n\tTo add to a ledger, the client generates the entry above using the ledger number. The entry number will be one more \n\tthan the last entry generated. The <em>LC</em> field contains the last entry that has been successfully recorded by BookKeeper. \n\tIf the client writes entries one at a time, <em>LC</em> is the last entry id. But, if the client is using asyncAddEntry, there \n\tmay be many entries in flight. An entry is considered recorded when both of the following conditions are met:\n\t</p>\n<ul>\n\t\n<li>\n    \n<p>\n    \tthe entry has been accepted by a quorum of bookies\n    </p>\n    \n</li>\n    \n    \n<li>\n    \n<p>\n    \tall entries with a lower entry id have been accepted by a quorum of bookies \n\t</p>\n\t\n</li>\n    \n</ul>\n<p>\n\t\n<em>LC</em> seems mysterious right now, but it is too early to explain how we use it; just smile and move on.\n\t</p>\n<p>\n\tOnce all the other fields have been field in, the client generates an authentication code with all of the previous fields. \n\tThe entry is then sent to a quorum of bookies to be recorded. Any failures will result in the entry being sent to a new\n\tquorum of bookies.\n\t</p>\n<p>\n\tTo read, the client library initially contacts a bookie and starts requesting entries. If an entry is missing or \n\tinvalid (a bad MAC for example), the client will make a request to a different bookie. By using quorum writes, \n\tas long as enough bookies are up we are guaranteed to eventually be able to read an entry.\n\t</p>\n<a name=\"bk_metadata\"></a>\n<h3 class=\"h4\">Bookkeeper metadata management</h3>\n<p>\n\tThere are some meta data that needs to be made available to BookKeeper clients:\n\t</p>\n<ul>\n\t\n<li>\n\t\n<p>\n\t\tThe available bookies;\n\t</p>\n\t\n</li>\n\t\n\t\n<li>\n\t\n<p>\n    \tThe list of ledgers;\n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    \tThe list of bookies that have been used for a given ledger;\n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    \tThe last entry of a ledger; \n\t</p>\n\t\n</li>\n\t\n</ul>\n<p>\n\tWe maintain this information in ZooKeeper. Bookies use ephemeral nodes to indicate their availability. Clients \n\tuse znodes to track ledger creation and deletion and also to know the end of the ledger and the bookies that \n\twere used to store the ledger. Bookies also watch the ledger list so that they can cleanup ledgers that get deleted.\n\t</p>\n<a name=\"bk_closingOut\"></a>\n<h3 class=\"h4\">Closing out ledgers</h3>\n<p>\n\tThe process of closing out the ledger and finding the last ledger is difficult due to the durability guarantees of BookKeeper:\n\t</p>\n<ul>\n\t\n<li>\n\t\n<p>\n    \tIf an entry has been successfully recorded, it must be readable.\n    </p>\n    \n</li>\n    \n    \n<li>\n\t\n<p>\n    \tIf an entry is read once, it must always be available to be read. \n\t</p>\n\t\n</li>\n\t\n</ul>\n<p>\n\tIf the ledger was closed gracefully, ZooKeeper will have the last entry and everything will work well. But, if the \n\tBookKeeper client that was writing the ledger dies, there is some recovery that needs to take place.\n\t</p>\n<p>\n\tThe problematic entries are the ones at the end of the ledger. There can be entries in flight when a BookKeeper client \n\tdies. If the entry only gets to one bookie, the entry should not be readable since the entry will disappear if that bookie\n\tfails. If the entry is only on one bookie, that doesn't mean that the entry has not been recorded successfully; the other\n\tbookies that recorded the entry might have failed.\n\t</p>\n<p>\n\tThe trick to making everything work is to have a correct idea of a last entry. We do it in roughly three steps:\n\t</p>\n<ol>\n\t\n<li>\n\t\n<p>\n\t\tFind the entry with the highest last recorded entry, <em>LC</em>;\n\t</p>\n\t\n</li>\n\t\n\t\n<li>\n\t\n<p>\n\t\tFind the highest consecutively recorded entry, <em>LR</em>;\n\t</p>\n\t\n</li>\n\t\n\t\n<li>\n\t\n<p>\n\t\tMake sure that all entries between <em>LC</em> and <em>LR</em> are on a quorum of bookies; \n\t</p>\n\t\n</li>\n\t\n\t\n</ol>\n</div>  \n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/bookkeeperProgrammer.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>BookKeeper Getting Started Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.3', 'skin/')\" id=\"menu_selected_1.3Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">BookKeeper</div>\n<div id=\"menu_selected_1.3\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Programmer's guide</div>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"bookkeeperProgrammer.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>BookKeeper Getting Started Guide</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_GettingStarted\">Programming with BookKeeper</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_instance\"> Instantiating BookKeeper.</a>\n</li>\n<li>\n<a href=\"#bk_createLedger\"> Creating a ledger. </a>\n</li>\n<li>\n<a href=\"#bk_writeLedger\"> Adding entries to a ledger. </a>\n</li>\n<li>\n<a href=\"#bk_closeLedger\"> Closing a ledger. </a>\n</li>\n<li>\n<a href=\"#bk_openLedger\"> Opening a ledger. </a>\n</li>\n<li>\n<a href=\"#bk_readLedger\"> Reading from ledger </a>\n</li>\n<li>\n<a href=\"#bk_deleteLedger\"> Deleting a ledger </a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n  \n<a name=\"bk_GettingStarted\"></a>\n<h2 class=\"h3\">Programming with BookKeeper</h2>\n<div class=\"section\">\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#bk_instance\"> Instantiating BookKeeper.</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#bk_createLedger\"> Creating a ledger. </a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#bk_writeLedger\"> Adding entries to a ledger. </a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#bk_closeLedger\"> Closing a ledger. </a>\n</p>\n      \n</li>\n      \n\t  \n<li>\n        \n<p>\n<a href=\"#bk_openLedger\"> Opening a ledger. </a>\n</p>\n      \n</li>\n      \n      \n<li>\n        \n<p>\n<a href=\"#bk_readLedger\"> Reading from ledger </a>\n</p>\n      \n</li>\n      \n      \n<li>\n        \n<p>\n<a href=\"#bk_deleteLedger\"> Deleting a ledger </a>\n</p>\n      \n</li>\n      \n    \n</ul>\n<a name=\"bk_instance\"></a>\n<h3 class=\"h4\"> Instantiating BookKeeper.</h3>\n<p>\n    The first step to use BookKeeper is to instantiate a BookKeeper object:\n    </p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n    org.apache.bookkeeper.BookKeeper\n    </span>\n    \n</p>\n<p>\n    There are three BookKeeper constructors:\n    </p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic BookKeeper(String servers) \n    \tthrows KeeperException, IOException    \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">servers</span> is a comma-separated list of ZooKeeper servers.\n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic BookKeeper(ZooKeeper zk) \n    \tthrows InterruptedException, KeeperException    \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">zk</span> is a ZooKeeper object. This constructor is useful when\n        the application also using ZooKeeper and wants to have a single instance of ZooKeeper.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic BookKeeper(ZooKeeper zk, ClientSocketChannelFactory channelFactory) \n    \tthrows InterruptedException, KeeperException    \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">zk</span> is a ZooKeeper object. This constructor is useful when\n        the application also using ZooKeeper and wants to have a single instance of ZooKeeper.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">channelFactory</span> is a netty channel object \n        (<span class=\"codefrag computeroutput\">org.jboss.netty.channel.socket</span>).  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<a name=\"bk_createLedger\"></a>\n<h3 class=\"h4\"> Creating a ledger. </h3>\n<p> Before writing entries to BookKeeper, it is necessary to create a ledger. \n    With the current BookKeeper API, it is possible to create a ledger both synchronously\n    or asynchronously. The following methods belong\n    to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.BookKeeper</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous call:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n    public LedgerHandle createLedger(int ensSize, int qSize, DigestType type,  byte passwd[])\n        throws KeeperException, InterruptedException, \n        IOException, BKException\n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n    \t\n<span class=\"codefrag computeroutput\">ensSize</span> is the number of bookies (ensemble size);\n    \t</p>\n    \t\n</li>\n    \n    \t\n<li> \n    \t\n<p>\n    \t\n<span class=\"codefrag computeroutput\">qSize</span> is the write quorum size;\n    \t</p>\n    \t\n</li>\n    \n    \t\n<li> \n    \t\n<p>\n    \t\n<span class=\"codefrag computeroutput\">type</span> is the type of digest used with entries: either MAC or CRC32.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p>\n    \t\n<span class=\"codefrag computeroutput\">passwd</span> is a password that authorizes the client to write to the\n    \tledger being created.\n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    All further operations on a ledger are invoked through the <span class=\"codefrag computeroutput\">LedgerHandle</span>\n    object returned.\n    </p>\n<p>\n    As a convenience, we provide a <span class=\"codefrag computeroutput\">createLedger</span> with default parameters (3,2,VERIFIABLE), \n    and the only two input parameters it requires are a digest type and a password.\n    </p>\n<p>\n   \t\n<strong>Asynchronous call:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n    public void asyncCreateLedger(int ensSize, \n            int qSize, \n            DigestType type,  \n            byte passwd[],\n            CreateCallback cb,\n            Object ctx\n            )\n    </span>\n\t\n</p>\n<p>\n\tThe parameters are the same of the synchronous version, with the\n\texception of <span class=\"codefrag computeroutput\">cb</span> and <span class=\"codefrag computeroutput\">ctx</span>. <span class=\"codefrag computeroutput\">CreateCallback</span>\n\tis an interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">createComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tvoid createComplete(int rc, LedgerHandle lh, Object ctx);\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKException</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">lh</span> is a <span class=\"codefrag computeroutput\">LedgerHandle</span> object to manipulate a ledger;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is a control object for accountability purposes. It can be essentially any object the application is happy with.\n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n<p>\n\tThe <span class=\"codefrag computeroutput\">ctx</span> object passed as a parameter to the call to create a ledger\n\tis the one same returned in the callback.\n    </p>\n<a name=\"bk_writeLedger\"></a>\n<h3 class=\"h4\"> Adding entries to a ledger. </h3>\n<p>\n    Once we have a ledger handle <span class=\"codefrag computeroutput\">lh</span> obtained through a call to create a ledger, we\n    can start writing entries. As with creating ledgers, we can write both synchronously and \n    asynchronously. The following methods belong\n    to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.LedgerHandle</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous call:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic long addEntry(byte[] data)\n    \tthrows InterruptedException\n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n    \t\n<span class=\"codefrag computeroutput\">data</span> is a byte array;\n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n\tA call to <span class=\"codefrag computeroutput\">addEntry</span> returns the status of the operation (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n    </p>\n<p>\n   \t\n<strong>Asynchronous call:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void asyncAddEntry(byte[] data, AddCallback cb, Object ctx)\n    </span>\n\t\n</p>\n<p>\n    It also takes a byte array as the sequence of bytes to be stored as an entry. Additionaly, it takes\n    a callback object <span class=\"codefrag computeroutput\">cb</span> and a control object <span class=\"codefrag computeroutput\">ctx</span>. The callback object must implement\n    the <span class=\"codefrag computeroutput\">AddCallback</span> interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">addComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tvoid addComplete(int rc, LedgerHandle lh, long entryId, Object ctx);\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">lh</span> is a <span class=\"codefrag computeroutput\">LedgerHandle</span> object to manipulate a ledger;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">entryId</span> is the identifier of entry associated with this request;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is control object used for accountability purposes. It can be any object the application is happy with.\n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n<a name=\"bk_closeLedger\"></a>\n<h3 class=\"h4\"> Closing a ledger. </h3>\n<p>\n    Once a client is done writing, it closes the ledger. The following methods belong\n    to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.LedgerHandle</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous close:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void close() \n    throws InterruptedException\n    </span>\n\t\n</p>\n<p>\n    It takes no input parameters.\n    </p>\n<p>\n   \t\n<strong>Asynchronous close:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void asyncClose(CloseCallback cb, Object ctx)\n    throws InterruptedException\n    </span>\n\t\n</p>\n<p>\n    It takes a callback object <span class=\"codefrag computeroutput\">cb</span> and a control object <span class=\"codefrag computeroutput\">ctx</span>. The callback object must implement\n    the <span class=\"codefrag computeroutput\">CloseCallback</span> interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">closeComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tvoid closeComplete(int rc, LedgerHandle lh, Object ctx)\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">lh</span> is a <span class=\"codefrag computeroutput\">LedgerHandle</span> object to manipulate a ledger;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is control object used for accountability purposes. \n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n<a name=\"bk_openLedger\"></a>\n<h3 class=\"h4\"> Opening a ledger. </h3>\n<p>\n    To read from a ledger, a client must open it first. The following methods belong\n    to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.BookKeeper</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous open:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic LedgerHandle openLedger(long lId, DigestType type, byte passwd[])\n    throws InterruptedException, BKException\n    </span>\n\t\n</p>\n<ul>\n\t\n<li>\n\t\n<p>\n\t\n<span class=\"codefrag computeroutput\">ledgerId</span> is the ledger identifier;\n\t</p>\n\t\n</li>\n\t\n\t\n<li> \n    \n<p>\n    \n<span class=\"codefrag computeroutput\">type</span> is the type of digest used with entries: either MAC or CRC32.  \n    </p>\n    \n</li>\n\t\n\t\n<li>\n\t\n<p>\n\t\n<span class=\"codefrag computeroutput\">passwd</span> is a password to access the ledger (used only in the case of <span class=\"codefrag computeroutput\">VERIFIABLE</span> ledgers);\n\t</p>\n\t\n</li>\n\t\n</ul>\n<p>\n   \t\n<strong>Asynchronous open:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void asyncOpenLedger(long lId, DigestType type, byte passwd[], OpenCallback cb, Object ctx)\n    </span>\n\t\n</p>\n<p>\n    It also takes a a ledger identifier and a password. Additionaly, it takes a callback object \n    <span class=\"codefrag computeroutput\">cb</span> and a control object <span class=\"codefrag computeroutput\">ctx</span>. The callback object must implement\n    the <span class=\"codefrag computeroutput\">OpenCallback</span> interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">openComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tpublic void openComplete(int rc, LedgerHandle lh, Object ctx)\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">lh</span> is a <span class=\"codefrag computeroutput\">LedgerHandle</span> object to manipulate a ledger;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is control object used for accountability purposes. \n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n<a name=\"bk_readLedger\"></a>\n<h3 class=\"h4\"> Reading from ledger </h3>\n<p>\n    Read calls may request one or more consecutive entries. The following methods belong\n    to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.LedgerHandle</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous read:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic Enumeration&lt;LedgerEntry&gt; readEntries(long firstEntry, long lastEntry) \n    throws InterruptedException, BKException\n    </span>\n\t\n</p>\n<ul>\n\t\n<li>\n\t\n<p>\n\t\n<span class=\"codefrag computeroutput\">firstEntry</span> is the identifier of the first entry in the sequence of entries to read;\n\t</p>\n\t\n</li>\n\t\n\t\n<li>\n\t\n<p>\n\t\n<span class=\"codefrag computeroutput\">lastEntry</span> is the identifier of the last entry in the sequence of entries to read.\n\t</p>\n\t\n</li>\n\t\n</ul>\n<p>\n   \t\n<strong>Asynchronous read:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void asyncReadEntries(long firstEntry, \n            long lastEntry, ReadCallback cb, Object ctx)\n    throws BKException, InterruptedException\n    </span>\n\t\n</p>\n<p>\n    It also takes a first and a last entry identifiers. Additionaly, it takes a callback object \n    <span class=\"codefrag computeroutput\">cb</span> and a control object <span class=\"codefrag computeroutput\">ctx</span>. The callback object must implement\n    the <span class=\"codefrag computeroutput\">ReadCallback</span> interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">readComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tvoid readComplete(int rc, LedgerHandle lh, Enumeration&lt;LedgerEntry&gt; seq, Object ctx)\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">lh</span> is a <span class=\"codefrag computeroutput\">LedgerHandle</span> object to manipulate a ledger;\n\t\t</p>\n\t\t\n</li>\n\t\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">seq</span> is a <span class=\"codefrag computeroutput\">Enumeration&lt;LedgerEntry&gt; </span> object to containing the list of entries requested;\n\t\t</p>\n\t\t\n</li>\n\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is control object used for accountability purposes. \n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n<a name=\"bk_deleteLedger\"></a>\n<h3 class=\"h4\"> Deleting a ledger </h3>\n<p>\n    Once a client is done with a ledger and is sure that nobody will ever need to read from it again, they can delete the ledger.\n    The following methods belong to <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.BookKeeper</span>.\n    </p>\n<p>\n   \t\n<strong>Synchronous delete:</strong>\n   \t\n</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n        public void deleteLedger(long lId) throws InterruptedException, BKException\n    </span>\n    \n</p>\n<ul>\n\t\n<li>\n\t\n<p>\n\t\n<span class=\"codefrag computeroutput\">lId</span> is the ledger identifier;\n\t</p>\n\t\n</li>\n\t\n</ul>\n<p>\n   \t\n<strong>Asynchronous delete:</strong>\n    \n</p>\n<p>\n      \n<span class=\"codefrag computeroutput\">\n\t public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) \n      </span>\n    \n</p>\n<p>\n    It takes a ledger identifier. Additionally, it takes a callback object \n    <span class=\"codefrag computeroutput\">cb</span> and a control object <span class=\"codefrag computeroutput\">ctx</span>. The callback object must implement\n    the <span class=\"codefrag computeroutput\">DeleteCallback</span> interface in <span class=\"codefrag computeroutput\">org.apache.bookkeeper.client.AsyncCallback</span>, and\n\ta class implementing it has to implement a method called <span class=\"codefrag computeroutput\">deleteComplete</span>\n\tthat has the following signature: \n    </p>\n<p>\n\t\n<span class=\"codefrag computeroutput\">\n\tvoid deleteComplete(int rc, Object ctx)\n\t</span>    \n\t\n</p>\n<p>\n\twhere:\n\t</p>\n<ul>\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">rc</span> is a return code (please refer to <span class=\"codefrag computeroutput\">org.apache.bookeeper.client.BKDefs</span> for a list);\n\t\t</p>\n\t\t\n</li>\n\t\n\t\t\n<li>\n\t\t\n<p>\n\t\t\n<span class=\"codefrag computeroutput\">ctx</span> is control object used for accountability purposes. \n\t\t</p>\n\t\t\n</li>\n\t\n</ul>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/bookkeeperStarted.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>BookKeeper Getting Started Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.3', 'skin/')\" id=\"menu_selected_1.3Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">BookKeeper</div>\n<div id=\"menu_selected_1.3\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Getting started</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"bookkeeperStarted.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>BookKeeper Getting Started Guide</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_GettingStarted\">Getting Started: Setting up BookKeeper to write logs.</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_Prerequisites\">Pre-requisites</a>\n</li>\n<li>\n<a href=\"#bk_Download\">Download</a>\n</li>\n<li>\n<a href=\"#bk_localBK\">LocalBookKeeper</a>\n</li>\n<li>\n<a href=\"#bk_setupBookies\">Setting up bookies</a>\n</li>\n<li>\n<a href=\"#bk_setupZK\">Setting up ZooKeeper</a>\n</li>\n<li>\n<a href=\"#bk_example\">Example</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n  \n<a name=\"bk_GettingStarted\"></a>\n<h2 class=\"h3\">Getting Started: Setting up BookKeeper to write logs.</h2>\n<div class=\"section\">\n<p>This document contains information to get you started quickly with\n    BookKeeper. It is aimed primarily at developers willing to try it out, and\n    contains simple installation instructions for a simple BookKeeper installation\n    and a simple programming example. For further programming detail, please refer to \n    <a href=\"bookkeeperProgrammer.html\">BookKeeper Programmer's Guide</a>.\n    </p>\n<a name=\"bk_Prerequisites\"></a>\n<h3 class=\"h4\">Pre-requisites</h3>\n<p>See <a href=\"bookkeeperConfig.html#bk_sysReq\">\n    \t      System Requirements</a> in the Admin guide.</p>\n<a name=\"bk_Download\"></a>\n<h3 class=\"h4\">Download</h3>\n<p> BookKeeper is distributed along with ZooKeeper. To get a ZooKeeper distribution, \n\t\t\t   download a recent\n    \t    <a href=\"http://zookeeper.apache.org/releases.html\">\n        \t  stable</a> release from one of the Apache Download\n       \t Mirrors.</p>\n<a name=\"bk_localBK\"></a>\n<h3 class=\"h4\">LocalBookKeeper</h3>\n<p> Under org.apache.bookkeeper.util, you'll find a java program\n\t\tcalled LocalBookKeeper.java that sets you up to run BookKeeper on a \n\t\tsingle machine. This is far from ideal from a performance perspective,\n\t\tbut the program is useful for both test and educational purposes.\n\t\t</p>\n<a name=\"bk_setupBookies\"></a>\n<h3 class=\"h4\">Setting up bookies</h3>\n<p> If you're bold and you want more than just running things locally, then\n\t\tyou'll need to run bookies in different servers. You'll need at least three bookies\n\t\tto start with.  \n\t\t</p>\n<p>\n\t\tFor each bookie, we need to execute a command like the following:\n\t\t</p>\n<p>\n<span class=\"codefrag computeroutput\">\n\t\tjava -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\\\n\t\t:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\\ \n\t\torg.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\\\n\t\t/path_to_ledger_device/\n\t\t</span>\n</p>\n<p> \"/path_to_log_device/\" and \"/path_to_ledger_device/\" are different paths. Also, port 3181\n\t\tis the port that a bookie listens on for connection requests from clients. 127.0.0.1:2181 is the hostname:port \n\t\tfor the ZooKeeper server. In this example, the standalone ZooKeeper server is running locally on port 2181.\n\t\tIf we had multiple ZooKeeper servers, this parameter would be a comma separated list of all the hostname:port\n\t\tvalues corresponding to them.\n\t\t</p>\n<a name=\"bk_setupZK\"></a>\n<h3 class=\"h4\">Setting up ZooKeeper</h3>\n<p> ZooKeeper stores metadata on behalf of BookKeeper clients and bookies. To get a minimal \n\t  \tZooKeeper installation to work with BookKeeper, we can set up one server running in\n\t  \tstandalone mode. Once we have the server running, we need to create a few znodes:\n\t  \t</p>\n<ol>\n\t  \t\n<li>\n\t  \t\n<p>\n<span class=\"codefrag computeroutput\">\n\t  \t/ledgers\t\n\t  \t</span>\n</p>\n\t  \t\n</li>\n\t  \t\n\t  \t\n<li>\n\t  \t\n<p>\n<span class=\"codefrag computeroutput\">\n\t  \t/ledgers/available\n\t  \t</span>\n</p>\n\t  \t\n</li>\n\t  \t\n\t  \t\n<li>\n\t  \t\n<p> For each bookie, we add one znode such that the name of the znode is the\n\t  \tconcatenation of the machine name and the port number that the bookie is \n\t  \tlistening on. For example, if a bookie is running on bookie.foo.com an is listening \n\t  \ton port 3181, we add a znode \n\t  \t<span class=\"codefrag computeroutput\">/ledgers/available/bookie.foo.com:3181</span>.  \n\t  \t</p>\n\t  \t\n</li>\n\t  \t\n</ol>\n<a name=\"bk_example\"></a>\n<h3 class=\"h4\">Example</h3>\n<p>\n\t    In the following excerpt of code, we:\n\t    </p>\n<ol>\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tCreate a ledger;\n\t    \t</p>\n\t    \t\n</li>\n\t    \t\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tWrite to the ledger;\n\t    \t</p>\n\t    \t\n</li>\n\t    \t\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tClose the ledger;\n\t    \t</p>\n\t    \t\n</li>\n\t    \t\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tOpen the same ledger for reading;\n\t    \t</p>\n\t    \t\n</li>\n\t    \t\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tRead from the ledger;\n\t    \t</p>\n\t    \t\n</li>\n\t    \t\n\t    \t\n<li>\n\t    \t\n<p>\n\t    \tClose the ledger again;\n\t    \t</p>\n\t    \t\n</li>\n\t    \n</ol>\n<pre class=\"code\">\nLedgerHandle lh = bkc.createLedger(ledgerPassword);\nledgerId = lh.getId();\nByteBuffer entry = ByteBuffer.allocate(4);\n\nfor(int i = 0; i &lt; 10; i++){\n\tentry.putInt(i);\n\tentry.position(0);\n\tentries.add(entry.array());\t\t\t\t\n\tlh.addEntry(entry.array());\n}\nlh.close();\nlh = bkc.openLedger(ledgerId, ledgerPassword);\t\t\n\t\t\t\nEnumeration&lt;LedgerEntry&gt; ls = lh.readEntries(0, 9);\nint i = 0;\nwhile(ls.hasMoreElements()){\n\tByteBuffer origbb = ByteBuffer.wrap(\n\t\t\t\tentries.get(i++));\n\tInteger origEntry = origbb.getInt();\n\tByteBuffer result = ByteBuffer.wrap(\n\t\t\t\tls.nextElement().getEntry());\n\n\tInteger retrEntry = result.getInt();\n}\nlh.close();\n\t    </pre>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/bookkeeperStream.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>Streaming with BookKeeper</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"bookkeeperStream.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>Streaming with BookKeeper</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#bk_StreamSummary\">Summary</a>\n</li>\n<li>\n<a href=\"#bk_LedgerOutputStream\">Writing a stream of bytes</a>\n</li>\n<li>\n<a href=\"#bk_LedgerInputStream\">Reading a stream of bytes</a>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\t\n<a name=\"bk_StreamSummary\"></a>\n<h2 class=\"h3\">Summary</h2>\n<div class=\"section\">\n<p>\n    When using the BookKeeper API, an application has to split the data to write into entries, each\n    entry being a byte array. This is natural for many applications. For example, when using BookKeeper\n    for write-ahead logging, an application typically wants to write the modifications corresponding\n    to a command or a transaction. Some other applications, however, might not have a natural boundary\n    for entries, and may prefer to write and read streams of bytes. This is exactly the purpose of the\n    stream API we have implemented on top of BookKeeper.\n    </p>\n<p>\n    The stream API is implemented in the package <span class=\"codefrag computeroutput\">Streaming</span>, and it contains two main classes: <span class=\"codefrag computeroutput\">LedgerOutputStream</span> and \n    <span class=\"codefrag computeroutput\">LedgerInputStream</span>. The class names are indicative of what they do.\n    </p>\n</div>\n    \n    \n<a name=\"bk_LedgerOutputStream\"></a>\n<h2 class=\"h3\">Writing a stream of bytes</h2>\n<div class=\"section\">\n<p>\n    Class <span class=\"codefrag computeroutput\">LedgerOutputStream</span> implements two constructors and five public methods:\n    </p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic LedgerOutputStream(LedgerHandle lh) \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">lh</span> is a ledger handle for a previously created and open ledger.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic LedgerOutputStream(LedgerHandle lh, int size) \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">lh</span> is a ledger handle for a previously created and open ledger.  \n    \t</p>\n    \t\n</li>\n\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">size</span> is the size of the byte buffer to store written bytes before flushing.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n   \t\n<strong>Closing a stream.</strong> This call closes the stream by flushing the write buffer.\n   \t</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void close() \n    </span>\n\t\n</p>\n<p>\n    which has no parameters.\n    </p>\n<p>\n   \t\n<strong>Flushing a stream.</strong> This call essentially flushes the write buffer.\n   \t</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized void flush() \n    </span>\n\t\n</p>\n<p>\n    which has no parameters.\n    </p>\n<p>\n   \t\n<strong>Writing bytes.</strong> There are three calls for writing bytes to a stream.\n   \t</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized void write(byte[] b) \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">b</span> is an array of bytes to write.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized void write(byte[] b, int off, int len) \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">b</span> is an array of bytes to write.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">off</span> is a buffer offset.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">len</span> is the length to write.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized void write(int b) \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">b</span> contains a byte to write. The method writes the least significant byte of the integer four bytes.    \n    \t</p>\n    \t\n</li>\n    \n</ul>\n</div>\n    \n    \n<a name=\"bk_LedgerInputStream\"></a>\n<h2 class=\"h3\">Reading a stream of bytes</h2>\n<div class=\"section\">\n<p>\n    Class <span class=\"codefrag computeroutput\">LedgerOutputStream</span> implements two constructors and four public methods:\n    </p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic LedgerInputStream(LedgerHandle lh)\n\tthrows BKException, InterruptedException \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">lh</span> is a ledger handle for a previously created and open ledger.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic LedgerInputStream(LedgerHandle lh, int size) \n    throws BKException, InterruptedException\n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">lh</span> is a ledger handle for a previously created and open ledger.  \n    \t</p>\n    \t\n</li>\n\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">size</span> is the size of the byte buffer to store bytes that the application\n        will eventually read.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n   \t\n<strong>Closing.</strong> There is one call to close an input stream, but the call\n   \tis currently empty and the application is responsible for closing the ledger handle. \n   \t</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic void close()\n    </span>\n\t\n</p>\n<p>\n    which has no parameters.\n    </p>\n<p>\n   \t\n<strong>Reading.</strong> There are three calls to read from the stream.\n   \t</p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized int read()\n\tthrows IOException \n    </span>\n\t\n</p>\n<p>\n    which has no parameters.\n    </p>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized int read(byte[] b)\n\tthrows IOException \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">b</span> is a byte array to write to.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n<p>\n    \n<span class=\"codefrag computeroutput\">\n\tpublic synchronized int read(byte[] b, int off, int len)\n\tthrows IOException \n    </span>\n\t\n</p>\n<p>\n    where:\n    </p>\n<ul>\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">b</span> is a byte array to write to.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">off</span> is an offset for byte array <span class=\"codefrag computeroutput\">b</span>.  \n    \t</p>\n    \t\n</li>\n    \t\n    \t\n<li>\n    \t\n<p> \n        \n<span class=\"codefrag computeroutput\">len</span> is the length in bytes to write to <span class=\"codefrag computeroutput\">b</span>.  \n    \t</p>\n    \t\n</li>\n    \n</ul>\n</div>\n  \n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/broken-links.xml",
    "content": "<broken-links>\n</broken-links>\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper: Because Coordinating Distributed Systems is a Zoo</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_selected_1.1', 'skin/')\" id=\"menu_selected_1.1Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Overview</div>\n<div id=\"menu_selected_1.1\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Welcome</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\">\n<hr>\n<a href=\"http://forrest.apache.org/\"><img border=\"0\" title=\"Built with Apache Forrest\" alt=\"Built with Apache Forrest - logo\" src=\"images/built-with-forrest-button.png\" style=\"width: 88px;height: 31px;\"></a>\n</div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"index.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper: Because Coordinating Distributed Systems is a Zoo</h1>\n<div id=\"front-matter\"></div>\n    \n<p>ZooKeeper is a high-performance coordination service for\n      distributed applications.  It exposes common services - such as\n      naming, configuration management, synchronization, and group\n      services - in a simple interface so you don't have to write them\n      from scratch.  You can use it off-the-shelf to implement\n      consensus, group management, leader election, and presence\n      protocols. And you can build on it for your own, specific needs.\n    </p>\n\n    \n<p>\n      The following documents describe concepts and procedures to get\n      you started using ZooKeeper. If you have more questions, please\n      ask the <a href=\"http://zookeeper.apache.org/mailing_lists.html\">mailing list</a> or browse the\n      archives.\n    </p>\n    \n<ul>\n\n      \n<li>\n<strong>ZooKeeper Overview</strong>\n<p>Technical Overview Documents for Client Developers, Adminstrators, and Contributors</p>\n      \n<ul>\n<li>\n<a href=\"zookeeperOver.html\">Overview</a> - a bird's eye view of ZooKeeper, including design concepts and architecture</li>\n      \n<li>\n<a href=\"zookeeperStarted.html\">Getting Started</a> - a tutorial-style guide for developers to install, run, and program to ZooKeeper</li>\n      \n<li>\n<a href=\"releasenotes.html\">Release Notes</a> - new developer and user facing features, improvements, and incompatibilities</li>\n      \n</ul>\n      \n</li>\n      \n      \n<li>\n<strong>Developers</strong>\n<p> Documents for Developers using the ZooKeeper Client API</p>\n      \n<ul>\n            \n<li>\n<a href=\"api/index.html\">API Docs</a> - the technical reference to ZooKeeper Client APIs</li>\n      \n<li>\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a> - a client application developer's guide to ZooKeeper</li>\n      \n<li>\n<a href=\"javaExample.html\">ZooKeeper Java Example</a> - a simple Zookeeper client appplication, written in Java</li>\n      \n<li>\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a> - sample implementations of barriers and queues</li>  \n      \n<li>\n<a href=\"recipes.html\">ZooKeeper Recipes</a> - higher level solutions to common problems in distributed applications</li>\n      \n</ul>\n      \n</li>\n      \n      \n<li>\n<strong>Administrators &amp; Operators</strong> \n<p> Documents for Administrators and Operations Engineers of ZooKeeper Deployments</p>\n      \n<ul>\n      \n<li>\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy ZooKeeper</li>\n      \n<li>\n<a href=\"zookeeperQuotas.html\">Quota Guide</a> - a guide for system administrators on Quotas in ZooKeeper. </li>\n      \n<li>\n<a href=\"zookeeperJMX.html\">JMX</a> - how to enable JMX in ZooKeeper</li>\n      \n<li>\n<a href=\"zookeeperHierarchicalQuorums.html\">Hierarchical quorums</a>\n</li>\n      \n<li>\n<a href=\"zookeeperObservers.html\">Observers</a> - non-voting ensemble members that easily improve ZooKeeper's scalability</li>\n      \n</ul>\n      \n</li>\n      \n      \n<li>\n<strong>Contributors</strong>\n<p> Documents for Developers Contributing to the ZooKeeper Open Source Project</p>\n      \n<ul>\n      \n<li>\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a> - assorted topics on the inner workings of ZooKeeper</li>\n      \n</ul>\n      \n</li>\n      \n      \n<li>\n<strong>Miscellaneous ZooKeeper Documentation</strong>\n      \n<ul>\n      \n<li>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</li>\n      \n<li>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</li>    \n      \n</ul>\n      \n</li>\n\n\t  \n<li>\n<strong>BookKeeper Documentation</strong>\n\t  \n<p> BookKeeper is a highly-available system that implements high-performance write-ahead logging. It uses ZooKeeper for metadata, \n\t  which is the main reason for being a ZooKeeper contrib.\n\t  </p>\n      \n<ul>\n      \n<li>\n<a href=\"bookkeeperOverview.html\">henn, what's it again?</a>\n</li>\n\t  \n<li>\n<a href=\"bookkeeperStarted.html\">Ok, now how do I try it out</a>\n</li>\n\t  \n<li>\n<a href=\"bookkeeperProgrammer.html\">Awesome, but how do I integrate it with my app?</a>\n</li>\n      \n<li>\n<a href=\"bookkeeperStream.html\">Can I stream bytes instead of entries?</a>\n</li>\n      \n</ul>\n      \n</li>\n    \n</ul>\n  \n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<div id=\"logos\"></div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/javaExample.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Java Example</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.2', 'skin/')\" id=\"menu_selected_1.2Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Developer</div>\n<div id=\"menu_selected_1.2\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Java Example</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"javaExample.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Java Example</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_Introduction\">A Simple Watch Client</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_requirements\">Requirements</a>\n</li>\n<li>\n<a href=\"#sc_design\">Program Design</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_executor\">The Executor Class</a>\n</li>\n<li>\n<a href=\"#sc_DataMonitor\">The DataMonitor Class</a>\n</li>\n<li>\n<a href=\"#sc_completeSourceCode\">Complete Source Listings</a>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_Introduction\"></a>\n<h2 class=\"h3\">A Simple Watch Client</h2>\n<div class=\"section\">\n<p>To introduce you to the ZooKeeper Java API, we develop here a very simple \n    watch client. This ZooKeeper client watches a ZooKeeper node for changes \n    and responds to by starting or stopping a program.</p>\n<a name=\"sc_requirements\"></a>\n<h3 class=\"h4\">Requirements</h3>\n<p>The client has four requirements:</p>\n<ul>\n<li>\n<p>It takes as parameters:</p>\n    \t\n<ul>\n\t\t\n<li>\n<p>the address of the ZooKeeper service</p>\n</li>\n\t\t\n<li> \n<p>then name of a znode - the one to be watched</p>\n</li>\n\t\t\n<li>\n<p>an executable with arguments.</p>\n</li>\n</ul>\n</li>\n\t\n<li>\n<p>It fetches the data associated with the znode and starts the executable.</p>\n</li>\n\t\n<li>\n<p>If the znode changes, the client refetches the contents and restarts the executable.</p>\n</li>\n\t\n<li>\n<p>If the znode disappears, the client kills the executable.</p>\n</li>\n</ul>\n<a name=\"sc_design\"></a>\n<h3 class=\"h4\">Program Design</h3>\n<p>Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection, \n   and the other which monitors data.  In this application, the class called the <strong>Executor</strong> \n   maintains the ZooKeeper connection, and the class called the  <strong>DataMonitor</strong> monitors the data\n   in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.\n   It is responsible for what little user interaction there is, as well as interaction with the exectuable program you\n   pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the \n   state of the znode.</p>\n</div>\n\n   \n<a name=\"sc_executor\"></a>\n<h2 class=\"h3\">The Executor Class</h2>\n<div class=\"section\">\n<p>The Executor object is the primary container of the sample application. It contains \n    both the <strong>ZooKeeper</strong> object, <strong>DataMonitor</strong>, as described above in \n    <a href=\"#sc_design\">Program Design</a>.  </p>\n<pre class=\"code\">\n    // from the Executor class...\n    \n    public static void main(String[] args) {\n        if (args.length &lt; 4) {\n            System.err\n                    .println(\"USAGE: Executor hostPort znode filename program [args ...]\");\n            System.exit(2);\n        }\n        String hostPort = args[0];\n        String znode = args[1];\n        String filename = args[2];\n        String exec[] = new String[args.length - 3];\n        System.arraycopy(args, 3, exec, 0, exec.length);\n        try {\n            new Executor(hostPort, znode, filename, exec).run();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public Executor(String hostPort, String znode, String filename,\n            String exec[]) throws KeeperException, IOException {\n        this.filename = filename;\n        this.exec = exec;\n        zk = new ZooKeeper(hostPort, 3000, this);\n        dm = new DataMonitor(zk, znode, null, this);\n    }\n\n    public void run() {\n        try {\n            synchronized (this) {\n                while (!dm.dead) {\n                    wait();\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n</pre>\n<p>\n    Recall that the Executor's job is to start and stop the executable whose name you pass in on the command line. \n    It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes\n    a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself\n    as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these\n    interfaces:\n    </p>\n<pre class=\"code\">\npublic class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener {\n...</pre>\n<p>The <strong>Watcher</strong> interface is defined by the ZooKeeper Java API.\n    ZooKeeper uses it to communicate back to its container. It supports only one method, <span class=\"codefrag command\">process()</span>, and ZooKeeper uses \n    it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor \n    in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate\n    the point that, by convention, the Executor or some Executor-like object \"owns\" the ZooKeeper connection, but it is free to delegate the events to other\n    events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)</p>\n<pre class=\"code\">\n    public void process(WatchedEvent event) {\n        dm.process(event);\n    }\n</pre>\n<p>The <strong>DataMonitorListener</strong> \n    interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface, \n    designed for this sample application. The DataMonitor object uses it to communicate back to its container, which\n    is also the the Executor object.The DataMonitorListener interface looks like this:</p>\n<pre class=\"code\">\npublic interface DataMonitorListener {\n    /**\n    * The existence status of the node has changed.\n    */\n    void exists(byte data[]);\n\n    /**\n    * The ZooKeeper session is no longer valid.\n    * \n    * @param rc\n    * the ZooKeeper reason code\n    */\n    void closing(int rc);\n}\n</pre>\n<p>This interface is defined in the DataMonitor class and implemented in the Executor class. \n    When <span class=\"codefrag command\">Executor.exists()</span> is invoked,\n    the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the \n    znode ceases to <em>exist</em>. </p>\n<p>When <span class=\"codefrag command\">Executor.closing()</span>\n    is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.</p>\n<p>As you might have guessed, DataMonitor is the object that invokes \n    these methods, in response to changes in ZooKeeper's state.</p>\n<p>Here are Executor's implementation of \n    <span class=\"codefrag command\">DataMonitorListener.exists()</span> and <span class=\"codefrag command\">DataMonitorListener.closing</span>:\n    </p>\n<pre class=\"code\">\npublic void exists( byte[] data ) {\n    if (data == null) {\n        if (child != null) {\n            System.out.println(\"Killing process\");\n            child.destroy();\n            try {\n                child.waitFor();\n            } catch (InterruptedException e) {\n            }\n        }\n        child = null;\n    } else {\n        if (child != null) {\n            System.out.println(\"Stopping child\");\n            child.destroy();\n            try {\n               child.waitFor();\n            } catch (InterruptedException e) {\n            e.printStackTrace();\n            }\n        }\n        try {\n            FileOutputStream fos = new FileOutputStream(filename);\n            fos.write(data);\n            fos.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            System.out.println(\"Starting child\");\n            child = Runtime.getRuntime().exec(exec);\n            new StreamWriter(child.getInputStream(), System.out);\n            new StreamWriter(child.getErrorStream(), System.err);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n\npublic void closing(int rc) {\n    synchronized (this) {\n        notifyAll();\n    }\n}\n</pre>\n</div>\n\n<a name=\"sc_DataMonitor\"></a>\n<h2 class=\"h3\">The DataMonitor Class</h2>\n<div class=\"section\">\n<p>\nThe DataMonitor class has the meat of the ZooKeeper logic. It is mostly \nasynchronous and event driven. DataMonitor kicks things off in the constructor with:</p>\n<pre class=\"code\">\npublic DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,\n        DataMonitorListener listener) {\n    this.zk = zk;\n    this.znode = znode;\n    this.chainedWatcher = chainedWatcher;\n    this.listener = listener;\n    \n    // Get things started by checking if the node exists. We are going\n    // to be completely event driven\n    <strong>zk.exists(znode, true, this, null);</strong>\n}\n</pre>\n<p>The call to <span class=\"codefrag command\">ZooKeeper.exists()</span> checks for the existence of the znode, \nsets a watch, and passes a reference to itself (<span class=\"codefrag command\">this</span>)\nas the completion callback object. In this sense, it kicks things off, since the\nreal processing happens when the watch is triggered.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n\n<p>Don't confuse the completion callback with the watch callback. The <span class=\"codefrag command\">ZooKeeper.exists()</span> \ncompletion callback, which happens to be the method <span class=\"codefrag command\">StatCallback.processResult()</span> implemented \nin the DataMonitor object, is invoked when the asynchronous <em>setting of the watch</em> operation \n(by <span class=\"codefrag command\">ZooKeeper.exists()</span>) completes on the server. </p>\n\n<p>\nThe triggering of the watch, on the other hand, sends an event to the <em>Executor</em> object, since\nthe Executor registered as the Watcher of the ZooKeeper object.</p>\n\n\n<p>As an aside, you might note that the DataMonitor could also register itself as the Watcher\nfor this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this\nexample, however, DataMonitor does not register as the Watcher.</p>\n\n</div>\n</div>\n<p>When the <span class=\"codefrag command\">ZooKeeper.exists()</span> operation completes on the server, the ZooKeeper API invokes this completion callback on \nthe client:</p>\n<pre class=\"code\">\npublic void processResult(int rc, String path, Object ctx, Stat stat) {\n    boolean exists;\n    switch (rc) {\n    case Code.Ok:\n        exists = true;\n        break;\n    case Code.NoNode:\n        exists = false;\n        break;\n    case Code.SessionExpired:\n    case Code.NoAuth:\n        dead = true;\n        listener.closing(rc);\n        return;\n    default:\n        // Retry errors\n        zk.exists(znode, true, this, null);\n        return;\n    }\n \n    byte b[] = null;\n    if (exists) {\n        try {\n            <strong>b = zk.getData(znode, false, null);</strong>\n        } catch (KeeperException e) {\n            // We don't need to worry about recovering now. The watch\n            // callbacks will kick off any exception handling\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            return;\n        }\n    }     \n    if ((b == null &amp;&amp; b != prevData)\n            || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {\n        <strong>listener.exists(b);</strong>\n        prevData = b;\n    }\n}\n</pre>\n<p>\nThe code first checks the error codes for znode existence, fatal errors, and \nrecoverable errors. If the file (or znode) exists, it gets the data from the znode, and \nthen invoke the exists() callback of Executor if the state has changed. Note, \nit doesn't have to do any Exception processing for the getData call because it \nhas watches pending for anything that could cause an error: if the node is deleted \nbefore it calls <span class=\"codefrag command\">ZooKeeper.getData()</span>, the watch event set by \nthe <span class=\"codefrag command\">ZooKeeper.exists()</span> triggers a callback; \nif there is a communication error, a connection watch event fires when \nthe connection comes back up.\n</p>\n<p>Finally, notice how DataMonitor processes watch events: </p>\n<pre class=\"code\">\n    public void process(WatchedEvent event) {\n        String path = event.getPath();\n        if (event.getType() == Event.EventType.None) {\n            // We are are being told that the state of the\n            // connection has changed\n            switch (event.getState()) {\n            case SyncConnected:\n                // In this particular example we don't need to do anything\n                // here - watches are automatically re-registered with \n                // server and any watches triggered while the client was \n                // disconnected will be delivered (in order of course)\n                break;\n            case Expired:\n                // It's all over\n                dead = true;\n                listener.closing(KeeperException.Code.SessionExpired);\n                break;\n            }\n        } else {\n            if (path != null &amp;&amp; path.equals(znode)) {\n                // Something has changed on the node, let's find out\n                zk.exists(znode, true, this, null);\n            }\n        }\n        if (chainedWatcher != null) {\n            chainedWatcher.process(event);\n        }\n    }\n</pre>\n<p>\nIf the client-side ZooKeeper libraries can re-establish the\ncommunication channel (SyncConnected event) to ZooKeeper before\nsession expiration (Expired event) all of the session's watches will\nautomatically be re-established with the server (auto-reset of watches\nis new in ZooKeeper 3.0.0). See <a href=\"zookeeperProgrammers.html#ch_zkWatches\">ZooKeeper Watches</a>\nin the programmer guide for more on this. A bit lower down in this\nfunction, when DataMonitor gets an event for a znode, it calls\n<span class=\"codefrag command\">ZooKeeper.exists()</span> to find out what has changed.\n</p>\n</div>\n\n\n<a name=\"sc_completeSourceCode\"></a>\n<h2 class=\"h3\">Complete Source Listings</h2>\n<div class=\"section\">\n<div class=\"note example\">\n<div class=\"label\">Executor.java</div>\n<div class=\"content\">\n<title>Executor.java</title>\n<pre class=\"code\">\n/**\n * A simple example program to use DataMonitor to start and\n * stop executables based on a znode. The program watches the\n * specified znode and saves the data that corresponds to the\n * znode in the filesystem. It also starts the specified program\n * with the specified arguments when the znode exists and kills\n * the program if the znode goes away.\n */\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\n\npublic class Executor\n    implements Watcher, Runnable, DataMonitor.DataMonitorListener\n{\n    String znode;\n\n    DataMonitor dm;\n\n    ZooKeeper zk;\n\n    String filename;\n\n    String exec[];\n\n    Process child;\n\n    public Executor(String hostPort, String znode, String filename,\n            String exec[]) throws KeeperException, IOException {\n        this.filename = filename;\n        this.exec = exec;\n        zk = new ZooKeeper(hostPort, 3000, this);\n        dm = new DataMonitor(zk, znode, null, this);\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        if (args.length &lt; 4) {\n            System.err\n                    .println(\"USAGE: Executor hostPort znode filename program [args ...]\");\n            System.exit(2);\n        }\n        String hostPort = args[0];\n        String znode = args[1];\n        String filename = args[2];\n        String exec[] = new String[args.length - 3];\n        System.arraycopy(args, 3, exec, 0, exec.length);\n        try {\n            new Executor(hostPort, znode, filename, exec).run();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /***************************************************************************\n     * We do process any events ourselves, we just need to forward them on.\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.proto.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        dm.process(event);\n    }\n\n    public void run() {\n        try {\n            synchronized (this) {\n                while (!dm.dead) {\n                    wait();\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n\n    public void closing(int rc) {\n        synchronized (this) {\n            notifyAll();\n        }\n    }\n\n    static class StreamWriter extends Thread {\n        OutputStream os;\n\n        InputStream is;\n\n        StreamWriter(InputStream is, OutputStream os) {\n            this.is = is;\n            this.os = os;\n            start();\n        }\n\n        public void run() {\n            byte b[] = new byte[80];\n            int rc;\n            try {\n                while ((rc = is.read(b)) &gt; 0) {\n                    os.write(b, 0, rc);\n                }\n            } catch (IOException e) {\n            }\n\n        }\n    }\n\n    public void exists(byte[] data) {\n        if (data == null) {\n            if (child != null) {\n                System.out.println(\"Killing process\");\n                child.destroy();\n                try {\n                    child.waitFor();\n                } catch (InterruptedException e) {\n                }\n            }\n            child = null;\n        } else {\n            if (child != null) {\n                System.out.println(\"Stopping child\");\n                child.destroy();\n                try {\n                    child.waitFor();\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n            try {\n                FileOutputStream fos = new FileOutputStream(filename);\n                fos.write(data);\n                fos.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            try {\n                System.out.println(\"Starting child\");\n                child = Runtime.getRuntime().exec(exec);\n                new StreamWriter(child.getInputStream(), System.out);\n                new StreamWriter(child.getErrorStream(), System.err);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}\n</pre>\n\t\n\n</div>\n</div>\n<div class=\"note example\">\n<div class=\"label\">DataMonitor.java</div>\n<div class=\"content\">\n\t\n<title>DataMonitor.java</title>\n\t\n<pre class=\"code\">\n/**\n * A simple class that monitors the data and existence of a ZooKeeper\n * node. It uses asynchronous ZooKeeper APIs.\n */\nimport java.util.Arrays;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.data.Stat;\n\npublic class DataMonitor implements Watcher, StatCallback {\n\n    ZooKeeper zk;\n\n    String znode;\n\n    Watcher chainedWatcher;\n\n    boolean dead;\n\n    DataMonitorListener listener;\n\n    byte prevData[];\n\n    public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,\n            DataMonitorListener listener) {\n        this.zk = zk;\n        this.znode = znode;\n        this.chainedWatcher = chainedWatcher;\n        this.listener = listener;\n        // Get things started by checking if the node exists. We are going\n        // to be completely event driven\n        zk.exists(znode, true, this, null);\n    }\n\n    /**\n     * Other classes use the DataMonitor by implementing this method\n     */\n    public interface DataMonitorListener {\n        /**\n         * The existence status of the node has changed.\n         */\n        void exists(byte data[]);\n\n        /**\n         * The ZooKeeper session is no longer valid.\n         *\n         * @param rc\n         *                the ZooKeeper reason code\n         */\n        void closing(int rc);\n    }\n\n    public void process(WatchedEvent event) {\n        String path = event.getPath();\n        if (event.getType() == Event.EventType.None) {\n            // We are are being told that the state of the\n            // connection has changed\n            switch (event.getState()) {\n            case SyncConnected:\n                // In this particular example we don't need to do anything\n                // here - watches are automatically re-registered with \n                // server and any watches triggered while the client was \n                // disconnected will be delivered (in order of course)\n                break;\n            case Expired:\n                // It's all over\n                dead = true;\n                listener.closing(KeeperException.Code.SessionExpired);\n                break;\n            }\n        } else {\n            if (path != null &amp;&amp; path.equals(znode)) {\n                // Something has changed on the node, let's find out\n                zk.exists(znode, true, this, null);\n            }\n        }\n        if (chainedWatcher != null) {\n            chainedWatcher.process(event);\n        }\n    }\n\n    public void processResult(int rc, String path, Object ctx, Stat stat) {\n        boolean exists;\n        switch (rc) {\n        case Code.Ok:\n            exists = true;\n            break;\n        case Code.NoNode:\n            exists = false;\n            break;\n        case Code.SessionExpired:\n        case Code.NoAuth:\n            dead = true;\n            listener.closing(rc);\n            return;\n        default:\n            // Retry errors\n            zk.exists(znode, true, this, null);\n            return;\n        }\n\n        byte b[] = null;\n        if (exists) {\n            try {\n                b = zk.getData(znode, false, null);\n            } catch (KeeperException e) {\n                // We don't need to worry about recovering now. The watch\n                // callbacks will kick off any exception handling\n                e.printStackTrace();\n            } catch (InterruptedException e) {\n                return;\n            }\n        }\n        if ((b == null &amp;&amp; b != prevData)\n                || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {\n            listener.exists(b);\n            prevData = b;\n        }\n    }\n}\n</pre>\n\n</div>\n</div>\n</div>\n\n\n\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/linkmap.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>Site Linkmap Table of Contents</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"linkmap.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>Site Linkmap Table of Contents</h1>\n<div id=\"front-matter\"></div>\n<p>\n          This is a map of the complete site and its structure.\n        </p>\n<ul>\n<li>\n<a>ZooKeeper</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>site</em>\n</li>\n<ul>\n\n  \n<ul>\n<li>\n<a>Overview</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul> \n    \n<ul>\n<li>\n<a href=\"index.html\">Welcome</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>welcome</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"zookeeperOver.html\">Overview</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>overview</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"zookeeperStarted.html\">Getting Started</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>started</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"releasenotes.html\">Release Notes</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>relnotes</em>\n</li>\n</ul>\n  \n</ul>\n</ul>\n  \n  \n<ul>\n<li>\n<a>Developer</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul>\n    \n<ul>\n<li>\n<a href=\"api/index.html\">API Docs</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>api</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>program</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"javaExample.html\">Java Example</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>javaEx</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>barTutor</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"recipes.html\">Recipes</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>recipes</em>\n</li>\n</ul>\n  \n</ul>\n</ul>\n  \n  \n<ul>\n<li>\n<a>BookKeeper</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul>\n      \n<ul>\n<li>\n<a href=\"bookkeeperStarted.html\">Getting started</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>bkStarted</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"bookkeeperOverview.html\">Overview</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>bkOverview</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"bookkeeperConfig.html\">Setup guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>bkProgrammer</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>bkProgrammer</em>\n</li>\n</ul>\n  \n</ul>\n</ul>\n  \n  \n<ul>\n<li>\n<a>Admin &amp; Ops</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul>\n      \n<ul>\n<li>\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>admin</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>quota</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"zookeeperJMX.html\">JMX</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>jmx</em>\n</li>\n</ul>\n      \n<ul>\n<li>\n<a href=\"zookeeperObservers.html\">Observers Guide</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>observers</em>\n</li>\n</ul>\n  \n</ul>\n</ul>\n  \n  \n<ul>\n<li>\n<a>Contributor</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul>\n      \n<ul>\n<li>\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>internals</em>\n</li>\n</ul>\n  \n</ul>\n</ul>\n  \n  \n<ul>\n<li>\n<a>Miscellaneous</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>docs</em>\n</li>\n<ul>\n    \n<ul>\n<li>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>wiki</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>faq</em>\n</li>\n</ul>\n    \n<ul>\n<li>\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>lists</em>\n</li>\n</ul>\n    \n  \n</ul>\n</ul>\n  \n  \n\n  \n \n\n</ul>\n</ul>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/recipes.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Recipes and Solutions</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.2', 'skin/')\" id=\"menu_selected_1.2Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Developer</div>\n<div id=\"menu_selected_1.2\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Recipes</div>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"recipes.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Recipes and Solutions</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_recipes\">A Guide to Creating Higher-level Constructs with ZooKeeper</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_outOfTheBox\">Out of the Box Applications: Name Service, Configuration, Group\n    Membership</a>\n</li>\n<li>\n<a href=\"#sc_recipes_eventHandles\">Barriers</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_doubleBarriers\">Double Barriers</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_recipes_Queues\">Queues</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_recipes_priorityQueues\">Priority Queues</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_recipes_Locks\">Locks</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Shared+Locks\">Shared Locks</a>\n</li>\n<li>\n<a href=\"#sc_recoverableSharedLocks\">Recoverable Shared Locks</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_recipes_twoPhasedCommit\">Two-phased Commit</a>\n</li>\n<li>\n<a href=\"#sc_leaderElection\">Leader Election</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_recipes\"></a>\n<h2 class=\"h3\">A Guide to Creating Higher-level Constructs with ZooKeeper</h2>\n<div class=\"section\">\n<p>In this article, you'll find guidelines for using\n    ZooKeeper to implement higher order functions. All of them are conventions\n    implemented at the client and do not require special support from\n    ZooKeeper. Hopfully the community will capture these conventions in client-side libraries \n    to ease their use and to encourage standardization.</p>\n<p>One of the most interesting things about ZooKeeper is that even\n    though ZooKeeper uses <em>asynchronous</em> notifications, you\n    can use it to build <em>synchronous</em> consistency\n    primitives, such as queues and locks. As you will see, this is possible\n    because ZooKeeper imposes an overall order on updates, and has mechanisms\n    to expose this ordering.</p>\n<p>Note that the recipes below attempt to employ best practices. In\n    particular, they avoid polling, timers or anything else that would result\n    in a \"herd effect\", causing bursts of traffic and limiting\n    scalability.</p>\n<p>There are many useful functions that can be imagined that aren't\n    included here - revocable read-write priority locks, as just one example.\n    And some of the constructs mentioned here - locks, in particular -\n    illustrate certain points, even though you may find other constructs, such\n    as event handles or queues, a more practical means of performing the same\n    function. In general, the examples in this section are designed to\n    stimulate thought.</p>\n<a name=\"sc_outOfTheBox\"></a>\n<h3 class=\"h4\">Out of the Box Applications: Name Service, Configuration, Group\n    Membership</h3>\n<p>Name service and configuration are two of the primary applications\n    of ZooKeeper. These two functions are provided directly by the ZooKeeper\n    API.</p>\n<p>Another function directly provided by ZooKeeper is <em>group\n    membership</em>. The group is represented by a node. Members of the\n    group create ephemeral nodes under the group node. Nodes of the members\n    that fail abnormally will be removed automatically when ZooKeeper detects\n    the failure.</p>\n<a name=\"sc_recipes_eventHandles\"></a>\n<h3 class=\"h4\">Barriers</h3>\n<p>Distributed systems use <em>barriers</em>\n      to block processing of a set of nodes until a condition is met\n      at which time all the nodes are allowed to proceed. Barriers are\n      implemented in ZooKeeper by designating a barrier node. The\n      barrier is in place if the barrier node exists. Here's the\n      pseudo code:</p>\n<ol>\n      \n<li>\n        \n<p>Client calls the ZooKeeper API's <strong>exists()</strong> function on the barrier node, with\n        <em>watch</em> set to true.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>If <strong>exists()</strong> returns false, the\n        barrier is gone and the client proceeds</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Else, if <strong>exists()</strong> returns true,\n        the clients wait for a watch event from ZooKeeper for the barrier\n        node.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>When the watch event is triggered, the client reissues the\n        <strong>exists( )</strong> call, again waiting until\n        the barrier node is removed.</p>\n      \n</li>\n    \n</ol>\n<a name=\"sc_doubleBarriers\"></a>\n<h4>Double Barriers</h4>\n<p>Double barriers enable clients to synchronize the beginning and\n      the end of a computation. When enough processes have joined the barrier,\n      processes start their computation and leave the barrier once they have\n      finished. This recipe shows how to use a ZooKeeper node as a\n      barrier.</p>\n<p>The pseudo code in this recipe represents the barrier node as\n      <em>b</em>. Every client process <em>p</em>\n      registers with the barrier node on entry and unregisters when it is\n      ready to leave. A node registers with the barrier node via the <strong>Enter</strong> procedure below, it waits until\n      <em>x</em> client process register before proceeding with\n      the computation. (The <em>x</em> here is up to you to\n      determine for your system.)</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n        \n            \n<tr>\n              \n<td><strong>Enter</strong></td>\n\n              <td><strong>Leave</strong></td>\n            \n</tr>\n\n            \n<tr>\n              \n<td>\n<ol>\n                  \n<li>\n                    \n<p>Create a name <em><em>n</em> =\n                        <em>b</em>+&ldquo;/&rdquo;+<em>p</em></em>\n</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Set watch: <strong>exists(<em>b</em> + &lsquo;&lsquo;/ready&rsquo;&rsquo;,\n                        true)</strong>\n</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Create child: <strong>create(\n                        <em>n</em>, EPHEMERAL)</strong>\n</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>\n<strong>L = getChildren(b,\n                        false)</strong>\n</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>if fewer children in L than<em>\n                        x</em>, wait for watch event</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>else <strong>create(b + &lsquo;&lsquo;/ready&rsquo;&rsquo;,\n                        REGULAR)</strong>\n</p>\n                  \n</li>\n                \n</ol>\n</td>\n\n              <td>\n<ol>\n                  \n<li>\n                    \n<p>\n<strong>L = getChildren(b,\n                        false)</strong>\n</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>if no children, exit</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>if <em>p</em> is only process node in\n                      L, delete(n) and exit</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>if <em>p</em> is the lowest process\n                      node in L, wait on highest process node in L</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>else <strong>delete(<em>n</em>) </strong>if\n                      still exists and wait on lowest process node in L</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>goto 1</p>\n                  \n</li>\n                \n</ol>\n</td>\n            \n</tr>\n          \n      \n</table>\n<p>On entering, all processes watch on a ready node and\n        create an ephemeral node as a child of the barrier node. Each process\n        but the last enters the barrier and waits for the ready node to appear\n        at line 5. The process that creates the xth node, the last process, will\n        see x nodes in the list of children and create the ready node, waking up\n        the other processes. Note that waiting processes wake up only when it is\n        time to exit, so waiting is efficient.\n      </p>\n<p>On exit, you can't use a flag such as <em>ready</em>\n      because you are watching for process nodes to go away. By using\n      ephemeral nodes, processes that fail after the barrier has been entered\n      do not prevent correct processes from finishing. When processes are\n      ready to leave, they need to delete their process nodes and wait for all\n      other processes to do the same.</p>\n<p>Processes exit when there are no process nodes left as children of\n      <em>b</em>. However, as an efficiency, you can use the\n      lowest process node as the ready flag. All other processes that are\n      ready to exit watch for the lowest existing process node to go away, and\n      the owner of the lowest process watches for any other process node\n      (picking the highest for simplicity) to go away. This means that only a\n      single process wakes up on each node deletion except for the last node,\n      which wakes up everyone when it is removed.</p>\n<a name=\"sc_recipes_Queues\"></a>\n<h3 class=\"h4\">Queues</h3>\n<p>Distributed queues are a common data structure. To implement a\n    distributed queue in ZooKeeper, first designate a znode to hold the queue,\n    the queue node. The distributed clients put something into the queue by\n    calling create() with a pathname ending in \"queue-\", with the\n    <em>sequence</em> and <em>ephemeral</em> flags in\n    the create() call set to true. Because the <em>sequence</em>\n    flag is set, the new pathnames will have the form\n    _path-to-queue-node_/queue-X, where X is a monotonic increasing number. A\n    client that wants to be removed from the queue calls ZooKeeper's <strong>getChildren( )</strong> function, with\n    <em>watch</em> set to true on the queue node, and begins\n    processing nodes with the lowest number. The client does not need to issue\n    another <strong>getChildren( )</strong> until it exhausts\n    the list obtained from the first <strong>getChildren(\n    )</strong> call. If there are are no children in the queue node, the\n    reader waits for a watch notification to check the queue again.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n      \n<p>There now exists a Queue implementation in ZooKeeper\n      recipes directory. This is distributed with the release --\n      src/recipes/queue directory of the release artifact.\n      </p>\n    \n</div>\n</div>\n<a name=\"sc_recipes_priorityQueues\"></a>\n<h4>Priority Queues</h4>\n<p>To implement a priority queue, you need only make two simple\n      changes to the generic <a href=\"#sc_recipes_Queues\">queue\n      recipe</a> . First, to add to a queue, the pathname ends with\n      \"queue-YY\" where YY is the priority of the element with lower numbers\n      representing higher priority (just like UNIX). Second, when removing\n      from the queue, a client uses an up-to-date children list meaning that\n      the client will invalidate previously obtained children lists if a watch\n      notification triggers for the queue node.</p>\n<a name=\"sc_recipes_Locks\"></a>\n<h3 class=\"h4\">Locks</h3>\n<p>Fully distributed locks that are globally synchronous, meaning at\n    any snapshot in time no two clients think they hold the same lock. These\n    can be implemented using ZooKeeeper. As with priority queues, first define\n    a lock node.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n      \n<p>There now exists a Lock implementation in ZooKeeper\n      recipes directory. This is distributed with the release --\n      src/recipes/lock directory of the release artifact.\n      </p>\n    \n</div>\n</div>\n<p>Clients wishing to obtain a lock do the following:</p>\n<ol>\n      \n<li>\n        \n<p>Call <strong>create( )</strong> with a pathname\n        of \"_locknode_/lock-\" and the <em>sequence</em> and\n        <em>ephemeral</em> flags set.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Call <strong>getChildren( )</strong> on the lock\n        node <em>without</em> setting the watch flag (this is\n        important to avoid the herd effect).</p>\n      \n</li>\n\n      \n<li>\n        \n<p>If the pathname created in step <strong>1</strong> has the lowest sequence number suffix, the\n        client has the lock and the client exits the protocol.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The client calls <strong>exists( )</strong> with\n        the watch flag set on the path in the lock directory with the next\n        lowest sequence number.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>if <strong>exists( )</strong> returns false, go\n        to step <strong>2</strong>. Otherwise, wait for a\n        notification for the pathname from the previous step before going to\n        step <strong>2</strong>.</p>\n      \n</li>\n    \n</ol>\n<p>The unlock protocol is very simple: clients wishing to release a\n    lock simply delete the node they created in step 1.</p>\n<p>Here are a few things to notice:</p>\n<ul>\n      \n<li>\n        \n<p>The removal of a node will only cause one client to wake up\n        since each node is watched by exactly one client. In this way, you\n        avoid the herd effect.</p>\n      \n</li>\n    \n</ul>\n<ul>\n      \n<li>\n        \n<p>There is no polling or timeouts.</p>\n      \n</li>\n    \n</ul>\n<ul>\n      \n<li>\n        \n<p>Because of the way you implement locking, it is easy to see the\n        amount of lock contention, break locks, debug locking problems,\n        etc.</p>\n      \n</li>\n    \n</ul>\n<a name=\"Shared+Locks\"></a>\n<h4>Shared Locks</h4>\n<p>You can implement shared locks by with a few changes to the lock\n      protocol:</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n        \n            \n<tr>\n              \n<td><strong>Obtaining a read\n              lock:</strong></td>\n\n              <td><strong>Obtaining a write\n              lock:</strong></td>\n            \n</tr>\n\n            \n<tr>\n              \n<td>\n<ol>\n                  \n<li>\n                    \n<p>Call <strong>create( )</strong> to\n                    create a node with pathname\n                    \"<span class=\"codefrag filename\">_locknode_/read-</span>\". This is the\n                    lock node use later in the protocol. Make sure to set both\n                    the <em>sequence</em> and\n                    <em>ephemeral</em> flags.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Call <strong>getChildren( )</strong>\n                    on the lock node <em>without</em> setting the\n                    <em>watch</em> flag - this is important, as it\n                    avoids the herd effect.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>If there are no children with a pathname starting\n                    with \"<span class=\"codefrag filename\">write-</span>\" and having a lower\n                    sequence number than the node created in step <strong>1</strong>, the client has the lock and can\n                    exit the protocol. </p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Otherwise, call <strong>exists(\n                    )</strong>, with <em>watch</em> flag, set on\n                    the node in lock directory with pathname staring with\n                    \"<span class=\"codefrag filename\">write-</span>\" having the next lowest\n                    sequence number.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>If <strong>exists( )</strong>\n                    returns <em>false</em>, goto step <strong>2</strong>.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Otherwise, wait for a notification for the pathname\n                    from the previous step before going to step <strong>2</strong>\n</p>\n                  \n</li>\n                \n</ol>\n</td>\n\n              <td>\n<ol>\n                  \n<li>\n                    \n<p>Call <strong>create( )</strong> to\n                    create a node with pathname\n                    \"<span class=\"codefrag filename\">_locknode_/write-</span>\". This is the\n                    lock node spoken of later in the protocol. Make sure to\n                    set both <em>sequence</em> and\n                    <em>ephemeral</em> flags.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Call <strong>getChildren( )\n                    </strong> on the lock node <em>without</em>\n                    setting the <em>watch</em> flag - this is\n                    important, as it avoids the herd effect.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>If there are no children with a lower sequence\n                    number than the node created in step <strong>1</strong>, the client has the lock and the\n                    client exits the protocol.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>Call <strong>exists( ),</strong>\n                    with <em>watch</em> flag set, on the node with\n                    the pathname that has the next lowest sequence\n                    number.</p>\n                  \n</li>\n\n                  \n<li>\n                    \n<p>If <strong>exists( )</strong>\n                    returns <em>false</em>, goto step <strong>2</strong>. Otherwise, wait for a\n                    notification for the pathname from the previous step\n                    before going to step <strong>2</strong>.</p>\n                  \n</li>\n                \n</ol>\n</td>\n            \n</tr>\n          \n      \n</table>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n        \n<p>It might appear that this recipe creates a herd effect:\n          when there is a large group of clients waiting for a read\n          lock, and all getting notified more or less simultaneously\n          when the \"<span class=\"codefrag filename\">write-</span>\" node with the lowest\n          sequence number is deleted. In fact. that's valid behavior:\n          as all those waiting reader clients should be released since\n          they have the lock. The herd effect refers to releasing a\n          \"herd\" when in fact only a single or a small number of\n          machines can proceed.\n        </p>\n      \n</div>\n</div>\n<a name=\"sc_recoverableSharedLocks\"></a>\n<h4>Recoverable Shared Locks</h4>\n<p>With minor modifications to the Shared Lock protocol, you make\n      shared locks revocable by modifying the shared lock protocol:</p>\n<p>In step <strong>1</strong>, of both obtain reader\n      and writer lock protocols, call <strong>getData(\n      )</strong> with <em>watch</em> set, immediately after the\n      call to <strong>create( )</strong>. If the client\n      subsequently receives notification for the node it created in step\n      <strong>1</strong>, it does another <strong>getData( )</strong> on that node, with\n      <em>watch</em> set and looks for the string \"unlock\", which\n      signals to the client that it must release the lock. This is because,\n      according to this shared lock protocol, you can request the client with\n      the lock give up the lock by calling <strong>setData()\n      </strong> on the lock node, writing \"unlock\" to that node.</p>\n<p>Note that this protocol requires the lock holder to consent to\n      releasing the lock. Such consent is important, especially if the lock\n      holder needs to do some processing before releasing the lock. Of course\n      you can always implement <em>Revocable Shared Locks with Freaking\n      Laser Beams</em> by stipulating in your protocol that the revoker\n      is allowed to delete the lock node if after some length of time the lock\n      isn't deleted by the lock holder.</p>\n<a name=\"sc_recipes_twoPhasedCommit\"></a>\n<h3 class=\"h4\">Two-phased Commit</h3>\n<p>A two-phase commit protocol is an algorithm that lets all clients in\n    a distributed system agree either to commit a transaction or abort.</p>\n<p>In ZooKeeper, you can implement a two-phased commit by having a\n    coordinator create a transaction node, say \"/app/Tx\", and one child node\n    per participating site, say \"/app/Tx/s_i\". When coordinator creates the\n    child node, it leaves the content undefined. Once each site involved in\n    the transaction receives the transaction from the coordinator, the site\n    reads each child node and sets a watch. Each site then processes the query\n    and votes \"commit\" or \"abort\" by writing to its respective node. Once the\n    write completes, the other sites are notified, and as soon as all sites\n    have all votes, they can decide either \"abort\" or \"commit\". Note that a\n    node can decide \"abort\" earlier if some site votes for \"abort\".</p>\n<p>An interesting aspect of this implementation is that the only role\n    of the coordinator is to decide upon the group of sites, to create the\n    ZooKeeper nodes, and to propagate the transaction to the corresponding\n    sites. In fact, even propagating the transaction can be done through\n    ZooKeeper by writing it in the transaction node.</p>\n<p>There are two important drawbacks of the approach described above.\n    One is the message complexity, which is O(n&sup2;). The second is the\n    impossibility of detecting failures of sites through ephemeral nodes. To\n    detect the failure of a site using ephemeral nodes, it is necessary that\n    the site create the node.</p>\n<p>To solve the first problem, you can have only the coordinator\n    notified of changes to the transaction nodes, and then notify the sites\n    once coordinator reaches a decision. Note that this approach is scalable,\n    but it's is slower too, as it requires all communication to go through the\n    coordinator.</p>\n<p>To address the second problem, you can have the coordinator\n    propagate the transaction to the sites, and have each site creating its\n    own ephemeral node.</p>\n<a name=\"sc_leaderElection\"></a>\n<h3 class=\"h4\">Leader Election</h3>\n<p>A simple way of doing leader election with ZooKeeper is to use the\n    <strong>SEQUENCE|EPHEMERAL</strong> flags when creating\n    znodes that represent \"proposals\" of clients. The idea is to have a znode,\n    say \"/election\", such that each znode creates a child znode \"/election/n_\"\n    with both flags SEQUENCE|EPHEMERAL. With the sequence flag, ZooKeeper\n    automatically appends a sequence number that is greater that any one\n    previously appended to a child of \"/election\". The process that created\n    the znode with the smallest appended sequence number is the leader.\n    </p>\n<p>That's not all, though. It is important to watch for failures of the\n    leader, so that a new client arises as the new leader in the case the\n    current leader fails. A trivial solution is to have all application\n    processes watching upon the current smallest znode, and checking if they\n    are the new leader when the smallest znode goes away (note that the\n    smallest znode will go away if the leader fails because the node is\n    ephemeral). But this causes a herd effect: upon of failure of the current\n    leader, all other processes receive a notification, and execute\n    getChildren on \"/election\" to obtain the current list of children of\n    \"/election\". If the number of clients is large, it causes a spike on the\n    number of operations that ZooKeeper servers have to process. To avoid the\n    herd effect, it is sufficient to watch for the next znode down on the\n    sequence of znodes. If a client receives a notification that the znode it\n    is watching is gone, then it becomes the new leader in the case that there\n    is no smaller znode. Note that this avoids the herd effect by not having\n    all clients watching the same znode. </p>\n<p>Here's the pseudo code:</p>\n<p>Let ELECTION be a path of choice of the application. To volunteer to\n    be a leader: </p>\n<ol>\n      \n<li>\n        \n<p>Create znode z with path \"ELECTION/n_\" with both SEQUENCE and\n        EPHEMERAL flags;</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Let C be the children of \"ELECTION\", and i be the sequence\n        number of z;</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Watch for changes on \"ELECTION/n_j\", where j is the largest\n        sequence number such that j &lt; i and n_j is a znode in C;</p>\n      \n</li>\n    \n</ol>\n<p>Upon receiving a notification of znode deletion: </p>\n<ol>\n      \n<li>\n        \n<p>Let C be the new set of children of ELECTION; </p>\n      \n</li>\n\n      \n<li>\n        \n<p>If z is the smallest node in C, then execute leader\n        procedure;</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Otherwise, watch for changes on \"ELECTION/n_j\", where j is the\n        largest sequence number such that j &lt; i and n_j is a znode in C;\n        </p>\n      \n</li>\n    \n</ol>\n<p>Note that the znode having no preceding znode on the list of\n    children does not imply that the creator of this znode is aware that it is\n    the current leader. Applications may consider creating a separate znode\n    to acknowledge that the leader has executed the leader procedure. </p>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/releasenotes.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Release Notes</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_selected_1.1', 'skin/')\" id=\"menu_selected_1.1Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Overview</div>\n<div id=\"menu_selected_1.1\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Release Notes</div>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"releasenotes.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n        Release Notes - ZooKeeper - Version 3.4.12\n\n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2249'>ZOOKEEPER-2249</a>] -         CRC check failed when preAllocSize smaller than node data\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2690'>ZOOKEEPER-2690</a>] -         Update documentation source for ZOOKEEPER-2574\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2806'>ZOOKEEPER-2806</a>] -         Flaky test: org.apache.zookeeper.server.quorum.FLEBackwardElectionRoundTest.testBackwardElectionRound\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2845'>ZOOKEEPER-2845</a>] -         Data inconsistency issue due to retain database in leader election\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2893'>ZOOKEEPER-2893</a>] -         very poor choice of logging if client fails to connect to server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2923'>ZOOKEEPER-2923</a>] -         The comment of the variable matchSyncs in class CommitProcessor has a mistake.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2924'>ZOOKEEPER-2924</a>] -         Flaky Test: org.apache.zookeeper.test.LoadFromLogTest.testRestoreWithTransactionErrors\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2931'>ZOOKEEPER-2931</a>] -         WriteLock recipe: incorrect znode ordering when the sessionId is part of the znode name\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2936'>ZOOKEEPER-2936</a>] -         Duplicate Keys in log4j.properties config files\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2944'>ZOOKEEPER-2944</a>] -         Specify correct overflow value\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2948'>ZOOKEEPER-2948</a>] -         Failing c unit tests on apache jenkins\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2951'>ZOOKEEPER-2951</a>] -         zkServer.cmd does not start when JAVA_HOME ends with a \\\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2953'>ZOOKEEPER-2953</a>] -         Flaky Test: testNoLogBeforeLeaderEstablishment\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2960'>ZOOKEEPER-2960</a>] -         The dataDir and dataLogDir are used opposingly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2961'>ZOOKEEPER-2961</a>] -         Fix testElectionFraud Flakyness\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2978'>ZOOKEEPER-2978</a>] -         fix potential null pointer exception when deleting node\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2992'>ZOOKEEPER-2992</a>] -         The eclipse build target fails due to protocol redirection: http-&gt;https\n</li>\n</ul>\n\n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2950'>ZOOKEEPER-2950</a>] -         Add keys for the Zxid from the stat command to check_zookeeper.py\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2952'>ZOOKEEPER-2952</a>] -         Upgrade third party libraries to address vulnerabilities\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2962'>ZOOKEEPER-2962</a>] -         The function queueEmpty() in FastLeaderElection.Messenger is not used, should be removed.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2967'>ZOOKEEPER-2967</a>] -         Add check to validate dataDir and dataLogDir parameters at startup\n</li>\n</ul>\n\n<h2>        Wish\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2795'>ZOOKEEPER-2795</a>] -         Change log level for &quot;ZKShutdownHandler is not registered&quot; error message\n</li>\n</ul>\n        Release Notes - ZooKeeper - Version 3.4.11\n    \n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2707'>ZOOKEEPER-2707</a>] -         Fix &quot;Unexpected bean exists!&quot; issue in WatcherTests\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2729'>ZOOKEEPER-2729</a>] -         Cleanup findbug warnings in branch-3.4: Correctness Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2730'>ZOOKEEPER-2730</a>] -         Cleanup findbug warnings in branch-3.4: Disable Internationalization Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2731'>ZOOKEEPER-2731</a>] -         Cleanup findbug warnings in branch-3.4: Malicious code vulnerability Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2732'>ZOOKEEPER-2732</a>] -         Cleanup findbug warnings in branch-3.4: Performance Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2733'>ZOOKEEPER-2733</a>] -         Cleanup findbug warnings in branch-3.4: Dodgy code Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2749'>ZOOKEEPER-2749</a>] -         Cleanup findbug warnings in branch-3.4: Experimental Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2754'>ZOOKEEPER-2754</a>] -         Set up Apache Jenkins job that runs the flaky test analyzer script.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2762'>ZOOKEEPER-2762</a>] -         Multithreaded correctness Warnings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2834'>ZOOKEEPER-2834</a>] -         ZOOKEEPER-2355 fix for branch-3.4\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1643'>ZOOKEEPER-1643</a>] -         Windows: fetch_and_add not 64bit-compatible, may not be correct\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2349'>ZOOKEEPER-2349</a>] -         Update documentation for snapCount\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2355'>ZOOKEEPER-2355</a>] -         Ephemeral node is never deleted if follower fails while reading the proposal packet\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2614'>ZOOKEEPER-2614</a>] -         Port ZOOKEEPER-1576 to branch3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2691'>ZOOKEEPER-2691</a>] -         recreateSocketAddresses may recreate the unreachable IP address\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2722'>ZOOKEEPER-2722</a>] -         Flaky Test: org.apache.zookeeper.test.ReadOnlyModeTest.testSessionEstablishment\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2728'>ZOOKEEPER-2728</a>] -         Clean up findbug warnings in branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2740'>ZOOKEEPER-2740</a>] -         Port ZOOKEEPER-2737 to branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2743'>ZOOKEEPER-2743</a>] -         Netty connection leaks JMX connection bean upon connection close in certain race conditions.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2758'>ZOOKEEPER-2758</a>] -         Typo: transasction --&gt; transaction\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2759'>ZOOKEEPER-2759</a>] -         Flaky test: org.apache.zookeeper.server.quorum.QuorumCnxManagerTest.testNoAuthLearnerConnectToAuthRequiredServerWithHigherSid\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2774'>ZOOKEEPER-2774</a>] -         Ephemeral znode will not be removed when sesstion timeout, if the system time of ZooKeeper node changes unexpectedly.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2775'>ZOOKEEPER-2775</a>] -         ZK Client not able to connect with Xid out of order error \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2777'>ZOOKEEPER-2777</a>] -         There is a typo in zk.py which prevents from using/compiling it.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2783'>ZOOKEEPER-2783</a>] -         follower disconnects and cannot reconnect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2785'>ZOOKEEPER-2785</a>] -         Server inappropriately throttles connections under load before SASL completes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2786'>ZOOKEEPER-2786</a>] -         Flaky test: org.apache.zookeeper.test.ClientTest.testNonExistingOpCode\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2798'>ZOOKEEPER-2798</a>] -         Fix flaky test: org.apache.zookeeper.test.ReadOnlyModeTest.testConnectionEvents\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2809'>ZOOKEEPER-2809</a>] -         Unnecessary stack-trace in server when the client disconnect unexpectedly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2811'>ZOOKEEPER-2811</a>] -         PurgeTxnLog#validateAndGetFile: return tag has no arguments.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2818'>ZOOKEEPER-2818</a>] -         Improve the ZooKeeper#setACL  java doc\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2841'>ZOOKEEPER-2841</a>] -         ZooKeeper public include files leak porting changes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2859'>ZOOKEEPER-2859</a>] -         CMake build doesn&#39;t support OS X\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2861'>ZOOKEEPER-2861</a>] -         Main-Class JAR manifest attribute is incorrect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2874'>ZOOKEEPER-2874</a>] -         Windows Debug builds don&#39;t link with `/MTd`\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2890'>ZOOKEEPER-2890</a>] -         Local automatic variable is left uninitialized and then freed.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2905'>ZOOKEEPER-2905</a>] -         Don&#39;t include `config.h` in `zookeeper.h`\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2906'>ZOOKEEPER-2906</a>] -         The OWASP dependency check jar should not be included in the default classpath\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2908'>ZOOKEEPER-2908</a>] -         quorum.auth.MiniKdcTest.testKerberosLogin failing with NPE on java 9\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2909'>ZOOKEEPER-2909</a>] -         Create ant task to generate ivy dependency reports\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2914'>ZOOKEEPER-2914</a>] -         compiler warning using java 9\n</li>\n</ul>\n                                \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1669'>ZOOKEEPER-1669</a>] -         Operations to server will be timed-out while thousands of sessions expired same time\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1748'>ZOOKEEPER-1748</a>] -         TCP keepalive for leader election connections\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2788'>ZOOKEEPER-2788</a>] -         The define of MAX_CONNECTION_ATTEMPTS in QuorumCnxManager.java seems useless, should it be removed?\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2856'>ZOOKEEPER-2856</a>] -         ZooKeeperSaslClient#respondToServer should log exception message of SaslException\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2864'>ZOOKEEPER-2864</a>] -         Add script to run a java api compatibility tool\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2870'>ZOOKEEPER-2870</a>] -         Improve the efficiency of AtomicFileOutputStream\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2880'>ZOOKEEPER-2880</a>] -         Rename README.txt to README.md\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2887'>ZOOKEEPER-2887</a>] -         define dependency versions in build.xml to be easily overridden in build.properties\n</li>\n</ul>\n            \n<h2>        New Feature\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1703'>ZOOKEEPER-1703</a>] -         Please add instructions for running the tutorial\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2875'>ZOOKEEPER-2875</a>] -         Add ant task for running OWASP dependency report\n</li>\n</ul>\n                                                                \n<h2>        Test\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2686'>ZOOKEEPER-2686</a>] -         Flaky Test: org.apache.zookeeper.test.WatcherTest.\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.10\n    \n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2692'>ZOOKEEPER-2692</a>] -         Fix race condition in testWatchAutoResetWithPending\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2044'>ZOOKEEPER-2044</a>] -         CancelledKeyException in zookeeper branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2383'>ZOOKEEPER-2383</a>] -         Startup race in ZooKeeperServer\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2465'>ZOOKEEPER-2465</a>] -         Documentation copyright notice is out of date.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2467'>ZOOKEEPER-2467</a>] -         NullPointerException when redo Command is passed negative value\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2470'>ZOOKEEPER-2470</a>] -         ServerConfig#parse(String[])  ignores tickTime\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2542'>ZOOKEEPER-2542</a>] -         Update NOTICE file with Netty notice in 3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2552'>ZOOKEEPER-2552</a>] -         Revisit release note doc and remove the items which are not related to the released version\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2558'>ZOOKEEPER-2558</a>] -         Potential memory leak in recordio.c\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2573'>ZOOKEEPER-2573</a>] -         Modify Info.REVISION to adapt git repo\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2574'>ZOOKEEPER-2574</a>] -         PurgeTxnLog can inadvertently delete required txn log files\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2579'>ZOOKEEPER-2579</a>] -         ZooKeeper server should verify that dataDir and snapDir are writeable before starting\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2606'>ZOOKEEPER-2606</a>] -         SaslServerCallbackHandler#handleAuthorizeCallback() should log the exception\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2617'>ZOOKEEPER-2617</a>] -         correct a few spelling typos\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2622'>ZOOKEEPER-2622</a>] -         ZooTrace.logQuorumPacket does nothing\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2633'>ZOOKEEPER-2633</a>] -         Build failure in contrib/zkfuse with gcc 6.x\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2646'>ZOOKEEPER-2646</a>] -         Java target in branch 3.4 doesn&#39;t match documentation \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2651'>ZOOKEEPER-2651</a>] -         Missing src/pom.template in release\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2652'>ZOOKEEPER-2652</a>] -         Fix HierarchicalQuorumTest.java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2671'>ZOOKEEPER-2671</a>] -         Fix compilation error in branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2678'>ZOOKEEPER-2678</a>] -         Large databases take a long time to regain a quorum\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2680'>ZOOKEEPER-2680</a>] -         Correct DataNode.getChildren() inconsistent behaviour.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2689'>ZOOKEEPER-2689</a>] -         Fix Kerberos Authentication related test cases\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2693'>ZOOKEEPER-2693</a>] -         DOS attack on wchp/wchc four letter words (4lw)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2696'>ZOOKEEPER-2696</a>] -         Eclipse ant task no longer determines correct classpath for tests after ZOOKEEPER-2689\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2706'>ZOOKEEPER-2706</a>] -         checkstyle broken on branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2710'>ZOOKEEPER-2710</a>] -         Regenerate documentation for branch-3.4 release\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2712'>ZOOKEEPER-2712</a>] -         MiniKdc test case intermittently failing due to principal not found in Kerberos database\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2726'>ZOOKEEPER-2726</a>] -         Patch for ZOOKEEPER-2693 introduces potential race condition\n</li>\n</ul>\n                    \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2479'>ZOOKEEPER-2479</a>] -         Add &#39;electionTimeTaken&#39; value in LeaderMXBean and FollowerMXBean\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2507'>ZOOKEEPER-2507</a>] -         C unit test improvement: line break between &#39;ZooKeeper server started&#39; and &#39;Running&#39;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2557'>ZOOKEEPER-2557</a>] -         Update gitignore to account for other file extensions\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2594'>ZOOKEEPER-2594</a>] -         Use TLS for downloading artifacts during build\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2620'>ZOOKEEPER-2620</a>] -         Add comments to testReadOnlySnapshotDir and testReadOnlyTxnLogDir indicating that the tests will fail when run as root\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2672'>ZOOKEEPER-2672</a>] -         Remove CHANGE.txt\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2682'>ZOOKEEPER-2682</a>] -         Make it optional to fail build on test failure\n</li>\n</ul>\n                \n<h2>        New Feature\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1045'>ZOOKEEPER-1045</a>] -         Support Quorum Peer mutual authentication via SASL\n</li>\n</ul>\n                                                                    \n<h2>        Test\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2502'>ZOOKEEPER-2502</a>] -         Flaky Test: org.apache.zookeeper.server.quorum.CnxManagerTest.testCnxFromFutureVersion\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2650'>ZOOKEEPER-2650</a>] -         Test Improvement by adding more QuorumPeer Auth related test cases\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2656'>ZOOKEEPER-2656</a>] -         Fix ServerConfigTest#testValidArguments test case failures\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2664'>ZOOKEEPER-2664</a>] -         ClientPortBindTest#testBindByAddress may fail due to &quot;No such device&quot; exception\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2665'>ZOOKEEPER-2665</a>] -         Port QA github pull request build to branch 3.4 and 3.5\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2716'>ZOOKEEPER-2716</a>] -         Flaky Test: org.apache.zookeeper.server.SessionTrackerTest.testAddSessionAfterSessionExpiry\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.9\n    \n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2396'>ZOOKEEPER-2396</a>] -         Login object in ZooKeeperSaslClient is static\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1676'>ZOOKEEPER-1676</a>] -         C client zookeeper_interest returning ZOK on Connection Loss\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2133'>ZOOKEEPER-2133</a>] -         zkperl: Segmentation fault if getting a node with null value\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2141'>ZOOKEEPER-2141</a>] -         ACL cache in DataTree never removes entries\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2195'>ZOOKEEPER-2195</a>] -         fsync.warningthresholdms in zoo.cfg not working\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2243'>ZOOKEEPER-2243</a>] -         Supported platforms is completely out of date\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2247'>ZOOKEEPER-2247</a>] -         Zookeeper service becomes unavailable when leader fails to write transaction log\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2283'>ZOOKEEPER-2283</a>] -         traceFile property is not used in the ZooKeeper,  it should be removed from documentation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2294'>ZOOKEEPER-2294</a>] -         Ant target generate-clover-reports is broken\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2375'>ZOOKEEPER-2375</a>] -         Prevent multiple initialization of login object in each ZooKeeperSaslClient instance\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2379'>ZOOKEEPER-2379</a>] -         recent commit broke findbugs qabot check\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2385'>ZOOKEEPER-2385</a>] -         Zookeeper trunk build is failing on windows\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2405'>ZOOKEEPER-2405</a>] -         getTGT() in Login.java mishandles confidential information\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2450'>ZOOKEEPER-2450</a>] -         Upgrade Netty version due to security vulnerability (CVE-2014-3488)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2452'>ZOOKEEPER-2452</a>] -         Back-port ZOOKEEPER-1460 to 3.4 for IPv6 literal address support.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2477'>ZOOKEEPER-2477</a>] -         documentation should refer to Java cli shell and not C cli shell\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2498'>ZOOKEEPER-2498</a>] -         Potential resource leak in C client when processing unexpected / out of order response\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2240'>ZOOKEEPER-2240</a>] -         Make the three-node minimum more explicit in documentation and on website\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2373'>ZOOKEEPER-2373</a>] -         Licenses section missing from pom file\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2378'>ZOOKEEPER-2378</a>] -         upgrade ivy to recent version\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2514'>ZOOKEEPER-2514</a>] -         Simplify releasenotes creation for 3.4 branch - consistent with newer branches.\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.8\n                                \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1929'>ZOOKEEPER-1929</a>] -         std::length_error on update children\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2211'>ZOOKEEPER-2211</a>] -         PurgeTxnLog does not correctly purge when snapshots and logs are at different locations\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2229'>ZOOKEEPER-2229</a>] -         Several four-letter words are undocumented.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2281'>ZOOKEEPER-2281</a>] -         ZK Server startup fails if there are spaces in the JAVA_HOME path\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2295'>ZOOKEEPER-2295</a>] -         TGT refresh time logic is wrong\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2311'>ZOOKEEPER-2311</a>] -         assert in setup_random\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2337'>ZOOKEEPER-2337</a>] -         Fake &quot;invalid&quot; hostnames used in tests are sometimes valid\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2340'>ZOOKEEPER-2340</a>] -         JMX is disabled even if JMXDISABLE is false\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2347'>ZOOKEEPER-2347</a>] -         Deadlock shutting down zookeeper\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2360'>ZOOKEEPER-2360</a>] -         Update commons collections version used by tests/releaseaudit\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2412'>ZOOKEEPER-2412</a>] -         leader zk out of memory,  and leader db lastZxid is not update when process set data. \n</li>\n</ul>\n                        \n        Release Notes - ZooKeeper - Version 3.4.7\n    \n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1866'>ZOOKEEPER-1866</a>] -         ClientBase#createClient is failing frequently\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1868'>ZOOKEEPER-1868</a>] -         Server not coming back up in QuorumZxidSyncTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1872'>ZOOKEEPER-1872</a>] -         QuorumPeer is not shutdown in few cases\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1904'>ZOOKEEPER-1904</a>] -         WatcherTest#testWatchAutoResetWithPending is failing\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1905'>ZOOKEEPER-1905</a>] -         ZKClients are hitting KeeperException$ConnectionLossException due to wrong usage pattern\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2047'>ZOOKEEPER-2047</a>] -         testTruncationNullLog fails on windows\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2237'>ZOOKEEPER-2237</a>] -         Port async multi to 3.4 branch\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-602'>ZOOKEEPER-602</a>] -         log all exceptions not caught by ZK threads\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-706'>ZOOKEEPER-706</a>] -         large numbers of watches can cause session re-establishment to fail\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1002'>ZOOKEEPER-1002</a>] -         The Barrier sample code should create a EPHEMERAL znode instead of EPHEMERAL_SEQUENTIAL znode\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1029'>ZOOKEEPER-1029</a>] -         C client bug in zookeeper_init (if bad hostname is given)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1062'>ZOOKEEPER-1062</a>] -         Net-ZooKeeper: Net::ZooKeeper consumes 100% cpu on wait\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1077'>ZOOKEEPER-1077</a>] -         C client lib doesn&#39;t build on Solaris\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1222'>ZOOKEEPER-1222</a>] -         getACL should only call DataTree.copyStat when passed in stat is not null\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1575'>ZOOKEEPER-1575</a>] -         adding .gitattributes to prevent CRLF and LF mismatches for source and text files\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1797'>ZOOKEEPER-1797</a>] -         PurgeTxnLog may delete data logs during roll\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1803'>ZOOKEEPER-1803</a>] -         Add description for pzxid in programmer&#39;s guide.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1833'>ZOOKEEPER-1833</a>] -         fix windows build\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1853'>ZOOKEEPER-1853</a>] -         zkCli.sh can&#39;t issue a CREATE command containing spaces in the data\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1878'>ZOOKEEPER-1878</a>] -         Inconsistent behavior in autocreation of dataDir and dataLogDir\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1888'>ZOOKEEPER-1888</a>] -         ZkCli.cmd commands fail with &quot;&#39;java&#39; is not recognized as an internal or external command&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1895'>ZOOKEEPER-1895</a>] -         update all notice files, copyright, etc... with the new year - 2014\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1897'>ZOOKEEPER-1897</a>] -         ZK Shell/Cli not processing commands\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1900'>ZOOKEEPER-1900</a>] -          NullPointerException in truncate\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1901'>ZOOKEEPER-1901</a>] -         [JDK8] Sort children for comparison in AsyncOps tests\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1906'>ZOOKEEPER-1906</a>] -         zkpython: invalid data in GetData for empty node\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1911'>ZOOKEEPER-1911</a>] -         REST contrib module does not include all required files when packaged\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1913'>ZOOKEEPER-1913</a>] -         Invalid manifest files due to bogus revision property value\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1917'>ZOOKEEPER-1917</a>] -         Apache Zookeeper logs cleartext admin passwords\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1926'>ZOOKEEPER-1926</a>] -         Unit tests should only use build/test/data for data\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1927'>ZOOKEEPER-1927</a>] -         zkServer.sh fails to read dataDir (and others) from zoo.cfg on Solaris 10 (grep issue, manifests as FAILED TO WRITE PID).  \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1939'>ZOOKEEPER-1939</a>] -         ReconfigRecoveryTest.testNextConfigUnreachable is failing\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1943'>ZOOKEEPER-1943</a>] -         &quot;src/contrib/zooinspector/NOTICE.txt&quot; isn&#39;t complying to &quot;.gitattributes&quot; in branch-3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1945'>ZOOKEEPER-1945</a>] -         deb - zkCli.sh, zkServer.sh and zkEnv.sh regression caused by ZOOKEEPER-1663\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1949'>ZOOKEEPER-1949</a>] -         recipes jar not included in the distribution package\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2026'>ZOOKEEPER-2026</a>] -         Startup order in ServerCnxnFactory-ies is wrong\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2033'>ZOOKEEPER-2033</a>] -         zookeeper follower fails to start after a restart immediately following a new epoch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2039'>ZOOKEEPER-2039</a>] -         Jute compareBytes incorrect comparison index\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2049'>ZOOKEEPER-2049</a>] -         Yosemite build failure: htonll conflict\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2052'>ZOOKEEPER-2052</a>] -         Unable to delete a node when the node has no children\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2056'>ZOOKEEPER-2056</a>] -         Zookeeper 3.4.x and 3.5.0-alpha is not OSGi compliant\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2060'>ZOOKEEPER-2060</a>] -         Trace bug in NettyServerCnxnFactory\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2064'>ZOOKEEPER-2064</a>] -         Prevent resource leak in various classes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2073'>ZOOKEEPER-2073</a>] -         Memory leak on zookeeper_close\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2096'>ZOOKEEPER-2096</a>] -         C client builds with incorrect error codes in VisualStudio 2010+\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2114'>ZOOKEEPER-2114</a>] -         jute generated allocate_* functions are not externally visible\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2124'>ZOOKEEPER-2124</a>] -         Allow Zookeeper version string to have underscore &#39;_&#39;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2142'>ZOOKEEPER-2142</a>] -         JMX ObjectName is incorrect for observers\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2146'>ZOOKEEPER-2146</a>] -         BinaryInputArchive readString should check length before allocating memory\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2174'>ZOOKEEPER-2174</a>] -         JUnit4ZKTestRunner logs test failure for all exceptions even if the test method is annotated with an expected exception.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2186'>ZOOKEEPER-2186</a>] -         QuorumCnxManager#receiveConnection may crash with random input\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2201'>ZOOKEEPER-2201</a>] -         Network issues can cause cluster to hang due to near-deadlock\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2213'>ZOOKEEPER-2213</a>] -         Empty path in Set crashes server and prevents restart\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2224'>ZOOKEEPER-2224</a>] -         Four letter command hangs when network is slow\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2227'>ZOOKEEPER-2227</a>] -         stmk four-letter word fails execution at server while reading trace mask argument.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2235'>ZOOKEEPER-2235</a>] -         License update\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2239'>ZOOKEEPER-2239</a>] -         JMX State from LocalPeerBean incorrect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2245'>ZOOKEEPER-2245</a>] -         SimpleSysTest test cases fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2256'>ZOOKEEPER-2256</a>] -         Zookeeper is not using specified JMX port in zkEnv.sh\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2268'>ZOOKEEPER-2268</a>] -         Zookeeper doc creation fails on windows\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2279'>ZOOKEEPER-2279</a>] -         QuorumPeer  loadDataBase() error message is incorrect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2296'>ZOOKEEPER-2296</a>] -         compilation broken for 3.4\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-657'>ZOOKEEPER-657</a>] -         Cut down the running time of ZKDatabase corruption.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1402'>ZOOKEEPER-1402</a>] -         Upload Zookeeper package to Maven Central\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1506'>ZOOKEEPER-1506</a>] -         Re-try DNS hostname -&gt; IP resolution if node connection fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1574'>ZOOKEEPER-1574</a>] -         mismatched CR/LF endings in text files\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1746'>ZOOKEEPER-1746</a>] -         AsyncCallback.*Callback don&#39;t have any Javadoc\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1907'>ZOOKEEPER-1907</a>] -         Improve Thread handling\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1948'>ZOOKEEPER-1948</a>] -         Enable JMX remote monitoring\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2040'>ZOOKEEPER-2040</a>] -         Server to log underlying cause of SASL connection problems\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2126'>ZOOKEEPER-2126</a>] -         Improve exit log messsage of EventThread and SendThread by adding SessionId\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2179'>ZOOKEEPER-2179</a>] -         Typo in Watcher.java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2194'>ZOOKEEPER-2194</a>] -         Let DataNode.getChildren() return an unmodifiable view of its children set\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2205'>ZOOKEEPER-2205</a>] -         Log type of unexpected quorum packet in learner handler loop\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2315'>ZOOKEEPER-2315</a>] -         Change client connect zk service timeout log level from Info to Warn level\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.6\n    \n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1414'>ZOOKEEPER-1414</a>] -         QuorumPeerMainTest.testQuorum, testBadPackets are failing intermittently\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1459'>ZOOKEEPER-1459</a>] -         Standalone ZooKeeperServer is not closing the transaction log files on shutdown\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1558'>ZOOKEEPER-1558</a>] -         Leader should not snapshot uncommitted state\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1808'>ZOOKEEPER-1808</a>] -         Add version to FLE notifications for 3.4 branch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1817'>ZOOKEEPER-1817</a>] -         Fix don&#39;t care for b3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1834'>ZOOKEEPER-1834</a>] -         Catch IOException in FileTxnLog\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1837'>ZOOKEEPER-1837</a>] -         Fix JMXEnv checks (potential race conditions)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1838'>ZOOKEEPER-1838</a>] -         ZooKeeper shutdown hangs indefinitely at NioServerSocketChannelFactory.releaseExternalResources\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1841'>ZOOKEEPER-1841</a>] -         problem in QuorumTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1849'>ZOOKEEPER-1849</a>] -         Need to properly tear down tests in various cases\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1852'>ZOOKEEPER-1852</a>] -         ServerCnxnFactory instance is not properly cleanedup\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1854'>ZOOKEEPER-1854</a>] -         ClientBase ZooKeeper server clean-up\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1857'>ZOOKEEPER-1857</a>] -         PrepRequestProcessotTest doesn&#39;t shutdown ZooKeeper server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1858'>ZOOKEEPER-1858</a>] -         JMX checks - potential race conditions while stopping and starting server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1867'>ZOOKEEPER-1867</a>] -         Bug in ZkDatabaseCorruptionTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1873'>ZOOKEEPER-1873</a>] -         Unnecessarily InstanceNotFoundException is coming when unregister failed jmxbeans\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-87'>ZOOKEEPER-87</a>] -         Follower does not shut itself down if its too far behind the leader.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-732'>ZOOKEEPER-732</a>] -         Improper translation of error into Python exception\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-753'>ZOOKEEPER-753</a>] -         update log4j dependency from 1.2.15 to 1.2.16 in branch 3.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-805'>ZOOKEEPER-805</a>] -         four letter words fail with latest ubuntu nc.openbsd\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-877'>ZOOKEEPER-877</a>] -         zkpython does not work with python3.1\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-978'>ZOOKEEPER-978</a>] -         ZookeeperServer does not close zk database on shutdwon\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1057'>ZOOKEEPER-1057</a>] -         zookeeper c-client, connection to offline server fails to successfully fallback to second zk host\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1179'>ZOOKEEPER-1179</a>] -         NettyServerCnxn does not properly close socket on 4 letter word requests\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1238'>ZOOKEEPER-1238</a>] -         when the linger time was changed for NIO the patch missed Netty\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1334'>ZOOKEEPER-1334</a>] -         Zookeeper 3.4.x is not OSGi compliant - MANIFEST.MF is flawed\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1379'>ZOOKEEPER-1379</a>] -         &#39;printwatches, redo, history and connect &#39;. client commands always print usage. This is not necessary\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1382'>ZOOKEEPER-1382</a>] -         Zookeeper server holds onto dead/expired session ids in the watch data structures\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1387'>ZOOKEEPER-1387</a>] -         Wrong epoch file created\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1388'>ZOOKEEPER-1388</a>] -         Client side &#39;PathValidation&#39; is missing for the multi-transaction api.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1448'>ZOOKEEPER-1448</a>] -         Node+Quota creation in transaction log can crash leader startup\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1462'>ZOOKEEPER-1462</a>] -         Read-only server does not initialize database properly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1474'>ZOOKEEPER-1474</a>] -         Cannot build Zookeeper with IBM Java: use of Sun MXBean classes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1478'>ZOOKEEPER-1478</a>] -         Small bug in QuorumTest.testFollowersStartAfterLeader( )\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1495'>ZOOKEEPER-1495</a>] -         ZK client hangs when using a function not available on the server.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1513'>ZOOKEEPER-1513</a>] -         &quot;Unreasonable length&quot; exception while starting a server.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1535'>ZOOKEEPER-1535</a>] -         ZK Shell/Cli re-executes last command on exit\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1548'>ZOOKEEPER-1548</a>] -         Cluster fails election loop in new and interesting way\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1551'>ZOOKEEPER-1551</a>] -         Observers ignore txns that come after snapshot and UPTODATE \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1553'>ZOOKEEPER-1553</a>] -         Findbugs configuration is missing some dependencies\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1554'>ZOOKEEPER-1554</a>] -         Can&#39;t use zookeeper client without SASL\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1557'>ZOOKEEPER-1557</a>] -         jenkins jdk7 test failure in testBadSaslAuthNotifiesWatch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1562'>ZOOKEEPER-1562</a>] -         Memory leaks in zoo_multi API\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1573'>ZOOKEEPER-1573</a>] -         Unable to load database due to missing parent node\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1578'>ZOOKEEPER-1578</a>] -         org.apache.zookeeper.server.quorum.Zab1_0Test failed due to hard code with 33556 port\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1581'>ZOOKEEPER-1581</a>] -         change copyright in notice to 2012\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1596'>ZOOKEEPER-1596</a>] -         Zab1_0Test should ensure that the file is closed\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1597'>ZOOKEEPER-1597</a>] -         Windows build failing\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1599'>ZOOKEEPER-1599</a>] -         3.3 server cannot join 3.4 quorum\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1603'>ZOOKEEPER-1603</a>] -         StaticHostProviderTest testUpdateClientMigrateOrNot hangs\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1606'>ZOOKEEPER-1606</a>] -         intermittent failures in ZkDatabaseCorruptionTest on jenkins\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1610'>ZOOKEEPER-1610</a>] -         Some classes are using == or != to compare Long/String objects instead of .equals()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1613'>ZOOKEEPER-1613</a>] -         The documentation still points to 2008 in the copyright notice\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1622'>ZOOKEEPER-1622</a>] -         session ids will be negative in the year 2022\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1624'>ZOOKEEPER-1624</a>] -         PrepRequestProcessor abort multi-operation incorrectly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1629'>ZOOKEEPER-1629</a>] -         testTransactionLogCorruption occasionally fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1632'>ZOOKEEPER-1632</a>] -         fix memory leaks in cli_st \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1633'>ZOOKEEPER-1633</a>] -         Introduce a protocol version to connection initiation message\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1642'>ZOOKEEPER-1642</a>] -         Leader loading database twice\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1645'>ZOOKEEPER-1645</a>] -         ZooKeeper OSGi package imports not complete\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1646'>ZOOKEEPER-1646</a>] -         mt c client tests fail on Ubuntu Raring\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1647'>ZOOKEEPER-1647</a>] -         OSGi package import/export changes not applied to bin-jar\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1648'>ZOOKEEPER-1648</a>] -         Fix WatcherTest in JDK7\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1653'>ZOOKEEPER-1653</a>] -         zookeeper fails to start because of inconsistent epoch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1657'>ZOOKEEPER-1657</a>] -         Increased CPU usage by unnecessary SASL checks\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1663'>ZOOKEEPER-1663</a>] -         scripts don&#39;t work when path contains spaces\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1667'>ZOOKEEPER-1667</a>] -         Watch event isn&#39;t handled correctly when a client reestablish to a server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1696'>ZOOKEEPER-1696</a>] -         Fail to run zookeeper client on Weblogic application server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1697'>ZOOKEEPER-1697</a>] -         large snapshots can cause continuous quorum failure\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1702'>ZOOKEEPER-1702</a>] -         ZooKeeper client may write operation packets before receiving successful response to connection request, can cause TCP RST\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1706'>ZOOKEEPER-1706</a>] -         Typo in Double Barriers example\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1711'>ZOOKEEPER-1711</a>] -         ZooKeeper server binds to all ip addresses for leader election and broadcast\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1713'>ZOOKEEPER-1713</a>] -         wrong time calculation in zkfuse.cc\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1714'>ZOOKEEPER-1714</a>] -         perl client segfaults if ZOO_READ_ACL_UNSAFE constant is used\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1719'>ZOOKEEPER-1719</a>] -         zkCli.sh, zkServer.sh and zkEnv.sh regression caused by ZOOKEEPER-1663\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1731'>ZOOKEEPER-1731</a>] -         Unsynchronized access to ServerCnxnFactory.connectionBeans results in deadlock\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1732'>ZOOKEEPER-1732</a>] -         ZooKeeper server unable to join established ensemble\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1733'>ZOOKEEPER-1733</a>] -         FLETest#testLE is flaky on windows boxes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1744'>ZOOKEEPER-1744</a>] -         clientPortAddress breaks &quot;zkServer.sh status&quot; \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1745'>ZOOKEEPER-1745</a>] -         Wrong Import-Package in the META-INF/MANIFEST.MF of zookeeper 3.4.5 bundle\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1750'>ZOOKEEPER-1750</a>] -         Race condition producing NPE in NIOServerCnxn.toString\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1751'>ZOOKEEPER-1751</a>] -         ClientCnxn#run could miss the second ping or connection get dropped before a ping\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1753'>ZOOKEEPER-1753</a>] -         ClientCnxn is not properly releasing the resources, which are used to ping RwServer\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1754'>ZOOKEEPER-1754</a>] -         Read-only server allows to create znode\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1755'>ZOOKEEPER-1755</a>] -         Concurrent operations of four letter &#39;dump&#39; ephemeral command and killSession causing NPE\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1756'>ZOOKEEPER-1756</a>] -         zookeeper_interest() in C client can return a timeval of 0\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1764'>ZOOKEEPER-1764</a>] -         ZooKeeper attempts at SASL eventhough it shouldn&#39;t\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1765'>ZOOKEEPER-1765</a>] -         Update code conventions link on &quot;How to contribute&quot; page\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1770'>ZOOKEEPER-1770</a>] -         NullPointerException in SnapshotFormatter\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1774'>ZOOKEEPER-1774</a>] -         QuorumPeerMainTest fails consistently with &quot;complains about host&quot; assertion failure\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1775'>ZOOKEEPER-1775</a>] -         Ephemeral nodes not present in one of the members of the ensemble\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1776'>ZOOKEEPER-1776</a>] -         Ephemeral nodes not present in one of the members of the ensemble\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1781'>ZOOKEEPER-1781</a>] -         ZooKeeper Server fails if snapCount is set to 1 \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1786'>ZOOKEEPER-1786</a>] -         ZooKeeper data model documentation is incorrect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1790'>ZOOKEEPER-1790</a>] -         Deal with special ObserverId in QuorumCnxManager.receiveConnection\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1798'>ZOOKEEPER-1798</a>] -         Fix race condition in testNormalObserverRun\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1799'>ZOOKEEPER-1799</a>] -         SaslAuthFailDesignatedClientTest.testAuth fails frequently on SUSE\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1805'>ZOOKEEPER-1805</a>] -         &quot;Don&#39;t care&quot; value in ZooKeeper election breaks rolling upgrades\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1811'>ZOOKEEPER-1811</a>] -         The ZooKeeperSaslClient service name principal is hardcoded to &quot;zookeeper&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1812'>ZOOKEEPER-1812</a>] -         ZooInspector reconnection always fails if first connection fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1821'>ZOOKEEPER-1821</a>] -         very ugly warning when compiling load_gen.c\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1839'>ZOOKEEPER-1839</a>] -         Deadlock in NettyServerCnxn\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1844'>ZOOKEEPER-1844</a>] -         TruncateTest fails on windows\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1845'>ZOOKEEPER-1845</a>] -         FLETest.testLE fails on windows\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1850'>ZOOKEEPER-1850</a>] -         cppunit test testNonexistingHost in TestZookeeperInit is failing on Unbuntu\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-2015'>ZOOKEEPER-2015</a>] -         I found memory leak in zk client for c++\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1019'>ZOOKEEPER-1019</a>] -         zkfuse doesn&#39;t list dependency on boost in README\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1096'>ZOOKEEPER-1096</a>] -         Leader communication should listen on specified IP, not wildcard address\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1324'>ZOOKEEPER-1324</a>] -         Remove Duplicate NEWLEADER packets from the Leader to the Follower.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1552'>ZOOKEEPER-1552</a>] -         Enable sync request processor in Observer\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1564'>ZOOKEEPER-1564</a>] -         Allow JUnit test build with IBM Java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1583'>ZOOKEEPER-1583</a>] -         Document maxClientCnxns in conf/zoo_sample.cfg\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1584'>ZOOKEEPER-1584</a>] -         Adding mvn-install target for deploying the zookeeper artifacts to .m2 repository.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1598'>ZOOKEEPER-1598</a>] -         Ability to support more digits in the version string\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1615'>ZOOKEEPER-1615</a>] -         minor typos in ZooKeeper Programmer&#39;s Guide web page\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1627'>ZOOKEEPER-1627</a>] -         Add org.apache.zookeeper.common to exported packages in OSGi MANIFEST headers\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1666'>ZOOKEEPER-1666</a>] -         Avoid Reverse DNS lookup if the hostname in connection string is literal IP address.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1715'>ZOOKEEPER-1715</a>] -         Upgrade netty version\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1758'>ZOOKEEPER-1758</a>] -         Add documentation for zookeeper.observer.syncEnabled flag\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1771'>ZOOKEEPER-1771</a>] -         ZooInspector authentication\n</li>\n</ul>\n                                                                    \n<h2>        Task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1430'>ZOOKEEPER-1430</a>] -         add maven deploy support to the build\n</li>\n</ul>\n        \n<h2>        Test\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1980'>ZOOKEEPER-1980</a>] -         how to draw the figure&quot;ZooKeeper Throughput as the Read-Write Ratio Varies&quot; ?\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.5\n                                \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1376'>ZOOKEEPER-1376</a>] -         zkServer.sh does not correctly check for $SERVER_JVMFLAGS\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1550'>ZOOKEEPER-1550</a>] -         ZooKeeperSaslClient does not finish anonymous login on OpenJDK\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1560'>ZOOKEEPER-1560</a>] -         Zookeeper client hangs on creation of large nodes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1686'>ZOOKEEPER-1686</a>] -         Publish ZK 3.4.5 test jar\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1640'>ZOOKEEPER-1640</a>] -         dynamically load command objects in zk\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.4\n                                \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1048'>ZOOKEEPER-1048</a>] -         addauth command does not work in cli_mt/cli_st\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1163'>ZOOKEEPER-1163</a>] -         Memory leak in zk_hashtable.c:do_insert_watcher_object()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1210'>ZOOKEEPER-1210</a>] -         Can&#39;t build ZooKeeper RPM with RPM &gt;= 4.6.0 (i.e. on RHEL 6 and Fedora &gt;= 10)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1236'>ZOOKEEPER-1236</a>] -         Security uses proprietary Sun APIs\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1277'>ZOOKEEPER-1277</a>] -         servers stop serving when lower 32bits of zxid roll over\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1303'>ZOOKEEPER-1303</a>] -         Observer LearnerHandlers are not removed from Leader collection.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1307'>ZOOKEEPER-1307</a>] -         zkCli.sh is exiting when an Invalid ACL exception is thrown from setACL command through client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1318'>ZOOKEEPER-1318</a>] -         In Python binding, get_children (and get and exists, and probably others) with expired session doesn&#39;t raise exception properly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1339'>ZOOKEEPER-1339</a>] -         C clien doesn&#39;t build with --enable-debug\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1344'>ZOOKEEPER-1344</a>] -         ZooKeeper client multi-update command is not considering the Chroot request\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1354'>ZOOKEEPER-1354</a>] -         AuthTest.testBadAuthThenSendOtherCommands fails intermittently\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1361'>ZOOKEEPER-1361</a>] -         Leader.lead iterates over &#39;learners&#39; set without proper synchronisation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1380'>ZOOKEEPER-1380</a>] -         zkperl: _zk_release_watch doesn&#39;t remove items properly from the watch list\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1384'>ZOOKEEPER-1384</a>] -         test-cppunit overrides LD_LIBRARY_PATH and fails if gcc is in non-standard location\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1386'>ZOOKEEPER-1386</a>] -         avoid flaky URL redirection in &quot;ant javadoc&quot; : replace &quot;http://java.sun.com/javase/6/docs/api/&quot; with &quot;http://download.oracle.com/javase/6/docs/api/&quot; \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1395'>ZOOKEEPER-1395</a>] -         node-watcher double-free redux\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1403'>ZOOKEEPER-1403</a>] -         zkCli.sh script quoting issue\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1406'>ZOOKEEPER-1406</a>] -         dpkg init scripts don&#39;t restart - missing check_priv_sep_dir\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1412'>ZOOKEEPER-1412</a>] -         java client watches inconsistently triggered on reconnect\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1419'>ZOOKEEPER-1419</a>] -         Leader election never settles for a 5-node cluster\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1427'>ZOOKEEPER-1427</a>] -         Writing to local files is done non-atomically\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1431'>ZOOKEEPER-1431</a>] -         zkpython: async calls leak memory\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1437'>ZOOKEEPER-1437</a>] -         Client uses session before SASL authentication complete\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1463'>ZOOKEEPER-1463</a>] -         external inline function is not compatible with C99\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1465'>ZOOKEEPER-1465</a>] -         Cluster availability following new leader election takes a long time with large datasets - is correlated to dataset size\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1466'>ZOOKEEPER-1466</a>] -         QuorumCnxManager.shutdown missing synchronization\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1471'>ZOOKEEPER-1471</a>] -         Jute generates invalid C++ code\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1483'>ZOOKEEPER-1483</a>] -         Fix leader election recipe documentation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1489'>ZOOKEEPER-1489</a>] -         Data loss after truncate on transaction log\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1490'>ZOOKEEPER-1490</a>] -          If the configured log directory does not exist zookeeper will not start. Better to create the directory and start\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1493'>ZOOKEEPER-1493</a>] -         C Client: zookeeper_process doesn&#39;t invoke completion callback if zookeeper_close has been called\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1494'>ZOOKEEPER-1494</a>] -         C client: socket leak after receive timeout in zookeeper_interest()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1496'>ZOOKEEPER-1496</a>] -         Ephemeral node not getting cleared even after client has exited\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1501'>ZOOKEEPER-1501</a>] -         Nagios plugin always returns OK when it cannot connect to zookeeper\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1514'>ZOOKEEPER-1514</a>] -         FastLeaderElection - leader ignores the round information when joining a quorum\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1521'>ZOOKEEPER-1521</a>] -         LearnerHandler initLimit/syncLimit problems specifying follower socket timeout limits\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1522'>ZOOKEEPER-1522</a>] -         intermittent failures in Zab test due to NPE in recursiveDelete test function\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1536'>ZOOKEEPER-1536</a>] -         c client : memory leak in winport.c\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1686'>ZOOKEEPER-1686</a>] -         Publish ZK 3.4.5 test jar\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1321'>ZOOKEEPER-1321</a>] -         Add number of client connections metric in JMX and srvr\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1377'>ZOOKEEPER-1377</a>] -         add support for dumping a snapshot file content (similar to LogFormatter)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1389'>ZOOKEEPER-1389</a>] -         it would be nice if start-foreground used exec $JAVA in order to get rid of the intermediate shell process\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1390'>ZOOKEEPER-1390</a>] -         some expensive debug code not protected by a check for debug\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1433'>ZOOKEEPER-1433</a>] -         improve ZxidRolloverTest (test seems flakey)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1454'>ZOOKEEPER-1454</a>] -         Document how to run autoreconf if cppunit is installed in a non-standard directory\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1481'>ZOOKEEPER-1481</a>] -         allow the C cli to run exists with a watcher\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1497'>ZOOKEEPER-1497</a>] -         Allow server-side SASL login with JAAS configuration to be programmatically set (rather than only by reading JAAS configuration file)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1503'>ZOOKEEPER-1503</a>] -         remove redundant JAAS configuration code in SaslAuthTest and SaslAuthFailTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1510'>ZOOKEEPER-1510</a>] -         Should not log SASL errors for non-secure usage\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1565'>ZOOKEEPER-1565</a>] -         Allow ClientTest.java build with IBM Java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1570'>ZOOKEEPER-1570</a>] -         Allow QuorumBase.java build with IBM Java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1571'>ZOOKEEPER-1571</a>] -         Allow QuorumUtil.java build with IBM Java\n</li>\n</ul>\n                                                                    \n<h2>        Task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1450'>ZOOKEEPER-1450</a>] -         Backport ZOOKEEPER-1294 fix to 3.4 and 3.3\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.3\n                                \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-973'>ZOOKEEPER-973</a>] -         bind() could fail on Leader because it does not setReuseAddress on its ServerSocket \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1089'>ZOOKEEPER-1089</a>] -         zkServer.sh status does not work due to invalid option of nc\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1327'>ZOOKEEPER-1327</a>] -         there are still remnants of hadoop urls\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1336'>ZOOKEEPER-1336</a>] -         javadoc for multi is confusing, references functionality that doesn&#39;t seem to exist \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1338'>ZOOKEEPER-1338</a>] -         class cast exceptions may be thrown by multi ErrorResult class (invalid equals)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1340'>ZOOKEEPER-1340</a>] -         multi problem - typical user operations are generating ERROR level messages in the server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1343'>ZOOKEEPER-1343</a>] -         getEpochToPropose should check if lastAcceptedEpoch is greater or equal than epoch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1348'>ZOOKEEPER-1348</a>] -         Zookeeper 3.4.2 C client incorrectly reports string version of 3.4.1\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1351'>ZOOKEEPER-1351</a>] -         invalid test verification in MultiTransactionTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1352'>ZOOKEEPER-1352</a>] -         server.InvalidSnapshotTest is using connection timeouts that are too short\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1353'>ZOOKEEPER-1353</a>] -         C client test suite fails consistently\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1367'>ZOOKEEPER-1367</a>] -         Data inconsistencies and unexpired ephemeral nodes after cluster restart\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1370'>ZOOKEEPER-1370</a>] -         Add logging changes in Release Notes needed for clients because of ZOOKEEPER-850.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1373'>ZOOKEEPER-1373</a>] -         Hardcoded SASL login context name clashes with Hadoop security configuration override\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1374'>ZOOKEEPER-1374</a>] -         C client multi-threaded test suite fails to compile on ARM architectures.\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1322'>ZOOKEEPER-1322</a>] -         Cleanup/fix logging in Quorum code.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1345'>ZOOKEEPER-1345</a>] -         Add a .gitignore file with general exclusions and Eclipse project files excluded\n</li>\n</ul>\n                                                                            \n<h2>        Test\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1337'>ZOOKEEPER-1337</a>] -         multi&#39;s &quot;Transaction&quot; class is missing tests.\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.2\n                                \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1323'>ZOOKEEPER-1323</a>] -         c client doesn&#39;t compile on freebsd\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1333'>ZOOKEEPER-1333</a>] -         NPE in FileTxnSnapLog when restarting a cluster\n</li>\n</ul>\n\n        Release Notes - ZooKeeper - Version 3.4.1\n\n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1269'>ZOOKEEPER-1269</a>] -         Multi deserialization issues\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1305'>ZOOKEEPER-1305</a>] -         zookeeper.c:prepend_string func can dereference null ptr\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1311'>ZOOKEEPER-1311</a>] -         ZooKeeper test jar is broken\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1315'>ZOOKEEPER-1315</a>] -         zookeeper_init always reports sessionPasswd=&lt;hidden&gt;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1316'>ZOOKEEPER-1316</a>] -         zookeeper_init leaks memory if chroot is just &#39;/&#39;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1317'>ZOOKEEPER-1317</a>] -         Possible segfault in zookeeper_init\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1319'>ZOOKEEPER-1319</a>] -         Missing data after restarting+expanding a cluster\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1332'>ZOOKEEPER-1332</a>] -         Zookeeper data is not in sync with quorum in the mentioned scenario\n</li>\n</ul>\n\n\n        Release Notes - ZooKeeper - Version 3.4.0\n\n<h2>        Sub-task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-784'>ZOOKEEPER-784</a>] -         server-side functionality for read-only mode\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-798'>ZOOKEEPER-798</a>] -         Fixup loggraph for FLE changes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-839'>ZOOKEEPER-839</a>] -         deleteRecursive does not belong to the other methods\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-908'>ZOOKEEPER-908</a>] -         Remove code duplication and inconsistent naming in ClientCnxn.Packet creation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-909'>ZOOKEEPER-909</a>] -         Extract NIO specific code from ClientCnxn\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-966'>ZOOKEEPER-966</a>] -         Client side for multi\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-967'>ZOOKEEPER-967</a>] -         Server side decoding and function dispatch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-968'>ZOOKEEPER-968</a>] -         Database multi-update\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1042'>ZOOKEEPER-1042</a>] -         Generate zookeeper test jar for maven installation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1081'>ZOOKEEPER-1081</a>] -         modify leader/follower code to correctly deal with new leader\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1082'>ZOOKEEPER-1082</a>] -         modify leader election to correctly take into account current epoch\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1150'>ZOOKEEPER-1150</a>] -         fix for this patch to compile on windows...\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1160'>ZOOKEEPER-1160</a>] -         test timeouts are too small\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1201'>ZOOKEEPER-1201</a>] -         Clean SaslServerCallbackHandler.java\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1246'>ZOOKEEPER-1246</a>] -         Dead code in PrepRequestProcessor catch Exception block\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1282'>ZOOKEEPER-1282</a>] -         Learner.java not following Zab 1.0 protocol - setCurrentEpoch should be done upon receipt of NEWLEADER (before acking it) and not upon receipt of UPTODATE\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1291'>ZOOKEEPER-1291</a>] -         AcceptedEpoch not updated at leader before it proposes the epoch to followers\n</li>\n</ul>\n                            \n<h2>        Bug\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-335'>ZOOKEEPER-335</a>] -         zookeeper servers should commit the new leader txn to their logs.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-418'>ZOOKEEPER-418</a>] -         Need nifty zookeeper browser\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-603'>ZOOKEEPER-603</a>] -         zkpython should do a better job of freeing memory under error conditions\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-662'>ZOOKEEPER-662</a>] -         Too many CLOSE_WAIT socket state on a server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-690'>ZOOKEEPER-690</a>] -         AsyncTestHammer test fails on hudson.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-719'>ZOOKEEPER-719</a>] -         Add throttling to BookKeeper client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-720'>ZOOKEEPER-720</a>] -         Use zookeeper-{version}-sources.jar instead of zookeeper-{version}-src.jar to publish sources in the Maven repository\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-722'>ZOOKEEPER-722</a>] -         zkServer.sh uses sh&#39;s builtin echo on BSD, behaves incorrectly.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-731'>ZOOKEEPER-731</a>] -         Zookeeper#delete  , #create - async versions miss a verb in the javadoc \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-734'>ZOOKEEPER-734</a>] -         QuorumPeerTestBase.java and ZooKeeperServerMainTest.java do not handle windows path correctly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-735'>ZOOKEEPER-735</a>] -         cppunit test testipv6 assumes that the machine is ipv6 enabled.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-737'>ZOOKEEPER-737</a>] -         some 4 letter words may fail with netcat (nc)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-738'>ZOOKEEPER-738</a>] -         zookeeper.jute.h fails to compile with -pedantic \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-741'>ZOOKEEPER-741</a>] -         root level create on REST proxy fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-742'>ZOOKEEPER-742</a>] -         Deallocatng None on writes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-746'>ZOOKEEPER-746</a>] -         learner outputs session id to log in dec (should be hex)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-749'>ZOOKEEPER-749</a>] -         OSGi metadata not included in binary only jar\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-750'>ZOOKEEPER-750</a>] -         move maven artifacts into &quot;dist-maven&quot; subdir of the release (package target)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-758'>ZOOKEEPER-758</a>] -         zkpython segfaults on invalid acl with missing key\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-763'>ZOOKEEPER-763</a>] -         Deadlock on close w/ zkpython / c client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-764'>ZOOKEEPER-764</a>] -         Observer elected leader due to inconsistent voting view\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-766'>ZOOKEEPER-766</a>] -         forrest recipes docs don&#39;t mention the lock/queue recipe implementations available in the release\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-769'>ZOOKEEPER-769</a>] -         Leader can treat observers as quorum members\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-772'>ZOOKEEPER-772</a>] -         zkpython segfaults when watcher from async get children is invoked.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-774'>ZOOKEEPER-774</a>] -         Recipes tests are slightly outdated: they do not compile against JUnit 4.8\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-782'>ZOOKEEPER-782</a>] -         Incorrect C API documentation for Watches\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-783'>ZOOKEEPER-783</a>] -         committedLog in ZKDatabase is not properly synchronized\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-785'>ZOOKEEPER-785</a>] -          Zookeeper 3.3.1 shouldn&#39;t infinite loop if someone creates a server.0 line\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-787'>ZOOKEEPER-787</a>] -         groupId in deployed pom is wrong\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-790'>ZOOKEEPER-790</a>] -         Last processed zxid set prematurely while establishing leadership\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-792'>ZOOKEEPER-792</a>] -         zkpython memory leak\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-794'>ZOOKEEPER-794</a>] -         Callbacks are not invoked when the client is closed\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-795'>ZOOKEEPER-795</a>] -         eventThread isn&#39;t shutdown after a connection &quot;session expired&quot; event coming\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-796'>ZOOKEEPER-796</a>] -         zkServer.sh should support an external PIDFILE variable\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-800'>ZOOKEEPER-800</a>] -         zoo_add_auth returns ZOK if zookeeper handle is in ZOO_CLOSED_STATE\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-804'>ZOOKEEPER-804</a>] -         c unit tests failing due to &quot;assertion cptr failed&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-813'>ZOOKEEPER-813</a>] -         maven install is broken due to incorrect organisation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-814'>ZOOKEEPER-814</a>] -         monitoring scripts are missing apache license headers\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-820'>ZOOKEEPER-820</a>] -         update c unit tests to ensure &quot;zombie&quot; java server processes don&#39;t cause failure\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-822'>ZOOKEEPER-822</a>] -         Leader election taking a long time  to complete\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-831'>ZOOKEEPER-831</a>] -         BookKeeper: Throttling improved for reads\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-844'>ZOOKEEPER-844</a>] -         handle auth failure in java client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-846'>ZOOKEEPER-846</a>] -         zookeeper client doesn&#39;t shut down cleanly on the close call\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-854'>ZOOKEEPER-854</a>] -         BookKeeper does not compile due to changes in the ZooKeeper code\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-855'>ZOOKEEPER-855</a>] -         clientPortBindAddress should be clientPortAddress\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-861'>ZOOKEEPER-861</a>] -         Missing the test SSL certificate used for running junit tests.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-867'>ZOOKEEPER-867</a>] -         ClientTest is failing on hudson - fd cleanup\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-870'>ZOOKEEPER-870</a>] -         Zookeeper trunk build broken.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-874'>ZOOKEEPER-874</a>] -         FileTxnSnapLog.restore does not call listener\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-880'>ZOOKEEPER-880</a>] -         QuorumCnxManager$SendWorker grows without bounds\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-881'>ZOOKEEPER-881</a>] -         ZooKeeperServer.loadData loads database twice\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-882'>ZOOKEEPER-882</a>] -         Startup loads last transaction from snapshot\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-884'>ZOOKEEPER-884</a>] -         Remove LedgerSequence references from BookKeeper documentation and comments in tests \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-888'>ZOOKEEPER-888</a>] -         c-client / zkpython: Double free corruption on node watcher\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-893'>ZOOKEEPER-893</a>] -         ZooKeeper high cpu usage when invalid requests\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-897'>ZOOKEEPER-897</a>] -         C Client seg faults during close\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-898'>ZOOKEEPER-898</a>] -         C Client might not cleanup correctly during close\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-902'>ZOOKEEPER-902</a>] -         Fix findbug issue in trunk &quot;Malicious code vulnerability&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-904'>ZOOKEEPER-904</a>] -         super digest is not actually acting as a full superuser\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-907'>ZOOKEEPER-907</a>] -         Spurious &quot;KeeperErrorCode = Session moved&quot; messages\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-913'>ZOOKEEPER-913</a>] -         Version parser fails to parse &quot;3.3.2-dev&quot; from build.xml.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-919'>ZOOKEEPER-919</a>] -         Ephemeral nodes remains in one of ensemble after deliberate SIGKILL\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-921'>ZOOKEEPER-921</a>] -         zkPython incorrectly checks for existence of required ACL elements\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-937'>ZOOKEEPER-937</a>] -         test -e not available on solaris /bin/sh\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-957'>ZOOKEEPER-957</a>] -         zkCleanup.sh doesn&#39;t do anything\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-958'>ZOOKEEPER-958</a>] -         Flag to turn off autoconsume in hedwig c++ client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-961'>ZOOKEEPER-961</a>] -         Watch recovery after disconnection when connection string contains a prefix\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-962'>ZOOKEEPER-962</a>] -         leader/follower coherence issue when follower is receiving a DIFF\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-963'>ZOOKEEPER-963</a>] -         Make Forrest work with JDK6\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-975'>ZOOKEEPER-975</a>] -         new peer goes in LEADING state even if ensemble is online\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-976'>ZOOKEEPER-976</a>] -         ZooKeeper startup script doesn&#39;t use JAVA_HOME\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-981'>ZOOKEEPER-981</a>] -         Hang in zookeeper_close() in the multi-threaded C client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-983'>ZOOKEEPER-983</a>] -         running zkServer.sh start remotely using ssh hangs\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-985'>ZOOKEEPER-985</a>] -         Test BookieRecoveryTest fails on trunk.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-994'>ZOOKEEPER-994</a>] -         &quot;eclipse&quot; target in the build script doesnot include libraray required for test classes in the classpath\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1006'>ZOOKEEPER-1006</a>] -         QuorumPeer &quot;Address already in use&quot; -- regression in 3.3.3\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1007'>ZOOKEEPER-1007</a>] -         iarchive leak in C client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1013'>ZOOKEEPER-1013</a>] -         zkServer.sh usage message should mention all startup options\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1027'>ZOOKEEPER-1027</a>] -         chroot not transparent in zoo_create()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1028'>ZOOKEEPER-1028</a>] -         In python bindings, zookeeper.set2() should return a stat dict but instead returns None\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1033'>ZOOKEEPER-1033</a>] -         c client should install includes into INCDIR/zookeeper, not INCDIR/c-client-src\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1034'>ZOOKEEPER-1034</a>] -         perl bindings should automatically find the zookeeper c-client headers\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1046'>ZOOKEEPER-1046</a>] -         Creating a new sequential node results in a ZNODEEXISTS error\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1049'>ZOOKEEPER-1049</a>] -         Session expire/close flooding renders heartbeats to delay significantly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1051'>ZOOKEEPER-1051</a>] -         SIGPIPE in Zookeeper 0.3.* when send&#39;ing after cluster disconnection\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1052'>ZOOKEEPER-1052</a>] -         Findbugs warning in QuorumPeer.ResponderThread.run()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1055'>ZOOKEEPER-1055</a>] -         check for duplicate ACLs in addACL() and create()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1058'>ZOOKEEPER-1058</a>] -         fix typo in opToString for getData\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1059'>ZOOKEEPER-1059</a>] -         stat command isses on non-existing node causes NPE \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1060'>ZOOKEEPER-1060</a>] -         QuorumPeer takes a long time to shutdown\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1061'>ZOOKEEPER-1061</a>] -         Zookeeper stop fails if start called twice\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1063'>ZOOKEEPER-1063</a>] -         Dubious synchronization in Zookeeper and ClientCnxnSocketNIO classes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1068'>ZOOKEEPER-1068</a>] -         Documentation and default config suggest incorrect location for Zookeeper state\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1069'>ZOOKEEPER-1069</a>] -         Calling shutdown() on a QuorumPeer too quickly can lead to a corrupt log\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1073'>ZOOKEEPER-1073</a>] -         address a documentation issue in ZOOKEEPER-1030\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1074'>ZOOKEEPER-1074</a>] -         zkServer.sh is missing nohup/sleep, which are necessary for remote invocation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1076'>ZOOKEEPER-1076</a>] -         some quorum tests are unnecessarily extending QuorumBase\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1083'>ZOOKEEPER-1083</a>] -         Javadoc for WatchedEvent not being generated\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1086'>ZOOKEEPER-1086</a>] -         zookeeper test jar has non mavenised dependency.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1087'>ZOOKEEPER-1087</a>] -         ForceSync VM arguement not working when set to &quot;no&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1090'>ZOOKEEPER-1090</a>] -         Race condition while taking snapshot can lead to not restoring data tree correctly\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1091'>ZOOKEEPER-1091</a>] -         when the chrootPath of ClientCnxn is not null and the Watches of zooKeeper is not null and the method primeConnection(SelectionKey k) of ClientCnxn Occurred again for some reason ,then the wrong watcher clientPath is sended to server\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1097'>ZOOKEEPER-1097</a>] -         Quota is not correctly rehydrated on snapshot reload\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1101'>ZOOKEEPER-1101</a>] -         Upload zookeeper-test maven artifacts to maven repository.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1108'>ZOOKEEPER-1108</a>] -         Various bugs in zoo_add_auth in C\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1109'>ZOOKEEPER-1109</a>] -         Zookeeper service is down when SyncRequestProcessor meets any exception.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1111'>ZOOKEEPER-1111</a>] -         JMXEnv uses System.err instead of logging\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1117'>ZOOKEEPER-1117</a>] -         zookeeper 3.3.3 fails to build with gcc &gt;= 4.6.1 on Debian/Ubuntu\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1119'>ZOOKEEPER-1119</a>] -         zkServer stop command incorrectly reading comment lines in zoo.cfg\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1124'>ZOOKEEPER-1124</a>] -         Multiop submitted to non-leader always fails due to timeout\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1134'>ZOOKEEPER-1134</a>] -         ClientCnxnSocket string comparison using == rather than equals\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1136'>ZOOKEEPER-1136</a>] -         NEW_LEADER should be queued not sent to match the Zab 1.0 protocol on the twiki\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1138'>ZOOKEEPER-1138</a>] -         release audit failing for a number of new files\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1139'>ZOOKEEPER-1139</a>] -         jenkins is reporting two warnings, fix these\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1140'>ZOOKEEPER-1140</a>] -         server shutdown is not stopping threads\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1141'>ZOOKEEPER-1141</a>] -         zkpython fails tests under python 2.4\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1142'>ZOOKEEPER-1142</a>] -         incorrect stat output\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1144'>ZOOKEEPER-1144</a>] -         ZooKeeperServer not starting on leader due to a race condition\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1145'>ZOOKEEPER-1145</a>] -         ObserverTest.testObserver fails at particular point after several runs of ant junt.run -Dtestcase=ObserverTest\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1146'>ZOOKEEPER-1146</a>] -         significant regression in client (c/python) performance\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1152'>ZOOKEEPER-1152</a>] -         Exceptions thrown from handleAuthentication can cause buffer corruption issues in NIOServer\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1154'>ZOOKEEPER-1154</a>] -         Data inconsistency when the node(s) with the highest zxid is not present at the time of leader election\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1156'>ZOOKEEPER-1156</a>] -         Log truncation truncating log too much - can cause data loss\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1165'>ZOOKEEPER-1165</a>] -         better eclipse support in tests\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1168'>ZOOKEEPER-1168</a>] -         ZooKeeper fails to run with IKVM\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1171'>ZOOKEEPER-1171</a>] -         fix build for java 7\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1174'>ZOOKEEPER-1174</a>] -         FD leak when network unreachable\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1181'>ZOOKEEPER-1181</a>] -         Fix problems with Kerberos TGT renewal\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1185'>ZOOKEEPER-1185</a>] -         Send AuthFailed event to client if SASL authentication fails\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1189'>ZOOKEEPER-1189</a>] -         For an invalid snapshot file(less than 10bytes size) RandomAccessFile stream is leaking.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1190'>ZOOKEEPER-1190</a>] -         ant package is not including many of the bin scripts in the package (zkServer.sh for example)\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1192'>ZOOKEEPER-1192</a>] -         Leader.waitForEpochAck() checks waitingForNewEpoch instead of checking electionFinished\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1194'>ZOOKEEPER-1194</a>] -         Two possible race conditions during leader establishment\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1195'>ZOOKEEPER-1195</a>] -         SASL authorizedID being incorrectly set: should use getHostName() rather than getServiceName()\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1203'>ZOOKEEPER-1203</a>] -         Zookeeper systest is missing Junit Classes \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1206'>ZOOKEEPER-1206</a>] -         Sequential node creation does not use always use digits in node name given certain Locales.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1208'>ZOOKEEPER-1208</a>] -         Ephemeral node not removed after the client session is long gone\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1212'>ZOOKEEPER-1212</a>] -         zkServer.sh stop action is not conformat with LSB para 20.2 Init Script Actions\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1264'>ZOOKEEPER-1264</a>] -         FollowerResyncConcurrencyTest failing intermittently\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1268'>ZOOKEEPER-1268</a>] -         problems with read only mode, intermittent test failures and ERRORs in the log\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1270'>ZOOKEEPER-1270</a>] -         testEarlyLeaderAbandonment failing intermittently, quorum formed, no serving.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1271'>ZOOKEEPER-1271</a>] -         testEarlyLeaderAbandonment failing on solaris - clients not retrying connection\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1299'>ZOOKEEPER-1299</a>] -         Add winconfig.h file to ignore in release audit.\n</li>\n</ul>\n                        \n<h2>        Improvement\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-494'>ZOOKEEPER-494</a>] -         zookeeper should install include headers in /usr/local/include/zookeeper\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-500'>ZOOKEEPER-500</a>] -         Async methods shouldnt throw exceptions\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-631'>ZOOKEEPER-631</a>] -         zkpython&#39;s C code could do with a style clean-up\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-636'>ZOOKEEPER-636</a>] -         configure.ac has instructions which override the contents of CFLAGS and CXXFLAGS.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-724'>ZOOKEEPER-724</a>] -         Improve junit test integration - log harness information\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-733'>ZOOKEEPER-733</a>] -         use netty to handle client connections\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-765'>ZOOKEEPER-765</a>] -         Add python example script\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-773'>ZOOKEEPER-773</a>] -         Log visualisation\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-788'>ZOOKEEPER-788</a>] -         Add server id to message logs\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-789'>ZOOKEEPER-789</a>] -         Improve FLE log messages\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-797'>ZOOKEEPER-797</a>] -         c client source with AI_ADDRCONFIG cannot be compiled with early glibc\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-809'>ZOOKEEPER-809</a>] -         Improved REST Interface\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-821'>ZOOKEEPER-821</a>] -         Add ZooKeeper version information to zkpython\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-850'>ZOOKEEPER-850</a>] -         Switch from log4j to slf4j\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-853'>ZOOKEEPER-853</a>] -         Make zookeeper.is_unrecoverable return True or False and not an integer\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-862'>ZOOKEEPER-862</a>] -         Hedwig created ledgers with hardcoded Bookkeeper ensemble and quorum size.  Make these a server config parameter instead.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-864'>ZOOKEEPER-864</a>] -         Hedwig C++ client improvements\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-891'>ZOOKEEPER-891</a>] -         Allow non-numeric version strings\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-905'>ZOOKEEPER-905</a>] -         enhance zkServer.sh for easier zookeeper automation-izing\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-926'>ZOOKEEPER-926</a>] -         Fork Hadoop common&#39;s test-patch.sh and modify for Zookeeper\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-977'>ZOOKEEPER-977</a>] -         passing null for path_buffer in zoo_create\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-980'>ZOOKEEPER-980</a>] -         allow configuration parameters for log4j.properties\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-993'>ZOOKEEPER-993</a>] -         Code improvements\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-997'>ZOOKEEPER-997</a>] -         ZkClient ignores command if there are any space in front of it\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1018'>ZOOKEEPER-1018</a>] -         The connection permutation in get_addrs uses a weak and inefficient shuffle\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1025'>ZOOKEEPER-1025</a>] -         zkCli is overly sensitive to to spaces.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1030'>ZOOKEEPER-1030</a>] -         Increase default for maxClientCnxns\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1094'>ZOOKEEPER-1094</a>] -         Small improvements to LeaderElection and Vote classes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1095'>ZOOKEEPER-1095</a>] -         Simple leader election recipe\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1103'>ZOOKEEPER-1103</a>] -         In QuorumTest, use the same &quot;for ( .. try { break } catch { } )&quot; pattern in testFollowersStartAfterLeaders as in testSessionMove.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1104'>ZOOKEEPER-1104</a>] -         CLONE - In QuorumTest, use the same &quot;for ( .. try { break } catch { } )&quot; pattern in testFollowersStartAfterLeaders as in testSessionMove.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1143'>ZOOKEEPER-1143</a>] -         quorum send &amp; recv workers are missing thread names\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1153'>ZOOKEEPER-1153</a>] -         Deprecate AuthFLE and LE\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1166'>ZOOKEEPER-1166</a>] -         Please add a few svn:ignore properties\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1169'>ZOOKEEPER-1169</a>] -         Fix compiler (eclipse) warnings in (generated) jute code\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1239'>ZOOKEEPER-1239</a>] -         add logging/stats to identify fsync stalls\n</li>\n</ul>\n            \n<h2>        New Feature\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-464'>ZOOKEEPER-464</a>] -         Need procedure to garbage collect ledgers\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-465'>ZOOKEEPER-465</a>] -         Ledger size in bytes\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-712'>ZOOKEEPER-712</a>] -         Bookie recovery\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-729'>ZOOKEEPER-729</a>] -         Recursively delete a znode  - zkCli.sh rmr /node\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-744'>ZOOKEEPER-744</a>] -         Add monitoring four-letter word\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-747'>ZOOKEEPER-747</a>] -         Add C# generation to Jute\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-775'>ZOOKEEPER-775</a>] -         A large scale pub/sub system\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-799'>ZOOKEEPER-799</a>] -         Add tools and recipes for monitoring as a contrib\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-808'>ZOOKEEPER-808</a>] -         Web-based Administrative Interface\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-859'>ZOOKEEPER-859</a>] -         Native Windows version of C client\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-938'>ZOOKEEPER-938</a>] -         Support Kerberos authentication of clients.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-965'>ZOOKEEPER-965</a>] -         Need a multi-update command to allow multiple znodes to be updated safely\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-992'>ZOOKEEPER-992</a>] -         MT Native Version of Windows C Client \n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-999'>ZOOKEEPER-999</a>] -         Create an package integration project\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1012'>ZOOKEEPER-1012</a>] -         support distinct JVMFLAGS for zookeeper server in zkServer.sh and zookeeper client in zkCli.sh\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1020'>ZOOKEEPER-1020</a>] -         Implement function in C client to determine which host you&#39;re currently connected to.\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1107'>ZOOKEEPER-1107</a>] -         automating log and snapshot cleaning\n</li>\n</ul>\n                                                        \n<h2>        Task\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-754'>ZOOKEEPER-754</a>] -         numerous misspellings &quot;succesfully&quot;\n</li>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-1149'>ZOOKEEPER-1149</a>] -         users cannot migrate from 3.4-&gt;3.3-&gt;3.4 server code against a single datadir\n</li>\n</ul>\n        \n<h2>        Test\n</h2>\n<ul>\n<li>[<a href='https://issues.apache.org/jira/browse/ZOOKEEPER-239'>ZOOKEEPER-239</a>] -         ZooKeeper System Tests\n</li>\n</ul>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n         2008-2013 <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/skin/CommonMessages_de.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<catalogue>\n  <message key=\"Font size:\">Schriftgrsse:</message>\n  <message key=\"Last Published:\">Zuletzt verffentlicht:</message>\n  <message key=\"Search\">Suche:</message>\n  <message key=\"Search the site with\">Suche auf der Seite mit</message>\n</catalogue>\n"
  },
  {
    "path": "docs/skin/CommonMessages_en_US.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<catalogue>\n  <message  key=\"Font size:\">Font size:</message>\n  <message key=\"Last Published:\">Last Published:</message>\n  <message key=\"Search\">Search</message>\n  <message key=\"Search the site with\">Search site with</message>\n</catalogue>\n"
  },
  {
    "path": "docs/skin/CommonMessages_es.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<catalogue>\n  <message key=\"Font size:\">Tamao del texto:</message>\n  <message key=\"Last Published:\">Fecha de publicacin:</message>\n  <message key=\"Search\">Buscar</message>\n  <message key=\"Search the site with\">Buscar en</message>\n</catalogue>\n"
  },
  {
    "path": "docs/skin/CommonMessages_fr.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<catalogue>\n  <message key=\"Font size:\">Taille :</message>\n  <message key=\"Last Published:\">Dernire publication :</message>\n  <message key=\"Search\">Rechercher</message>\n  <message key=\"Search the site with\">Rechercher sur le site avec</message>\n</catalogue>\n"
  },
  {
    "path": "docs/skin/basic.css",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n/**\n * General\n */\n\nimg { border: 0; }\n\n#content table {\n  border: 0;\n  width: 100%;\n}\n/*Hack to get IE to render the table at 100%*/\n* html #content table { margin-left: -3px; }\n\n#content th,\n#content td {\n  margin: 0;\n  padding: 0;\n  vertical-align: top;\n}\n\n.clearboth {\n  clear: both;\n}\n\n.note, .warning, .fixme {\n  clear:right;\n  border: solid black 1px;\n  margin: 1em 3em;\n}\n\n.note .label {\n  background: #369;\n  color: white;\n  font-weight: bold;\n  padding: 5px 10px;\n}\n.note .content {\n  background: #F0F0FF;\n  color: black;\n  line-height: 120%;\n  font-size: 90%;\n  padding: 5px 10px;\n}\n.warning .label {\n  background: #C00;\n  color: white;\n  font-weight: bold;\n  padding: 5px 10px;\n}\n.warning .content {\n  background: #FFF0F0;\n  color: black;\n  line-height: 120%;\n  font-size: 90%;\n  padding: 5px 10px;\n}\n.fixme .label {\n  background: #C6C600;\n  color: black;\n  font-weight: bold;\n  padding: 5px 10px;\n}\n.fixme .content {\n  padding: 5px 10px;\n}\n\n/**\n * Typography\n */\n\nbody {\n  font-family: verdana, \"Trebuchet MS\", arial, helvetica, sans-serif;\n  font-size: 100%;\n}\n\n#content {\n  font-family: Georgia, Palatino, Times, serif;\n  font-size: 95%;\n}\n#tabs {\n  font-size: 70%;\n}\n#menu {\n  font-size: 80%;\n}\n#footer {\n  font-size: 70%;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: \"Trebuchet MS\", verdana, arial, helvetica, sans-serif;\n  font-weight: bold;\n  margin-top: 1em;\n  margin-bottom: .5em;\n}\n\nh1 {\n    margin-top: 0;\n    margin-bottom: 1em;\n  font-size: 1.4em;\n}\n#content h1 {\n  font-size: 160%;\n  margin-bottom: .5em;\n}\n#menu h1 {\n  margin: 0;\n  padding: 10px;\n  background: #336699;\n  color: white;\n}\nh2 { font-size: 120%; }\nh3 { font-size: 100%; }\nh4 { font-size: 90%; }\nh5 { font-size: 80%; }\nh6 { font-size: 75%; }\n\np {\n  line-height: 120%;\n  text-align: left;\n  margin-top: .5em;\n  margin-bottom: 1em;\n}\n\n#content li,\n#content th,\n#content td,\n#content li ul,\n#content li ol{\n  margin-top: .5em;\n  margin-bottom: .5em;\n}\n\n\n#content li li,\n#minitoc-area li{\n  margin-top: 0em;\n  margin-bottom: 0em;\n}\n\n#content .attribution {\n  text-align: right;\n  font-style: italic;\n  font-size: 85%;\n  margin-top: 1em;\n}\n\n.codefrag {\n  font-family: \"Courier New\", Courier, monospace;\n  font-size: 110%;\n}"
  },
  {
    "path": "docs/skin/breadcrumbs-optimized.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\nvar PREPREND_CRUMBS=new Array();\nvar link1=\"@skinconfig.trail.link1.name@\";\nvar link2=\"@skinconfig.trail.link2.name@\";\nvar link3=\"@skinconfig.trail.link3.name@\";\nif(!(link1==\"\")&&!link1.indexOf( \"@\" ) == 0){\n  PREPREND_CRUMBS.push( new Array( link1, @skinconfig.trail.link1.href@ ) ); }\nif(!(link2==\"\")&&!link2.indexOf( \"@\" ) == 0){\n  PREPREND_CRUMBS.push( new Array( link2, @skinconfig.trail.link2.href@ ) ); }\nif(!(link3==\"\")&&!link3.indexOf( \"@\" ) == 0){\n  PREPREND_CRUMBS.push( new Array( link3, @skinconfig.trail.link3.href@ ) ); }\nvar DISPLAY_SEPARATOR=\" &gt; \";\nvar DISPLAY_PREPREND=\" &gt; \";\nvar DISPLAY_POSTPREND=\":\";\nvar CSS_CLASS_CRUMB=\"breadcrumb\";\nvar CSS_CLASS_TRAIL=\"breadcrumbTrail\";\nvar CSS_CLASS_SEPARATOR=\"crumbSeparator\";\nvar FILE_EXTENSIONS=new Array( \".html\", \".htm\", \".jsp\", \".php\", \".php3\", \".php4\" );\nvar PATH_SEPARATOR=\"/\";\n\nfunction sc(s) {\n\tvar l=s.toLowerCase();\n\treturn l.substr(0,1).toUpperCase()+l.substr(1);\n}\nfunction getdirs() {\n\tvar t=document.location.pathname.split(PATH_SEPARATOR);\n\tvar lc=t[t.length-1];\n\tfor(var i=0;i < FILE_EXTENSIONS.length;i++)\n\t{\n\t\tif(lc.indexOf(FILE_EXTENSIONS[i]))\n\t\t\treturn t.slice(1,t.length-1); }\n\treturn t.slice(1,t.length);\n}\nfunction getcrumbs( d )\n{\n\tvar pre = \"/\";\n\tvar post = \"/\";\n\tvar c = new Array();\n\tif( d != null )\n\t{\n\t\tfor(var i=0;i < d.length;i++) {\n\t\t\tpre+=d[i]+postfix;\n\t\t\tc.push(new Array(d[i],pre)); }\n\t}\n\tif(PREPREND_CRUMBS.length > 0 )\n\t\treturn PREPREND_CRUMBS.concat( c );\n\treturn c;\n}\nfunction gettrail( c )\n{\n\tvar h=DISPLAY_PREPREND;\n\tfor(var i=0;i < c.length;i++)\n\t{\n\t\th+='<a href=\"'+c[i][1]+'\" >'+sc(c[i][0])+'</a>';\n\t\tif(i!=(c.length-1))\n\t\t\th+=DISPLAY_SEPARATOR; }\n\treturn h+DISPLAY_POSTPREND;\n}\n\nfunction gettrailXHTML( c )\n{\n\tvar h='<span class=\"'+CSS_CLASS_TRAIL+'\">'+DISPLAY_PREPREND;\n\tfor(var i=0;i < c.length;i++)\n\t{\n\t\th+='<a href=\"'+c[i][1]+'\" class=\"'+CSS_CLASS_CRUMB+'\">'+sc(c[i][0])+'</a>';\n\t\tif(i!=(c.length-1))\n\t\t\th+='<span class=\"'+CSS_CLASS_SEPARATOR+'\">'+DISPLAY_SEPARATOR+'</span>'; }\n\treturn h+DISPLAY_POSTPREND+'</span>';\n}\n\nif(document.location.href.toLowerCase().indexOf(\"http://\")==-1)\n\tdocument.write(gettrail(getcrumbs()));\nelse\n\tdocument.write(gettrail(getcrumbs(getdirs())));\n\n"
  },
  {
    "path": "docs/skin/breadcrumbs.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n/**\n * This script, when included in a html file, builds a neat breadcrumb trail\n * based on its url. That is, if it doesn't contains bugs (I'm relatively\n * sure it does).\n *\n * Typical usage:\n * <script type=\"text/javascript\" language=\"JavaScript\" src=\"breadcrumbs.js\"></script>\n */\n\n/**\n * IE 5 on Mac doesn't know Array.push.\n *\n * Implement it - courtesy to fritz.\n */\nvar abc\t= new Array();\nif (!abc.push) {\n  Array.prototype.push\t= function(what){this[this.length]=what}\n}\n\n/* ========================================================================\n\tCONSTANTS\n   ======================================================================== */\n\n/**\n * Two-dimensional array containing extra crumbs to place at the front of\n * the trail. Specify first the name of the crumb, then the URI that belongs\n * to it. You'll need to modify this for every domain or subdomain where\n * you use this script (you can leave it as an empty array if you wish)\n */\nvar PREPREND_CRUMBS = new Array();\n\nvar link1 = \"@skinconfig.trail.link1.name@\";\nvar link2 = \"@skinconfig.trail.link2.name@\";\nvar link3 = \"@skinconfig.trail.link3.name@\";\n\nvar href1 = \"@skinconfig.trail.link1.href@\";\nvar href2 = \"@skinconfig.trail.link2.href@\";\nvar href3 = \"@skinconfig.trail.link3.href@\";\n\n   if(!(link1==\"\")&&!link1.indexOf( \"@\" ) == 0){\n     PREPREND_CRUMBS.push( new Array( link1, href1 ) );\n   }\n   if(!(link2==\"\")&&!link2.indexOf( \"@\" ) == 0){\n     PREPREND_CRUMBS.push( new Array( link2, href2 ) );\n   }\n   if(!(link3==\"\")&&!link3.indexOf( \"@\" ) == 0){\n     PREPREND_CRUMBS.push( new Array( link3, href3 ) );\n   }\n\n/**\n * String to include between crumbs:\n */\nvar DISPLAY_SEPARATOR = \" &gt; \";\n/**\n * String to include at the beginning of the trail\n */\nvar DISPLAY_PREPREND = \" &gt; \";\n/**\n * String to include at the end of the trail\n */\nvar DISPLAY_POSTPREND = \"\";\n\n/**\n * CSS Class to use for a single crumb:\n */\nvar CSS_CLASS_CRUMB = \"breadcrumb\";\n\n/**\n * CSS Class to use for the complete trail:\n */\nvar CSS_CLASS_TRAIL = \"breadcrumbTrail\";\n\n/**\n * CSS Class to use for crumb separator:\n */\nvar CSS_CLASS_SEPARATOR = \"crumbSeparator\";\n\n/**\n * Array of strings containing common file extensions. We use this to\n * determine what part of the url to ignore (if it contains one of the\n * string specified here, we ignore it).\n */\nvar FILE_EXTENSIONS = new Array( \".html\", \".htm\", \".jsp\", \".php\", \".php3\", \".php4\" );\n\n/**\n * String that separates parts of the breadcrumb trail from each other.\n * When this is no longer a slash, I'm sure I'll be old and grey.\n */\nvar PATH_SEPARATOR = \"/\";\n\n/* ========================================================================\n\tUTILITY FUNCTIONS\n   ======================================================================== */\n/**\n * Capitalize first letter of the provided string and return the modified\n * string.\n */\nfunction sentenceCase( string )\n{        return string;\n\t//var lower = string.toLowerCase();\n\t//return lower.substr(0,1).toUpperCase() + lower.substr(1);\n}\n\n/**\n * Returns an array containing the names of all the directories in the\n * current document URL\n */\nfunction getDirectoriesInURL()\n{\n\tvar trail = document.location.pathname.split( PATH_SEPARATOR );\n\n\t// check whether last section is a file or a directory\n\tvar lastcrumb = trail[trail.length-1];\n\tfor( var i = 0; i < FILE_EXTENSIONS.length; i++ )\n\t{\n\t\tif( lastcrumb.indexOf( FILE_EXTENSIONS[i] ) )\n\t\t{\n\t\t\t// it is, remove it and send results\n\t\t\treturn trail.slice( 1, trail.length-1 );\n\t\t}\n\t}\n\n\t// it's not; send the trail unmodified\n\treturn trail.slice( 1, trail.length );\n}\n\n/* ========================================================================\n\tBREADCRUMB FUNCTIONALITY\n   ======================================================================== */\n/**\n * Return a two-dimensional array describing the breadcrumbs based on the\n * array of directories passed in.\n */\nfunction getBreadcrumbs( dirs )\n{\n\tvar prefix = \"/\";\n\tvar postfix = \"/\";\n\n\t// the array we will return\n\tvar crumbs = new Array();\n\n\tif( dirs != null )\n\t{\n\t\tfor( var i = 0; i < dirs.length; i++ )\n\t\t{\n\t\t\tprefix += dirs[i] + postfix;\n\t\t\tcrumbs.push( new Array( dirs[i], prefix ) );\n\t\t}\n\t}\n\n\t// preprend the PREPREND_CRUMBS\n\tif(PREPREND_CRUMBS.length > 0 )\n\t{\n\t\treturn PREPREND_CRUMBS.concat( crumbs );\n\t}\n\n\treturn crumbs;\n}\n\n/**\n * Return a string containing a simple text breadcrumb trail based on the\n * two-dimensional array passed in.\n */\nfunction getCrumbTrail( crumbs )\n{\n\tvar xhtml = DISPLAY_PREPREND;\n\n\tfor( var i = 0; i < crumbs.length; i++ )\n\t{\n\t\txhtml += '<a href=\"' + crumbs[i][1] + '\" >';\n\t\txhtml += unescape( crumbs[i][0] ) + '</a>';\n\t\tif( i != (crumbs.length-1) )\n\t\t{\n\t\t\txhtml += DISPLAY_SEPARATOR;\n\t\t}\n\t}\n\n\txhtml += DISPLAY_POSTPREND;\n\n\treturn xhtml;\n}\n\n/**\n * Return a string containing an XHTML breadcrumb trail based on the\n * two-dimensional array passed in.\n */\nfunction getCrumbTrailXHTML( crumbs )\n{\n\tvar xhtml = '<span class=\"' + CSS_CLASS_TRAIL  + '\">';\n\txhtml += DISPLAY_PREPREND;\n\n\tfor( var i = 0; i < crumbs.length; i++ )\n\t{\n\t\txhtml += '<a href=\"' + crumbs[i][1] + '\" class=\"' + CSS_CLASS_CRUMB + '\">';\n\t\txhtml += unescape( crumbs[i][0] ) + '</a>';\n\t\tif( i != (crumbs.length-1) )\n\t\t{\n\t\t\txhtml += '<span class=\"' + CSS_CLASS_SEPARATOR + '\">' + DISPLAY_SEPARATOR + '</span>';\n\t\t}\n\t}\n\n\txhtml += DISPLAY_POSTPREND;\n\txhtml += '</span>';\n\n\treturn xhtml;\n}\n\n/* ========================================================================\n\tPRINT BREADCRUMB TRAIL\n   ======================================================================== */\n\n// check if we're local; if so, only print the PREPREND_CRUMBS\nif( document.location.href.toLowerCase().indexOf( \"http://\" ) == -1 )\n{\n\tdocument.write( getCrumbTrail( getBreadcrumbs() ) );\n}\nelse\n{\n\tdocument.write( getCrumbTrail( getBreadcrumbs( getDirectoriesInURL() ) ) );\n}\n\n"
  },
  {
    "path": "docs/skin/fontsize.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\nfunction init() \n{ //embedded in the doc\n  //ndeSetTextSize();\n}\n\nfunction checkBrowser(){\n  if (!document.getElementsByTagName){\n    return true;\n  }\n  else{\n    return false;\n  }\n}\n\n\nfunction ndeSetTextSize(chgsize,rs) \n{\n  var startSize;\n  var newSize;\n\n  if (!checkBrowser)\n  {\n    return;\n  }\n\n  startSize = parseInt(ndeGetDocTextSize());\n\n  if (!startSize)\n  {\n    startSize = 16;\n  }\n\n  switch (chgsize)\n  {\n  case 'incr':\n    newSize = startSize + 2;\n    break;\n\n  case 'decr':\n    newSize = startSize - 2;\n    break;\n\n  case 'reset':\n    if (rs) {newSize = rs;} else {newSize = 16;}\n    break;\n\n  default:\n    try{\n      newSize = parseInt(ndeReadCookie(\"nde-textsize\"));\n    }\n    catch(e){\n      alert(e);\n    }\n    \n    if (!newSize || newSize == 'NaN')\n    {\n      newSize = startSize;\n    }\n    break;\n\n  }\n\n  if (newSize < 10) \n  {\n    newSize = 10;\n  }\n\n  newSize += 'px';\n\n  document.getElementsByTagName('html')[0].style.fontSize = newSize;\n  document.getElementsByTagName('body')[0].style.fontSize = newSize;\n\n  ndeCreateCookie(\"nde-textsize\", newSize, 365);\n}\n\nfunction ndeGetDocTextSize() \n{\n  if (!checkBrowser)\n  {\n    return 0;\n  }\n\n  var size = 0;\n  var body = document.getElementsByTagName('body')[0];\n\n  if (body.style && body.style.fontSize)\n  {\n    size = body.style.fontSize;\n  }\n  else if (typeof(getComputedStyle) != 'undefined')\n  {\n    size = getComputedStyle(body,'').getPropertyValue('font-size');\n  }\n  else if (body.currentStyle)\n  {\n   size = body.currentStyle.fontSize;\n  }\n\n  //fix IE bug\n  if( isNaN(size)){\n    if(size.substring(size.length-1)==\"%\"){\n      return\n    }\n\n  }\n\n  return size;\n\n}\n\n\n\nfunction ndeCreateCookie(name,value,days) \n{\n  var cookie = name + \"=\" + value + \";\";\n\n  if (days) \n  {\n    var date = new Date();\n    date.setTime(date.getTime()+(days*24*60*60*1000));\n    cookie += \" expires=\" + date.toGMTString() + \";\";\n  }\n  cookie += \" path=/\";\n\n  document.cookie = cookie;\n\n}\n\nfunction ndeReadCookie(name) \n{\n  var nameEQ = name + \"=\";\n  var ca = document.cookie.split(';');\n\n \n  for(var i = 0; i < ca.length; i++) \n  {\n    var c = ca[i];\n    while (c.charAt(0) == ' ') \n    {\n      c = c.substring(1, c.length);\n    }\n\n    ctest = c.substring(0,name.length);\n \n    if(ctest == name){\n      return c.substring(nameEQ.length,c.length);\n    }\n  }\n  return null;\n}\n"
  },
  {
    "path": "docs/skin/getBlank.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n/**\n * getBlank script - when included in a html file and called from a form text field, will set the value of this field to \"\"\n * if the text value is still the standard value.\n * getPrompt script - when included in a html file and called from a form text field, will set the value of this field to the prompt\n * if the text value is empty.\n *\n * Typical usage:\n * <script type=\"text/javascript\" language=\"JavaScript\" src=\"getBlank.js\"></script>\n * <input type=\"text\" id=\"query\" value=\"Search the site:\" onFocus=\"getBlank (this, 'Search the site:');\" onBlur=\"getBlank (this, 'Search the site:');\"/>\n */\n<!--\nfunction getBlank (form, stdValue){\nif (form.value == stdValue){\n\tform.value = '';\n\t}\nreturn true;\n}\nfunction getPrompt (form, stdValue){\nif (form.value == ''){\n\tform.value = stdValue;\n\t}\nreturn true;\n}\n//-->\n"
  },
  {
    "path": "docs/skin/getMenu.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n/**\n * This script, when included in a html file, can be used to make collapsible menus\n *\n * Typical usage:\n * <script type=\"text/javascript\" language=\"JavaScript\" src=\"menu.js\"></script>\n */\n\nif (document.getElementById){ \n  document.write('<style type=\"text/css\">.menuitemgroup{display: none;}</style>')\n}\n\n\nfunction SwitchMenu(obj, thePath)\n{\nvar open = 'url(\"'+thePath + 'images/chapter_open.gif\")';\nvar close = 'url(\"'+thePath + 'images/chapter.gif\")';\n  if(document.getElementById)  {\n    var el = document.getElementById(obj);\n    var title = document.getElementById(obj+'Title');\n\n    if(el.style.display != \"block\"){ \n      title.style.backgroundImage = open;\n      el.style.display = \"block\";\n    }else{\n      title.style.backgroundImage = close;\n      el.style.display = \"none\";\n    }\n  }// end -  if(document.getElementById) \n}//end - function SwitchMenu(obj)\n"
  },
  {
    "path": "docs/skin/images/README.txt",
    "content": "The images in this directory are used if the current skin lacks them.\n"
  },
  {
    "path": "docs/skin/menu.js",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n/**\n * This script, when included in a html file, can be used to make collapsible menus\n *\n * Typical usage:\n * <script type=\"text/javascript\" language=\"JavaScript\" src=\"menu.js\"></script>\n */\n\nif (document.getElementById){ \n  document.write('<style type=\"text/css\">.menuitemgroup{display: none;}</style>')\n}\n\nfunction SwitchMenu(obj)\n{\n  if(document.getElementById)  {\n    var el = document.getElementById(obj);\n    var title = document.getElementById(obj+'Title');\n\n    if(obj.indexOf(\"_selected_\")==0&&el.style.display == \"\"){\n      el.style.display = \"block\";\n      title.className = \"pagegroupselected\";\n    }\n\n    if(el.style.display != \"block\"){\n      el.style.display = \"block\";\n      title.className = \"pagegroupopen\";\n    }\n    else{\n      el.style.display = \"none\";\n      title.className = \"pagegroup\";\n    }\n  }// end -  if(document.getElementById) \n}//end - function SwitchMenu(obj)\n"
  },
  {
    "path": "docs/skin/note.txt",
    "content": "Notes for developer:\n\n--Legend-------------------\nTODO -> blocker\nDONE -> blocker\nToDo -> enhancement bug\ndone -> enhancement bug\n\n--Issues-------------------\n- the corner images should be rendered through svg with the header color.\n-> DONE \n-> ToDo: get rid of the images and use only divs!\n\n- the menu points should be displayed \"better\". \n-> DONE\n-- Use the krysalis-site menu approach for the overall menu display.\n-> DONE\n-- Use the old lenya innermenu approch to further enhance the menu .\n-> DONE\n\n- the content area needs some attention.\n-> DONE\n-- introduce the heading scheme from krysalis (<headings type=\"clean|box|underlined\"/>)\n-> DONE \n-> ToDo: make box with round corners\n-> done: make underlined with variable border height\n-> ToDo: make underline with bottom round corner\n-- introduce the toc for each html-page\n-> DONE\n-- introduce the external-link-images.\n-> DONE\n\n- the publish note should be where now only a border is. \nLike <div id=\"published\"/>\n-> DONE\n, but make it configurable.\n-> DONE\n- footer needs some attention\n-> DONE\n-- the footer do not have the color profile! Enable it!\n-> DONE\n-- the footer should as well contain a feedback link. \nSee http://issues.apache.org/eyebrowse/ReadMsg?listName=forrest-user@xml.apache.org&msgNo=71\n-> DONE\n\n- introduce credits alternativ location\n-> DONE\n\n- border for published / breadtrail / menu /tab divs \n-> ToDo"
  },
  {
    "path": "docs/skin/print.css",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\nbody {\n  font-family: Georgia, Palatino, serif;\n  font-size: 12pt;\n  background: white;\n}\n\n#tabs,\n#menu,\n#content .toc {\n  display: none;\n}\n\n#content {\n  width: auto;\n  padding: 0;\n  float: none !important;\n  color: black;\n  background: inherit;\n}\n\na:link, a:visited {\n  color: #336699;\n  background: inherit;\n  text-decoration: underline;\n}\n\n#top .logo {\n  padding: 0;\n  margin: 0 0 2em 0;\n}\n\n#footer {\n  margin-top: 4em;\n}\n\nacronym {\n  border: 0;\n}"
  },
  {
    "path": "docs/skin/profile.css",
    "content": "\n\n/* ==================== aural ============================ */\n\n@media aural {\n  h1, h2, h3, h4, h5, h6 { voice-family: paul, male; stress: 20; richness: 90 }\n  h1 { pitch: x-low; pitch-range: 90 }\n  h2 { pitch: x-low; pitch-range: 80 }\n  h3 { pitch: low; pitch-range: 70 }\n  h4 { pitch: medium; pitch-range: 60 }\n  h5 { pitch: medium; pitch-range: 50 }\n  h6 { pitch: medium; pitch-range: 40 }\n  li, dt, dd { pitch: medium; richness: 60 }\n  dt { stress: 80 }\n  pre, code, tt { pitch: medium; pitch-range: 0; stress: 0; richness: 80 }\n  em { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }\n  strong { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }\n  dfn { pitch: high; pitch-range: 60; stress: 60 }\n  s, strike { richness: 0 }\n  i { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }\n  b { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }\n  u { richness: 0 }\n  \n  :link { voice-family: harry, male }\n  :visited { voice-family: betty, female }\n  :active { voice-family: betty, female; pitch-range: 80; pitch: x-high }\n}\n  \na.external  {\n  padding: 0 20px 0px 0px;\n\tdisplay:inline;\n  background-repeat: no-repeat;\n\tbackground-position: center right;\n\tbackground-image: url(images/external-link.gif);\n}\n  \n#top          { background-color: #FFFFFF;}  \n \n#top .header .current { background-color: #4C6C8F;} \n#top .header .current a:link {  color: #ffffff;  }\n#top .header .current a:visited { color: #ffffff; }\n#top .header .current a:hover { color: #ffffff; }\n \n#tabs li      { background-color: #E5E4D9 ;} \n#tabs li a:link {  color: #000000;  }\n#tabs li a:visited { color: #000000; }\n#tabs li a:hover { color: #000000; }\n\n#level2tabs a.selected      { background-color: #4C6C8F ;} \n#level2tabs a:link {  color: #ffffff;  }\n#level2tabs a:visited { color: #ffffff; }\n#level2tabs a:hover { color: #ffffff; }\n\n#level2tabs { background-color: #E5E4D9;}\n#level2tabs a.unselected:link {  color: #000000;  }\n#level2tabs a.unselected:visited { color: #000000; }\n#level2tabs a.unselected:hover { color: #000000; }\n\n.heading { background-color: #E5E4D9;} \n\n.boxed { background-color: #E5E4D9;} \n.underlined_5 \t{border-bottom: solid 5px #E5E4D9;}\n.underlined_10 \t{border-bottom: solid 10px #E5E4D9;}\ntable caption { \nbackground-color: #E5E4D9; \ncolor: #000000;\n}\n    \n#feedback {\ncolor: #FFFFFF;\nbackground: #4C6C8F;\ntext-align: center;\n}\n#feedback #feedbackto {\ncolor: #FFFFFF;\n}   \n\n#publishedStrip { \ncolor: #FFFFFF;\nbackground: #4C6C8F; \n}\n\n#publishedStrip { \ncolor: #000000;\nbackground: #E5E4D9; \n}\n\n#menu .menupagetitle  { background-color: #CFDCED;\n  color: #000000;}\n\n#menu           { border-color: #999999;}\n#menu .menupagetitle  { border-color: #999999;}\n#menu .menupageitemgroup  { border-color: #999999;}\n\n#menu      { background-color: #4C6C8F;} \n#menu  {  color: #ffffff;} \n#menu a:link {  color: #ffffff;} \n#menu a:visited {  color: #ffffff;} \n#menu a:hover {  \nbackground-color: #4C6C8F;\ncolor: #ffffff;} \n\n#menu h1 {\ncolor: #000000;\nbackground-color: #cfdced;\n}   \n \n#top .searchbox { \nbackground-color: #E5E4D9 ;\ncolor: #000000; \n} \n \n#menu .menupageitemgroup     { \nbackground-color: #E5E4D9;\n}\n#menu .menupageitem {\ncolor: #000000;\n} \n#menu .menupageitem a:link {  color: #000000;} \n#menu .menupageitem a:visited {  color: #000000;} \n#menu .menupageitem a:hover {  \nbackground-color: #E5E4D9;\ncolor: #000000;\n}\n\nbody{ \nbackground-color: #ffffff;\ncolor: #000000;\n} \na:link { color:#0000ff} \na:visited { color:#009999} \na:hover { color:#6587ff} \n\n \n.ForrestTable      { background-color: #ccc;} \n \n.ForrestTable td   { background-color: #ffffff;} \n \n.highlight        { background-color: #ffff00;} \n \n.fixme        { border-color: #c60;} \n \n.note         { border-color: #069;} \n \n.warning         { border-color: #900;} \n \n.code         { border-color: #a5b6c6;} \n \n#footer       { background-color: #E5E4D9;} \n/* extra-css */\n    \n    p.quote {\n      margin-left: 2em;\n      padding: .5em;\n      background-color: #f0f0f0;\n      font-family: monospace;\n    }\n\n    pre.code {\n      margin-left: 0em;\n      padding: 0.5em;\n      background-color: #f0f0f0;\n      font-family: monospace;\n    }\n\n\n\n  "
  },
  {
    "path": "docs/skin/prototype.js",
    "content": "/*  Prototype JavaScript framework, version 1.4.0_pre4\n *  (c) 2005 Sam Stephenson <sam@conio.net>\n *\n *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff\n *  against the source tree, available from the Prototype darcs repository. \n *\n *  Prototype is freely distributable under the terms of an MIT-style license.\n *\n *  For details, see the Prototype web site: http://prototype.conio.net/\n *\n/*--------------------------------------------------------------------------*/\n\nvar Prototype = {\n  Version: '1.4.0_pre4',\n  \n  emptyFunction: function() {},\n  K: function(x) {return x}\n}\n\nvar Class = {\n  create: function() {\n    return function() { \n      this.initialize.apply(this, arguments);\n    }\n  }\n}\n\nvar Abstract = new Object();\n\nObject.extend = function(destination, source) {\n  for (property in source) {\n    destination[property] = source[property];\n  }\n  return destination;\n}\n\nFunction.prototype.bind = function(object) {\n  var __method = this;\n  return function() {\n    return __method.apply(object, arguments);\n  }\n}\n\nFunction.prototype.bindAsEventListener = function(object) {\n  var __method = this;\n  return function(event) {\n    return __method.call(object, event || window.event);\n  }\n}\n\nNumber.prototype.toColorPart = function() {\n  var digits = this.toString(16);\n  if (this < 16) return '0' + digits;\n  return digits;\n}\n\nvar Try = {\n  these: function() {\n    var returnValue;\n\n    for (var i = 0; i < arguments.length; i++) {\n      var lambda = arguments[i];\n      try {\n        returnValue = lambda();\n        break;\n      } catch (e) {}\n    }\n\n    return returnValue;\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar PeriodicalExecuter = Class.create();\nPeriodicalExecuter.prototype = {\n  initialize: function(callback, frequency) {\n    this.callback = callback;\n    this.frequency = frequency;\n    this.currentlyExecuting = false;\n\n    this.registerCallback();\n  },\n\n  registerCallback: function() {\n    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n\n  onTimerEvent: function() {\n    if (!this.currentlyExecuting) {\n      try { \n        this.currentlyExecuting = true;\n        this.callback(); \n      } finally { \n        this.currentlyExecuting = false;\n      }\n    }\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nfunction $() {\n  var elements = new Array();\n\n  for (var i = 0; i < arguments.length; i++) {\n    var element = arguments[i];\n    if (typeof element == 'string')\n      element = document.getElementById(element);\n\n    if (arguments.length == 1) \n      return element;\n\n    elements.push(element);\n  }\n\n  return elements;\n}\n\nif (!Array.prototype.push) {\n  Array.prototype.push = function() {\n\t\tvar startLength = this.length;\n\t\tfor (var i = 0; i < arguments.length; i++)\n      this[startLength + i] = arguments[i];\n\t  return this.length;\n  }\n}\n\nif (!Function.prototype.apply) {\n  // Based on code from http://www.youngpup.net/\n  Function.prototype.apply = function(object, parameters) {\n    var parameterStrings = new Array();\n    if (!object)     object = window;\n    if (!parameters) parameters = new Array();\n    \n    for (var i = 0; i < parameters.length; i++)\n      parameterStrings[i] = 'parameters[' + i + ']';\n    \n    object.__apply__ = this;\n    var result = eval('object.__apply__(' + \n      parameterStrings.join(', ') + ')');\n    object.__apply__ = null;\n    \n    return result;\n  }\n}\n\nObject.extend(String.prototype, {\n  stripTags: function() {\n    return this.replace(/<\\/?[^>]+>/gi, '');\n  },\n\n  escapeHTML: function() {\n    var div = document.createElement('div');\n    var text = document.createTextNode(this);\n    div.appendChild(text);\n    return div.innerHTML;\n  },\n\n  unescapeHTML: function() {\n    var div = document.createElement('div');\n    div.innerHTML = this.stripTags();\n    return div.childNodes[0].nodeValue;\n  },\n  \n  parseQuery: function() {\n    var str = this;\n    if (str.substring(0,1) == '?') {\n      str = this.substring(1);\n    }\n    var result = {};\n    var pairs = str.split('&');\n    for (var i = 0; i < pairs.length; i++) {\n      var pair = pairs[i].split('=');\n      result[pair[0]] = pair[1];\n    }\n    return result;\n  }\n});\n\n\nvar _break    = new Object();\nvar _continue = new Object();\n\nvar Enumerable = {\n  each: function(iterator) {\n    var index = 0;\n    try {\n      this._each(function(value) {\n        try {\n          iterator(value, index++);\n        } catch (e) {\n          if (e != _continue) throw e;\n        }\n      });\n    } catch (e) {\n      if (e != _break) throw e;\n    }\n  },\n  \n  all: function(iterator) {\n    var result = true;\n    this.each(function(value, index) {\n      if (!(result &= (iterator || Prototype.K)(value, index))) \n        throw _break;\n    });\n    return result;\n  },\n  \n  any: function(iterator) {\n    var result = true;\n    this.each(function(value, index) {\n      if (result &= (iterator || Prototype.K)(value, index)) \n        throw _break;\n    });\n    return result;\n  },\n  \n  collect: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      results.push(iterator(value, index));\n    });\n    return results;\n  },\n  \n  detect: function (iterator) {\n    var result;\n    this.each(function(value, index) {\n      if (iterator(value, index)) {\n        result = value;\n        throw _break;\n      }\n    });\n    return result;\n  },\n  \n  findAll: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      if (iterator(value, index))\n        results.push(value);\n    });\n    return results;\n  },\n  \n  grep: function(pattern, iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      var stringValue = value.toString();\n      if (stringValue.match(pattern))\n        results.push((iterator || Prototype.K)(value, index));\n    })\n    return results;\n  },\n  \n  include: function(object) {\n    var found = false;\n    this.each(function(value) {\n      if (value == object) {\n        found = true;\n        throw _break;\n      }\n    });\n    return found;\n  },\n  \n  inject: function(memo, iterator) {\n    this.each(function(value, index) {\n      memo = iterator(memo, value, index);\n    });\n    return memo;\n  },\n  \n  invoke: function(method) {\n    var args = $A(arguments).slice(1);\n    return this.collect(function(value) {\n      return value[method].apply(value, args);\n    });\n  },\n  \n  max: function(iterator) {\n    var result;\n    this.each(function(value, index) {\n      value = (iterator || Prototype.K)(value, index);\n      if (value >= (result || value))\n        result = value;\n    });\n    return result;\n  },\n  \n  min: function(iterator) {\n    var result;\n    this.each(function(value, index) {\n      value = (iterator || Prototype.K)(value, index);\n      if (value <= (result || value))\n        result = value;\n    });\n    return result;\n  },\n  \n  partition: function(iterator) {\n    var trues = [], falses = [];\n    this.each(function(value, index) {\n      ((iterator || Prototype.K)(value, index) ? \n        trues : falses).push(value);\n    });\n    return [trues, falses];\n  },\n  \n  pluck: function(property) {\n    var results = [];\n    this.each(function(value, index) {\n      results.push(value[property]);\n    });\n    return results;\n  },\n  \n  reject: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      if (!iterator(value, index))\n        results.push(value);\n    });\n    return results;\n  },\n  \n  sortBy: function(iterator) {\n    return this.collect(function(value, index) {\n      return {value: value, criteria: iterator(value, index)};\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }).pluck('value');\n  },\n  \n  toArray: function() {\n    return this.collect(Prototype.K);\n  },\n  \n  zip: function() {\n    var iterator = Prototype.K, args = $A(arguments);\n    if (typeof args.last() == 'function')\n      iterator = args.pop();\n\n    var collections = [this].concat(args).map($A);\n    return this.map(function(value, index) {\n      iterator(value = collections.pluck(index));\n      return value;\n    });\n  }\n}\n\nObject.extend(Enumerable, {\n  map:     Enumerable.collect,\n  find:    Enumerable.detect,\n  select:  Enumerable.findAll,\n  member:  Enumerable.include,\n  entries: Enumerable.toArray\n});\n\n$A = Array.from = function(iterable) {\n  var results = [];\n  for (var i = 0; i < iterable.length; i++)\n    results.push(iterable[i]);\n  return results;\n}\n\nObject.extend(Array.prototype, {\n  _each: function(iterator) {\n    for (var i = 0; i < this.length; i++)\n      iterator(this[i]);\n  },\n  \n  first: function() {\n    return this[0];\n  },\n  \n  last: function() {\n    return this[this.length - 1];\n  }\n});\n\nObject.extend(Array.prototype, Enumerable);\n\n\nvar Ajax = {\n  getTransport: function() {\n    return Try.these(\n      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\n      function() {return new ActiveXObject('Microsoft.XMLHTTP')},\n      function() {return new XMLHttpRequest()}\n    ) || false;\n  }\n}\n\nAjax.Base = function() {};\nAjax.Base.prototype = {\n  setOptions: function(options) {\n    this.options = {\n      method:       'post',\n      asynchronous: true,\n      parameters:   ''\n    }\n    Object.extend(this.options, options || {});\n  },\n\n  responseIsSuccess: function() {\n    return this.transport.status == undefined\n        || this.transport.status == 0 \n        || (this.transport.status >= 200 && this.transport.status < 300);\n  },\n\n  responseIsFailure: function() {\n    return !this.responseIsSuccess();\n  }\n}\n\nAjax.Request = Class.create();\nAjax.Request.Events = \n  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\n\nAjax.Request.prototype = Object.extend(new Ajax.Base(), {\n  initialize: function(url, options) {\n    this.transport = Ajax.getTransport();\n    this.setOptions(options);\n    this.request(url);\n  },\n\n  request: function(url) {\n    var parameters = this.options.parameters || '';\n    if (parameters.length > 0) parameters += '&_=';\n\n    try {\n      if (this.options.method == 'get')\n        url += '?' + parameters;\n\n      this.transport.open(this.options.method, url,\n        this.options.asynchronous);\n\n      if (this.options.asynchronous) {\n        this.transport.onreadystatechange = this.onStateChange.bind(this);\n        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);\n      }\n\n      this.setRequestHeaders();\n\n      var body = this.options.postBody ? this.options.postBody : parameters;\n      this.transport.send(this.options.method == 'post' ? body : null);\n\n    } catch (e) {\n    }\n  },\n\n  setRequestHeaders: function() {\n    var requestHeaders = \n      ['X-Requested-With', 'XMLHttpRequest',\n       'X-Prototype-Version', Prototype.Version];\n\n    if (this.options.method == 'post') {\n      requestHeaders.push('Content-type', \n        'application/x-www-form-urlencoded');\n\n      /* Force \"Connection: close\" for Mozilla browsers to work around\n       * a bug where XMLHttpReqeuest sends an incorrect Content-length\n       * header. See Mozilla Bugzilla #246651. \n       */\n      if (this.transport.overrideMimeType)\n        requestHeaders.push('Connection', 'close');\n    }\n\n    if (this.options.requestHeaders)\n      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);\n\n    for (var i = 0; i < requestHeaders.length; i += 2)\n      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);\n  },\n\n  onStateChange: function() {\n    var readyState = this.transport.readyState;\n    if (readyState != 1)\n      this.respondToReadyState(this.transport.readyState);\n  },\n\n  respondToReadyState: function(readyState) {\n    var event = Ajax.Request.Events[readyState];\n\n    if (event == 'Complete')\n      (this.options['on' + this.transport.status]\n       || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]\n       || Prototype.emptyFunction)(this.transport);\n\n    (this.options['on' + event] || Prototype.emptyFunction)(this.transport);\n\n    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */\n    if (event == 'Complete')\n      this.transport.onreadystatechange = Prototype.emptyFunction;\n  }\n});\n\nAjax.Updater = Class.create();\nAjax.Updater.ScriptFragment = '(?:<script.*?>)((\\n|.)*?)(?:<\\/script>)';\n\nObject.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {\n  initialize: function(container, url, options) {\n    this.containers = {\n      success: container.success ? $(container.success) : $(container),\n      failure: container.failure ? $(container.failure) :\n        (container.success ? null : $(container))\n    }\n\n    this.transport = Ajax.getTransport();\n    this.setOptions(options);\n\n    var onComplete = this.options.onComplete || Prototype.emptyFunction;\n    this.options.onComplete = (function() {\n      this.updateContent();\n      onComplete(this.transport);\n    }).bind(this);\n\n    this.request(url);\n  },\n\n  updateContent: function() {\n    var receiver = this.responseIsSuccess() ?\n      this.containers.success : this.containers.failure;\n\n    var match    = new RegExp(Ajax.Updater.ScriptFragment, 'img');\n    var response = this.transport.responseText.replace(match, '');\n    var scripts  = this.transport.responseText.match(match);\n\n    if (receiver) {\n      if (this.options.insertion) {\n        new this.options.insertion(receiver, response);\n      } else {\n        receiver.innerHTML = response;\n      }\n    }\n\n    if (this.responseIsSuccess()) {\n      if (this.onComplete)\n        setTimeout((function() {this.onComplete(\n          this.transport)}).bind(this), 10);\n    }\n\n    if (this.options.evalScripts && scripts) {\n      match = new RegExp(Ajax.Updater.ScriptFragment, 'im');\n      setTimeout((function() {\n        for (var i = 0; i < scripts.length; i++)\n          eval(scripts[i].match(match)[1]);\n      }).bind(this), 10);\n    }\n  }\n});\n\nAjax.PeriodicalUpdater = Class.create();\nAjax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {\n  initialize: function(container, url, options) {\n    this.setOptions(options);\n    this.onComplete = this.options.onComplete;\n\n    this.frequency = (this.options.frequency || 2);\n    this.decay = 1;\n\n    this.updater = {};\n    this.container = container;\n    this.url = url;\n\n    this.start();\n  },\n\n  start: function() {\n    this.options.onComplete = this.updateComplete.bind(this);\n    this.onTimerEvent();\n  },\n\n  stop: function() {\n    this.updater.onComplete = undefined;\n    clearTimeout(this.timer);\n    (this.onComplete || Ajax.emptyFunction).apply(this, arguments);\n  },\n\n  updateComplete: function(request) {\n    if (this.options.decay) {\n      this.decay = (request.responseText == this.lastText ? \n        this.decay * this.options.decay : 1);\n\n      this.lastText = request.responseText;\n    }\n    this.timer = setTimeout(this.onTimerEvent.bind(this), \n      this.decay * this.frequency * 1000);\n  },\n\n  onTimerEvent: function() {\n    this.updater = new Ajax.Updater(this.container, this.url, this.options);\n  }\n});\n\ndocument.getElementsByClassName = function(className) {\n  var children = document.getElementsByTagName('*') || document.all;\n  var elements = new Array();\n  \n  for (var i = 0; i < children.length; i++) {\n    var child = children[i];\n    var classNames = child.className.split(' ');\n    for (var j = 0; j < classNames.length; j++) {\n      if (classNames[j] == className) {\n        elements.push(child);\n        break;\n      }\n    }\n  }\n  \n  return elements;\n}\n\n/*--------------------------------------------------------------------------*/\n\nif (!window.Element) {\n  var Element = new Object();\n}\n\nObject.extend(Element, {\n  toggle: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      element.style.display = \n        (element.style.display == 'none' ? '' : 'none');\n    }\n  },\n\n  hide: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      element.style.display = 'none';\n    }\n  },\n\n  show: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      element.style.display = '';\n    }\n  },\n\n  remove: function(element) {\n    element = $(element);\n    element.parentNode.removeChild(element);\n  },\n   \n  getHeight: function(element) {\n    element = $(element);\n    return element.offsetHeight; \n  },\n\n  hasClassName: function(element, className) {\n    element = $(element);\n    if (!element)\n      return;\n    var a = element.className.split(' ');\n    for (var i = 0; i < a.length; i++) {\n      if (a[i] == className)\n        return true;\n    }\n    return false;\n  },\n\n  addClassName: function(element, className) {\n    element = $(element);\n    Element.removeClassName(element, className);\n    element.className += ' ' + className;\n  },\n\n  removeClassName: function(element, className) {\n    element = $(element);\n    if (!element)\n      return;\n    var newClassName = '';\n    var a = element.className.split(' ');\n    for (var i = 0; i < a.length; i++) {\n      if (a[i] != className) {\n        if (i > 0)\n          newClassName += ' ';\n        newClassName += a[i];\n      }\n    }\n    element.className = newClassName;\n  },\n  \n  // removes whitespace-only text node children\n  cleanWhitespace: function(element) {\n    var element = $(element);\n    for (var i = 0; i < element.childNodes.length; i++) {\n      var node = element.childNodes[i];\n      if (node.nodeType == 3 && !/\\S/.test(node.nodeValue)) \n        Element.remove(node);\n    }\n  }\n});\n\nvar Toggle = new Object();\nToggle.display = Element.toggle;\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.Insertion = function(adjacency) {\n  this.adjacency = adjacency;\n}\n\nAbstract.Insertion.prototype = {\n  initialize: function(element, content) {\n    this.element = $(element);\n    this.content = content;\n    \n    if (this.adjacency && this.element.insertAdjacentHTML) {\n      this.element.insertAdjacentHTML(this.adjacency, this.content);\n    } else {\n      this.range = this.element.ownerDocument.createRange();\n      if (this.initializeRange) this.initializeRange();\n      this.fragment = this.range.createContextualFragment(this.content);\n      this.insertContent();\n    }\n  }\n}\n\nvar Insertion = new Object();\n\nInsertion.Before = Class.create();\nInsertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {\n  initializeRange: function() {\n    this.range.setStartBefore(this.element);\n  },\n  \n  insertContent: function() {\n    this.element.parentNode.insertBefore(this.fragment, this.element);\n  }\n});\n\nInsertion.Top = Class.create();\nInsertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {\n  initializeRange: function() {\n    this.range.selectNodeContents(this.element);\n    this.range.collapse(true);\n  },\n  \n  insertContent: function() {  \n    this.element.insertBefore(this.fragment, this.element.firstChild);\n  }\n});\n\nInsertion.Bottom = Class.create();\nInsertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {\n  initializeRange: function() {\n    this.range.selectNodeContents(this.element);\n    this.range.collapse(this.element);\n  },\n  \n  insertContent: function() {\n    this.element.appendChild(this.fragment);\n  }\n});\n\nInsertion.After = Class.create();\nInsertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {\n  initializeRange: function() {\n    this.range.setStartAfter(this.element);\n  },\n  \n  insertContent: function() {\n    this.element.parentNode.insertBefore(this.fragment, \n      this.element.nextSibling);\n  }\n});\n\nvar Field = {\n  clear: function() {\n    for (var i = 0; i < arguments.length; i++)\n      $(arguments[i]).value = '';\n  },\n\n  focus: function(element) {\n    $(element).focus();\n  },\n  \n  present: function() {\n    for (var i = 0; i < arguments.length; i++)\n      if ($(arguments[i]).value == '') return false;\n    return true;\n  },\n  \n  select: function(element) {\n    $(element).select();\n  },\n   \n  activate: function(element) {\n    $(element).focus();\n    $(element).select();\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar Form = {\n  serialize: function(form) {\n    var elements = Form.getElements($(form));\n    var queryComponents = new Array();\n    \n    for (var i = 0; i < elements.length; i++) {\n      var queryComponent = Form.Element.serialize(elements[i]);\n      if (queryComponent)\n        queryComponents.push(queryComponent);\n    }\n    \n    return queryComponents.join('&');\n  },\n  \n  getElements: function(form) {\n    var form = $(form);\n    var elements = new Array();\n\n    for (tagName in Form.Element.Serializers) {\n      var tagElements = form.getElementsByTagName(tagName);\n      for (var j = 0; j < tagElements.length; j++)\n        elements.push(tagElements[j]);\n    }\n    return elements;\n  },\n  \n  getInputs: function(form, typeName, name) {\n    var form = $(form);\n    var inputs = form.getElementsByTagName('input');\n    \n    if (!typeName && !name)\n      return inputs;\n      \n    var matchingInputs = new Array();\n    for (var i = 0; i < inputs.length; i++) {\n      var input = inputs[i];\n      if ((typeName && input.type != typeName) ||\n          (name && input.name != name)) \n        continue;\n      matchingInputs.push(input);\n    }\n\n    return matchingInputs;\n  },\n\n  disable: function(form) {\n    var elements = Form.getElements(form);\n    for (var i = 0; i < elements.length; i++) {\n      var element = elements[i];\n      element.blur();\n      element.disabled = 'true';\n    }\n  },\n\n  enable: function(form) {\n    var elements = Form.getElements(form);\n    for (var i = 0; i < elements.length; i++) {\n      var element = elements[i];\n      element.disabled = '';\n    }\n  },\n\n  focusFirstElement: function(form) {\n    var form = $(form);\n    var elements = Form.getElements(form);\n    for (var i = 0; i < elements.length; i++) {\n      var element = elements[i];\n      if (element.type != 'hidden' && !element.disabled) {\n        Field.activate(element);\n        break;\n      }\n    }\n  },\n\n  reset: function(form) {\n    $(form).reset();\n  }\n}\n\nForm.Element = {\n  serialize: function(element) {\n    var element = $(element);\n    var method = element.tagName.toLowerCase();\n    var parameter = Form.Element.Serializers[method](element);\n    \n    if (parameter)\n      return encodeURIComponent(parameter[0]) + '=' + \n        encodeURIComponent(parameter[1]);                   \n  },\n  \n  getValue: function(element) {\n    var element = $(element);\n    var method = element.tagName.toLowerCase();\n    var parameter = Form.Element.Serializers[method](element);\n    \n    if (parameter) \n      return parameter[1];\n  }\n}\n\nForm.Element.Serializers = {\n  input: function(element) {\n    switch (element.type.toLowerCase()) {\n      case 'submit':\n      case 'hidden':\n      case 'password':\n      case 'text':\n        return Form.Element.Serializers.textarea(element);\n      case 'checkbox':  \n      case 'radio':\n        return Form.Element.Serializers.inputSelector(element);\n    }\n    return false;\n  },\n\n  inputSelector: function(element) {\n    if (element.checked)\n      return [element.name, element.value];\n  },\n\n  textarea: function(element) {\n    return [element.name, element.value];\n  },\n\n  select: function(element) {\n    var value = '';\n    if (element.type == 'select-one') {\n      var index = element.selectedIndex;\n      if (index >= 0)\n        value = element.options[index].value || element.options[index].text;\n    } else {\n      value = new Array();\n      for (var i = 0; i < element.length; i++) {\n        var opt = element.options[i];\n        if (opt.selected)\n          value.push(opt.value || opt.text);\n      }\n    }\n    return [element.name, value];\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar $F = Form.Element.getValue;\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.TimedObserver = function() {}\nAbstract.TimedObserver.prototype = {\n  initialize: function(element, frequency, callback) {\n    this.frequency = frequency;\n    this.element   = $(element);\n    this.callback  = callback;\n    \n    this.lastValue = this.getValue();\n    this.registerCallback();\n  },\n  \n  registerCallback: function() {\n    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n  \n  onTimerEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  }\n}\n\nForm.Element.Observer = Class.create();\nForm.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.Observer = Class.create();\nForm.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.EventObserver = function() {}\nAbstract.EventObserver.prototype = {\n  initialize: function(element, callback) {\n    this.element  = $(element);\n    this.callback = callback;\n    \n    this.lastValue = this.getValue();\n    if (this.element.tagName.toLowerCase() == 'form')\n      this.registerFormCallbacks();\n    else\n      this.registerCallback(this.element);\n  },\n  \n  onElementEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  },\n  \n  registerFormCallbacks: function() {\n    var elements = Form.getElements(this.element);\n    for (var i = 0; i < elements.length; i++)\n      this.registerCallback(elements[i]);\n  },\n  \n  registerCallback: function(element) {\n    if (element.type) {\n      switch (element.type.toLowerCase()) {\n        case 'checkbox':  \n        case 'radio':\n          element.target = this;\n          element.prev_onclick = element.onclick || Prototype.emptyFunction;\n          element.onclick = function() {\n            this.prev_onclick(); \n            this.target.onElementEvent();\n          }\n          break;\n        case 'password':\n        case 'text':\n        case 'textarea':\n        case 'select-one':\n        case 'select-multiple':\n          element.target = this;\n          element.prev_onchange = element.onchange || Prototype.emptyFunction;\n          element.onchange = function() {\n            this.prev_onchange(); \n            this.target.onElementEvent();\n          }\n          break;\n      }\n    }    \n  }\n}\n\nForm.Element.EventObserver = Class.create();\nForm.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.EventObserver = Class.create();\nForm.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\n\n\nif (!window.Event) {\n  var Event = new Object();\n}\n\nObject.extend(Event, {\n  KEY_BACKSPACE: 8,\n  KEY_TAB:       9,\n  KEY_RETURN:   13,\n  KEY_ESC:      27,\n  KEY_LEFT:     37,\n  KEY_UP:       38,\n  KEY_RIGHT:    39,\n  KEY_DOWN:     40,\n  KEY_DELETE:   46,\n\n  element: function(event) {\n    return event.target || event.srcElement;\n  },\n\n  isLeftClick: function(event) {\n    return (((event.which) && (event.which == 1)) ||\n            ((event.button) && (event.button == 1)));\n  },\n\n  pointerX: function(event) {\n    return event.pageX || (event.clientX + \n      (document.documentElement.scrollLeft || document.body.scrollLeft));\n  },\n\n  pointerY: function(event) {\n    return event.pageY || (event.clientY + \n      (document.documentElement.scrollTop || document.body.scrollTop));\n  },\n\n  stop: function(event) {\n    if (event.preventDefault) { \n      event.preventDefault(); \n      event.stopPropagation(); \n    } else {\n      event.returnValue = false;\n    }\n  },\n\n  // find the first node with the given tagName, starting from the\n  // node the event was triggered on; traverses the DOM upwards\n  findElement: function(event, tagName) {\n    var element = Event.element(event);\n    while (element.parentNode && (!element.tagName ||\n        (element.tagName.toUpperCase() != tagName.toUpperCase())))\n      element = element.parentNode;\n    return element;\n  },\n\n  observers: false,\n  \n  _observeAndCache: function(element, name, observer, useCapture) {\n    if (!this.observers) this.observers = [];\n    if (element.addEventListener) {\n      this.observers.push([element, name, observer, useCapture]);\n      element.addEventListener(name, observer, useCapture);\n    } else if (element.attachEvent) {\n      this.observers.push([element, name, observer, useCapture]);\n      element.attachEvent('on' + name, observer);\n    }\n  },\n  \n  unloadCache: function() {\n    if (!Event.observers) return;\n    for (var i = 0; i < Event.observers.length; i++) {\n      Event.stopObserving.apply(this, Event.observers[i]);\n      Event.observers[i][0] = null;\n    }\n    Event.observers = false;\n  },\n\n  observe: function(element, name, observer, useCapture) {\n    var element = $(element);\n    useCapture = useCapture || false;\n    \n    if (name == 'keypress' &&\n        ((/Konqueror|Safari|KHTML/.test(navigator.userAgent)) \n        || element.attachEvent))\n      name = 'keydown';\n    \n    this._observeAndCache(element, name, observer, useCapture);\n  },\n\n  stopObserving: function(element, name, observer, useCapture) {\n    var element = $(element);\n    useCapture = useCapture || false;\n    \n    if (name == 'keypress' &&\n        ((/Konqueror|Safari|KHTML/.test(navigator.userAgent)) \n        || element.detachEvent))\n      name = 'keydown';\n    \n    if (element.removeEventListener) {\n      element.removeEventListener(name, observer, useCapture);\n    } else if (element.detachEvent) {\n      element.detachEvent('on' + name, observer);\n    }\n  }\n});\n\n/* prevent memory leaks in IE */\nEvent.observe(window, 'unload', Event.unloadCache, false);\n\nvar Position = {\n\n  // set to true if needed, warning: firefox performance problems\n  // NOT neeeded for page scrolling, only if draggable contained in\n  // scrollable elements\n  includeScrollOffsets: false, \n\n  // must be called before calling withinIncludingScrolloffset, every time the\n  // page is scrolled\n  prepare: function() {\n    this.deltaX =  window.pageXOffset \n                || document.documentElement.scrollLeft \n                || document.body.scrollLeft \n                || 0;\n    this.deltaY =  window.pageYOffset \n                || document.documentElement.scrollTop \n                || document.body.scrollTop \n                || 0;\n  },\n\n  realOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.scrollTop  || 0;\n      valueL += element.scrollLeft || 0; \n      element = element.parentNode;\n    } while (element);\n    return [valueL, valueT];\n  },\n\n  cumulativeOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n    } while (element);\n    return [valueL, valueT];\n  },\n\n  // caches x/y coordinate pair to use with overlap\n  within: function(element, x, y) {\n    if (this.includeScrollOffsets)\n      return this.withinIncludingScrolloffsets(element, x, y);\n    this.xcomp = x;\n    this.ycomp = y;\n    this.offset = this.cumulativeOffset(element);\n\n    return (y >= this.offset[1] &&\n            y <  this.offset[1] + element.offsetHeight &&\n            x >= this.offset[0] && \n            x <  this.offset[0] + element.offsetWidth);\n  },\n\n  withinIncludingScrolloffsets: function(element, x, y) {\n    var offsetcache = this.realOffset(element);\n\n    this.xcomp = x + offsetcache[0] - this.deltaX;\n    this.ycomp = y + offsetcache[1] - this.deltaY;\n    this.offset = this.cumulativeOffset(element);\n\n    return (this.ycomp >= this.offset[1] &&\n            this.ycomp <  this.offset[1] + element.offsetHeight &&\n            this.xcomp >= this.offset[0] && \n            this.xcomp <  this.offset[0] + element.offsetWidth);\n  },\n\n  // within must be called directly before\n  overlap: function(mode, element) {  \n    if (!mode) return 0;  \n    if (mode == 'vertical') \n      return ((this.offset[1] + element.offsetHeight) - this.ycomp) / \n        element.offsetHeight;\n    if (mode == 'horizontal')\n      return ((this.offset[0] + element.offsetWidth) - this.xcomp) / \n        element.offsetWidth;\n  },\n\n  clone: function(source, target) {\n    source = $(source);\n    target = $(target);\n    target.style.position = 'absolute';\n    var offsets = this.cumulativeOffset(source);\n    target.style.top    = offsets[1] + 'px';\n    target.style.left   = offsets[0] + 'px';\n    target.style.width  = source.offsetWidth + 'px';\n    target.style.height = source.offsetHeight + 'px';\n  }\n}\n"
  },
  {
    "path": "docs/skin/screen.css",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\nbody {  margin: 0px 0px 0px 0px; font-family: Verdana, Helvetica, sans-serif; }\n\nh1     { font-size : 160%; margin: 0px 0px 0px 0px;  padding: 0px; }\nh2     { font-size : 140%; margin: 1em 0px 0.8em 0px; padding: 0px; font-weight : bold;}\nh3     { font-size : 130%; margin: 0.8em 0px 0px 0px; padding: 0px; font-weight : bold; }\n.h3 { margin: 22px 0px 3px 0px; }\nh4     { font-size : 120%; margin: 0.7em 0px 0px 0px; padding: 0px; font-weight : normal; text-align: left; }\n.h4 { margin: 18px 0px 0px 0px; }\nh4.faq { font-size : 120%; margin: 18px 0px 0px 0px; padding: 0px; font-weight : bold;   text-align: left; }\nh5     { font-size : 100%; margin: 14px 0px 0px 0px; padding: 0px; font-weight : normal; text-align: left; }\n\n/**\n* table\n*/\ntable .title { background-color: #000000; }\n.ForrestTable         {\n    color: #ffffff;\n    background-color: #7099C5;\n    width: 100%;\n    font-size : 100%;\n    empty-cells: show;\n}\ntable caption {\n    padding-left: 5px;\n    color: white;\n    text-align: left;\n    font-weight: bold;\n    background-color: #000000;\n}\n.ForrestTable td {\n    color: black;\n    background-color: #f0f0ff;\n}\n.ForrestTable th { text-align: center; }\n/**\n * Page Header\n */\n\n#top {\n    position: relative;\n    float: left;\n    width: 100%;\n    background: #294563; /* if you want a background in the header, put it here */\n}\n\n#top .breadtrail {\n    background: #CFDCED;\n    color: black;\n    border-bottom: solid 1px white;\n    padding: 3px 10px;\n    font-size: 75%;\n}\n#top .breadtrail a { color: black; }\n\n#top .header {\n    float: left;\n    width: 100%;\n    background: url(\"images/header_white_line.gif\") repeat-x bottom;\n}\n\n#top .grouplogo {\n    padding: 7px 0 10px 10px;\n    float: left;\n    text-align: left;\n}\n#top .projectlogo {\n    padding: 7px 0 10px 10px;\n    float: left;\n    width: 33%;\n    text-align: right;\n}\n#top .projectlogoA1 {\n    padding: 7px 0 10px 10px;\n    float: right;\n}\nhtml>body #top .searchbox {\n    bottom: 0px;\n}\n#top .searchbox {\n    position: absolute;\n    right: 10px;\n    height: 42px;\n    font-size: 70%;\n    white-space: nowrap;\n    text-align: right;\n    color: white;\n    background-color: #000000;\n    z-index:0;\n    background-image: url(images/rc-t-l-5-1header-2searchbox-3searchbox.png);\n    background-repeat: no-repeat;\n    background-position: top left;\n    bottom: -1px; /* compensate for IE rendering issue */\n}\n\n#top .searchbox form {\n    padding: 5px 10px;\n    margin: 0;\n}\n#top .searchbox p {\n    padding: 0 0 2px 0;\n    margin: 0;\n}\n#top .searchbox input {\n    font-size: 100%;\n}\n\n#tabs {\n    clear: both;\n    padding-left: 10px;\n    margin: 0;\n    list-style: none;\n}\n/*    background: #CFDCED url(\"images/tab-right.gif\") no-repeat right top;*/\n#tabs li {\n    float: left;\n    background-image: url(images/rc-t-r-5-1header-2tab-unselected-3tab-unselected.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n    background-color: #000000;\n    margin: 0 3px 0 0;\n    padding: 0;\n}\n\n/*background: url(\"images/tab-left.gif\") no-repeat left top;*/\n#tabs li a {\n    float: left;\n    display: block;\n    font-family: verdana, arial, sans-serif;\n    text-decoration: none;\n    color: black;\n    white-space: nowrap;\n    background-image: url(images/rc-t-l-5-1header-2tab-unselected-3tab-unselected.png);\n    background-repeat: no-repeat;\n    background-position: top left;\n    padding: 5px 15px 4px;\n    width: .1em; /* IE/Win fix */\n}\n\n#tabs li a:hover {\n   \n    cursor: pointer;\n    text-decoration:underline;\n}\n\n#tabs > li a { width: auto; } /* Rest of IE/Win fix */\n\n/* Commented Backslash Hack hides rule from IE5-Mac \\*/\n#tabs a { float: none; }\n/* End IE5-Mac hack */\n\n#top .header .current {\n    background-color: #4C6C8F;\n    background-image: url(images/rc-t-r-5-1header-2tab-selected-3tab-selected.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n}\n#top .header .current a {\n    font-weight: bold;\n    padding-bottom: 5px;\n    color: white;\n    background-image: url(images/rc-t-l-5-1header-2tab-selected-3tab-selected.png);\n    background-repeat: no-repeat;\n    background-position: top left;\n}\n#publishedStrip {\n    padding-right: 10px;\n    padding-left: 20px;\n    padding-top: 3px;\n    padding-bottom:3px;\n    color: #ffffff;\n    font-size : 60%;\n    font-weight: bold;\n    background-color: #4C6C8F;\n    text-align:right;\n}\n\n#level2tabs {\nmargin: 0;\nfloat:left;\nposition:relative;\n\n}\n\n\n\n#level2tabs  a:hover {\n   \n    cursor: pointer;\n    text-decoration:underline;\n    \n}\n\n#level2tabs  a{\n   \n    cursor: pointer;\n    text-decoration:none;\n    background-image: url('images/chapter.gif');\n    background-repeat: no-repeat;\n    background-position: center left;\n    padding-left: 6px;\n    margin-left: 6px;\n}\n\n/*\n*    border-top: solid #4C6C8F 15px;\n*/\n#main {\n    position: relative;\n    background: white;\n    clear:both;\n}\n#main .breadtrail {\n    clear:both;\n    position: relative;\n    background: #CFDCED;\n    color: black;\n    border-bottom: solid 1px black;\n    border-top: solid 1px black;\n    padding: 0px 180px;\n    font-size: 75%;\n    z-index:10;\n}\n/**\n* Round corner\n*/\n#roundtop {\n    background-image: url(images/rc-t-r-15-1body-2menu-3menu.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n}\n\n#roundbottom {\n    background-image: url(images/rc-b-r-15-1body-2menu-3menu.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n}\n\nimg.corner {\n   width: 15px;\n   height: 15px;\n   border: none;\n   display: block !important;\n}\n\n.roundtopsmall {\n    background-image: url(images/rc-t-r-5-1header-2searchbox-3searchbox.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n}\n\n#roundbottomsmall {\n    background-image: url(images/rc-b-r-5-1header-2tab-selected-3tab-selected.png);\n    background-repeat: no-repeat;\n    background-position: top right;\n}\n\nimg.cornersmall {\n   width: 5px;\n   height: 5px;\n   border: none;\n   display: block !important;\n}\n/**\n * Side menu\n */\n#menu a {  font-weight: normal; text-decoration: none;}\n#menu a:visited {  font-weight: normal; }\n#menu a:active {  font-weight: normal; }\n#menu a:hover {  font-weight: normal;  text-decoration:underline;}\n\n#menuarea { width:10em;}\n#menu {\n    position: relative;\n    float: left;\n    width: 160px;\n    padding-top: 0px;\n    top:-18px;\n    left:10px;\n    z-index: 20;\n    background-color: #f90;\n    font-size : 70%;\n    \n}\n\n.menutitle {\n        cursor:pointer;\n        padding: 3px 12px;\n        margin-left: 10px;\n        background-image: url('images/chapter.gif');\n        background-repeat: no-repeat;\n        background-position: center left;\n        font-weight : bold;\n\n        \n}\n\n.menutitle:hover{text-decoration:underline;cursor: pointer;}\n\n#menu .menuitemgroup {\n        margin: 0px 0px 6px 8px;\n        padding: 0px;\n        font-weight : bold; }\n\n#menu .selectedmenuitemgroup{\n        margin: 0px 0px 0px 8px;\n        padding: 0px;\n        font-weight : normal; \n       \n        }\n\n#menu .menuitem {\n        padding: 2px 0px 1px 13px;\n        background-image: url('images/page.gif');\n        background-repeat: no-repeat;\n        background-position: center left;\n        font-weight : normal;\n        margin-left: 10px;\n}\n\n#menu .menupage {\n        margin: 2px 0px 1px 10px;\n        padding: 0px 3px 0px 12px;\n        background-image: url('images/page.gif');\n        background-repeat: no-repeat;\n        background-position: center left;\n        font-style : normal;\n}\n#menu .menupagetitle {\n        padding: 0px 0px 0px 1px;\n        font-style : normal;\n        border-style: solid;\n        border-width: 1px;\n        margin-right: 10px;\n         \n}\n#menu .menupageitemgroup {\n        padding: 3px 0px 4px 6px;\n        font-style : normal;\n        border-bottom: 1px solid ;\n        border-left: 1px solid ;\n        border-right: 1px solid ;\n        margin-right: 10px;\n}\n#menu .menupageitem {\n        font-style : normal;\n        font-weight : normal;\n        border-width: 0px;\n        font-size : 90%;\n}\n#menu #credit {\n    text-align: center;\n}\n#menu #credit2 {\n    text-align: center;\n    padding: 3px 3px 3px 3px;\n    background-color: #ffffff;\n}\n#menu .searchbox {\n    text-align: center;\n}\n#menu .searchbox form {\n    padding: 3px 3px;\n    margin: 0;\n}\n#menu .searchbox input {\n    font-size: 100%;\n}\n\n#content {\n    padding: 20px 20px 20px 180px;\n    margin: 0;\n    font : small Verdana, Helvetica, sans-serif;\n    font-size : 80%;\n}\n\n#content ul {\n    margin: 0;\n    padding: 0 25px;\n}\n#content li {\n    padding: 0 5px;\n}\n#feedback {\n    color: black;\n    background: #CFDCED;\n    text-align:center;\n    margin-top: 5px;\n}\n#feedback #feedbackto {\n    font-size: 90%;\n    color: black;\n}\n#footer {\n    clear: both;\n    position: relative; /* IE bugfix (http://www.dracos.co.uk/web/css/ie6floatbug/) */\n    width: 100%;\n    background: #CFDCED;\n    border-top: solid 1px #4C6C8F;\n    color: black;\n}\n#footer .copyright {\n    position: relative; /* IE bugfix cont'd */\n    padding: 5px;\n    margin: 0;\n    width: 60%;\n}\n#footer .lastmodified {\n    position: relative; /* IE bugfix cont'd */\n    float: right;\n    width: 30%;\n    padding: 5px;\n    margin: 0;\n    text-align: right;\n}\n#footer a { color: white; }\n\n#footer #logos {\n    text-align: left;\n}\n\n\n/**\n * Misc Styles\n */\n\nacronym { cursor: help; }\n.boxed      { background-color: #a5b6c6;}\n.underlined_5     {border-bottom: solid 5px #4C6C8F;}\n.underlined_10     {border-bottom: solid 10px #4C6C8F;}\n/* ==================== snail trail ============================ */\n\n.trail {\n  position: relative; /* IE bugfix cont'd */\n  font-size: 70%;\n  text-align: right;\n  float: right;\n  margin: -10px 5px 0px 5px;\n  padding: 0;\n}\n\n#motd-area {\n    position:relative;\n    float:right;\n    width: 35%;\n    background-color: #f0f0ff;\n    border: solid 1px #4C6C8F;\n    margin: 0px 0px 10px 10px;\n    padding: 5px;\n}\n\n#minitoc-area {\n    border-top: solid 1px #4C6C8F;\n    border-bottom: solid 1px #4C6C8F;\n    margin: 15px 10% 5px 15px;\n   /* margin-bottom: 15px;\n    margin-left: 15px;\n    margin-right: 10%;*/\n    padding-bottom: 7px;\n    padding-top: 5px;\n}\n.minitoc {\n    list-style-image: url('images/current.gif');\n    font-weight: normal;\n}\n\n.abstract{\n    text-align:justify;\n    }\n\nli p {\n    margin: 0;\n    padding: 0;\n}\n\n.pdflink {\n    position: relative; /* IE bugfix cont'd */\n    float: right;\n    margin: 0px 5px;\n    padding: 0;\n}\n.pdflink br {\n    margin-top: -10px;\n    padding-left: 1px;\n}\n.pdflink a {\n    display: block;\n    font-size: 70%;\n    text-align: center;\n    margin: 0;\n    padding: 0;\n}\n\n.pdflink img {\n    display: block;\n    height: 16px;\n    width: 16px;\n}\n.xmllink {\n    position: relative; /* IE bugfix cont'd */\n    float: right;\n    margin: 0px 5px;\n    padding: 0;\n}\n.xmllink br {\n    margin-top: -10px;\n    padding-left: 1px;\n}\n.xmllink a {\n    display: block;\n    font-size: 70%;\n    text-align: center;\n    margin: 0;\n    padding: 0;\n}\n\n.xmllink img {\n    display: block;\n    height: 16px;\n    width: 16px;\n}\n.podlink {\n    position: relative; /* IE bugfix cont'd */\n    float: right;\n    margin: 0px 5px;\n    padding: 0;\n}\n.podlink br {\n    margin-top: -10px;\n    padding-left: 1px;\n}\n.podlink a {\n    display: block;\n    font-size: 70%;\n    text-align: center;\n    margin: 0;\n    padding: 0;\n}\n\n.podlink img {\n    display: block;\n    height: 16px;\n    width: 16px;\n}\n\n.printlink {\n    position: relative; /* IE bugfix cont'd */\n    float: right;\n}\n.printlink br {\n    margin-top: -10px;\n    padding-left: 1px;\n}\n.printlink a {\n    display: block;\n    font-size: 70%;\n    text-align: center;\n    margin: 0;\n    padding: 0;\n}\n.printlink img {\n    display: block;\n    height: 16px;\n    width: 16px;\n}\n\np.instruction {\n  display: list-item;\n  list-style-image: url('../images/instruction_arrow.png');\n  list-style-position: outside;\n  margin-left: 2em;\n} "
  },
  {
    "path": "docs/zookeeperAdmin.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Administrator's Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.4', 'skin/')\" id=\"menu_selected_1.4Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Admin &amp; Ops</div>\n<div id=\"menu_selected_1.4\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Administrator's Guide</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperAdmin.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Administrator's Guide</h1>\n<h3>A Guide to Deployment and Administration</h3>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_deployment\">Deployment</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_systemReq\">System Requirements</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_supportedPlatforms\">Supported Platforms</a>\n</li>\n<li>\n<a href=\"#sc_requiredSoftware\">Required Software </a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_zkMulitServerSetup\">Clustered (Multi-Server) Setup</a>\n</li>\n<li>\n<a href=\"#sc_singleAndDevSetup\">Single Server and Developer Setup</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#ch_administration\">Administration</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_designing\">Designing a ZooKeeper Deployment</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_CrossMachineRequirements\">Cross Machine Requirements</a>\n</li>\n<li>\n<a href=\"#Single+Machine+Requirements\">Single Machine Requirements</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_provisioning\">Provisioning</a>\n</li>\n<li>\n<a href=\"#sc_strengthsAndLimitations\">Things to Consider: ZooKeeper Strengths and Limitations</a>\n</li>\n<li>\n<a href=\"#sc_administering\">Administering</a>\n</li>\n<li>\n<a href=\"#sc_maintenance\">Maintenance</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Ongoing+Data+Directory+Cleanup\">Ongoing Data Directory Cleanup</a>\n</li>\n<li>\n<a href=\"#Debug+Log+Cleanup+%28log4j%29\">Debug Log Cleanup (log4j)</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_supervision\">Supervision</a>\n</li>\n<li>\n<a href=\"#sc_monitoring\">Monitoring</a>\n</li>\n<li>\n<a href=\"#sc_logging\">Logging</a>\n</li>\n<li>\n<a href=\"#sc_troubleshooting\">Troubleshooting</a>\n</li>\n<li>\n<a href=\"#sc_configuration\">Configuration Parameters</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_minimumConfiguration\">Minimum Configuration</a>\n</li>\n<li>\n<a href=\"#sc_advancedConfiguration\">Advanced Configuration</a>\n</li>\n<li>\n<a href=\"#sc_clusterOptions\">Cluster Options</a>\n</li>\n<li>\n<a href=\"#sc_authOptions\">Authentication &amp; Authorization Options</a>\n</li>\n<li>\n<a href=\"#Experimental+Options%2FFeatures\">Experimental Options/Features</a>\n</li>\n<li>\n<a href=\"#Unsafe+Options\">Unsafe Options</a>\n</li>\n<li>\n<a href=\"#Communication+using+the+Netty+framework\">Communication using the Netty framework</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_zkCommands\">ZooKeeper Commands: The Four Letter Words</a>\n</li>\n<li>\n<a href=\"#sc_dataFileManagement\">Data File Management</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#The+Data+Directory\">The Data Directory</a>\n</li>\n<li>\n<a href=\"#The+Log+Directory\">The Log Directory</a>\n</li>\n<li>\n<a href=\"#sc_filemanagement\">File Management</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_commonProblems\">Things to Avoid</a>\n</li>\n<li>\n<a href=\"#sc_bestPractices\">Best Practices</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n\n  \n<a name=\"ch_deployment\"></a>\n<h2 class=\"h3\">Deployment</h2>\n<div class=\"section\">\n<p>This section contains information about deploying Zookeeper and\n    covers these topics:</p>\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#sc_systemReq\">System Requirements</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#sc_zkMulitServerSetup\">Clustered (Multi-Server) Setup</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#sc_singleAndDevSetup\">Single Server and Developer Setup</a>\n</p>\n      \n</li>\n    \n</ul>\n<p>The first two sections assume you are interested in installing\n    ZooKeeper in a production environment such as a datacenter. The final\n    section covers situations in which you are setting up ZooKeeper on a\n    limited basis - for evaluation, testing, or development - but not in a\n    production environment.</p>\n<a name=\"sc_systemReq\"></a>\n<h3 class=\"h4\">System Requirements</h3>\n<a name=\"sc_supportedPlatforms\"></a>\n<h4>Supported Platforms</h4>\n<p>ZooKeeper consists of multiple components. Some components are\n        supported broadly, and other components are supported only on a smaller\n        set of platforms.</p>\n<ul>\n          \n<li>\n            \n<p>\n<strong>Client</strong> is the Java client\n            library, used by applications to connect to a ZooKeeper ensemble.\n            </p>\n          \n</li>\n          \n<li>\n            \n<p>\n<strong>Server</strong> is the Java server\n            that runs on the ZooKeeper ensemble nodes.</p>\n          \n</li>\n          \n<li>\n            \n<p>\n<strong>Native Client</strong> is a client\n            implemented in C, similar to the Java client, used by applications\n            to connect to a ZooKeeper ensemble.</p>\n          \n</li>\n          \n<li>\n            \n<p>\n<strong>Contrib</strong> refers to multiple\n            optional add-on components.</p>\n          \n</li>\n        \n</ul>\n<p>The following matrix describes the level of support committed for\n        running each component on different operating system platforms.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<caption>Support Matrix</caption>\n          \n<title>Support Matrix</title>\n          \n              \n<tr>\n                \n<th>Operating System</th>\n                <th>Client</th>\n                <th>Server</th>\n                <th>Native Client</th>\n                <th>Contrib</th>\n              \n</tr>\n            \n              \n<tr>\n                \n<td>GNU/Linux</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n              \n</tr>\n              \n<tr>\n                \n<td>Solaris</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n                <td>Not Supported</td>\n                <td>Not Supported</td>\n              \n</tr>\n              \n<tr>\n                \n<td>FreeBSD</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n                <td>Not Supported</td>\n                <td>Not Supported</td>\n              \n</tr>\n              \n<tr>\n                \n<td>Windows</td>\n                <td>Development and Production</td>\n                <td>Development and Production</td>\n                <td>Not Supported</td>\n                <td>Not Supported</td>\n              \n</tr>\n              \n<tr>\n                \n<td>Mac OS X</td>\n                <td>Development Only</td>\n                <td>Development Only</td>\n                <td>Not Supported</td>\n                <td>Not Supported</td>\n              \n</tr>\n            \n        \n</table>\n<p>For any operating system not explicitly mentioned as supported in\n        the matrix, components may or may not work.  The ZooKeeper community\n        will fix obvious bugs that are reported for other platforms, but there\n        is no full support.</p>\n<a name=\"sc_requiredSoftware\"></a>\n<h4>Required Software </h4>\n<p>ZooKeeper runs in Java, release 1.6 or greater (JDK 6 or\n          greater).  It runs as an <em>ensemble</em> of\n          ZooKeeper servers. Three ZooKeeper servers is the minimum\n          recommended size for an ensemble, and we also recommend that\n          they run on separate machines. At Yahoo!, ZooKeeper is\n          usually deployed on dedicated RHEL boxes, with dual-core\n          processors, 2GB of RAM, and 80GB IDE hard drives.</p>\n<a name=\"sc_zkMulitServerSetup\"></a>\n<h3 class=\"h4\">Clustered (Multi-Server) Setup</h3>\n<p>For reliable ZooKeeper service, you should deploy ZooKeeper in a\n      cluster known as an <em>ensemble</em>. As long as a majority\n      of the ensemble are up, the service will be available. Because Zookeeper\n      requires a majority, it is best to use an\n      odd number of machines. For example, with four machines ZooKeeper can\n      only handle the failure of a single machine; if two machines fail, the\n      remaining two machines do not constitute a majority. However, with five\n      machines ZooKeeper can handle the failure of two machines. </p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n         \n<p>\n            As mentioned in the\n            <a href=\"zookeeperStarted.html\">ZooKeeper Getting Started Guide</a>\n            , a minimum of three servers are required for a fault tolerant\n            clustered setup, and it is strongly recommended that you have an\n            odd number of servers.\n         </p>\n         \n<p>Usually three servers is more than enough for a production\n            install, but for maximum reliability during maintenance, you may\n            wish to install five servers. With three servers, if you perform\n            maintenance on one of them, you are vulnerable to a failure on one\n            of the other two servers during that maintenance. If you have five\n            of them running, you can take one down for maintenance, and know\n            that you're still OK if one of the other four suddenly fails.\n         </p>\n         \n<p>Your redundancy considerations should include all aspects of\n            your environment. If you have three ZooKeeper servers, but their\n            network cables are all plugged into the same network switch, then\n            the failure of that switch will take down your entire ensemble.\n         </p>\n      \n</div>\n</div>\n<p>Here are the steps to setting a server that will be part of an\n      ensemble. These steps should be performed on every host in the\n      ensemble:</p>\n<ol>\n        \n<li>\n          \n<p>Install the Java JDK. You can use the native packaging system\n          for your system, or download the JDK from:</p>\n\n          \n<p>\n<a href=\"http://java.sun.com/javase/downloads/index.jsp\">http://java.sun.com/javase/downloads/index.jsp</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Set the Java heap size. This is very important to avoid\n          swapping, which will seriously degrade ZooKeeper performance. To\n          determine the correct value, use load tests, and make sure you are\n          well below the usage limit that would cause you to swap. Be\n          conservative - use a maximum heap size of 3GB for a 4GB\n          machine.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Install the ZooKeeper Server Package. It can be downloaded\n            from:\n          </p>\n          \n<p>\n            \n<a href=\"http://zookeeper.apache.org/releases.html\">\n              http://zookeeper.apache.org/releases.html\n            </a>\n          \n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Create a configuration file. This file can be called anything.\n          Use the following settings as a starting point:</p>\n\n          \n<pre class=\"code\">\ntickTime=2000\ndataDir=/var/lib/zookeeper/\nclientPort=2181\ninitLimit=5\nsyncLimit=2\nserver.1=zoo1:2888:3888\nserver.2=zoo2:2888:3888\nserver.3=zoo3:2888:3888</pre>\n\n          \n<p>You can find the meanings of these and other configuration\n          settings in the section <a href=\"#sc_configuration\">Configuration Parameters</a>. A word\n          though about a few here:</p>\n\n          \n<p>Every machine that is part of the ZooKeeper ensemble should know\n          about every other machine in the ensemble. You accomplish this with\n          the series of lines of the form <strong>server.id=host:port:port</strong>. The parameters <strong>host</strong> and <strong>port</strong> are straightforward. You attribute the\n          server id to each machine by creating a file named\n          <span class=\"codefrag filename\">myid</span>, one for each server, which resides in\n          that server's data directory, as specified by the configuration file\n          parameter <strong>dataDir</strong>.</p>\n</li>\n\n          \n<li>\n<p>The myid file\n          consists of a single line containing only the text of that machine's\n          id. So <span class=\"codefrag filename\">myid</span> of server 1 would contain the text\n          \"1\" and nothing else. The id must be unique within the\n          ensemble and should have a value between 1 and 255.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>If your configuration file is set up, you can start a\n          ZooKeeper server:</p>\n\n          \n<p>\n<span class=\"codefrag computeroutput\">$ java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf \\\n              org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg\n          </span>\n</p>\n          \n          \n<p>QuorumPeerMain starts a ZooKeeper server,\n            <a href=\"http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/\">JMX</a>\n            management beans are also registered which allows\n            management through a JMX management console. \n            The <a href=\"zookeeperJMX.html\">ZooKeeper JMX\n            document</a> contains details on managing ZooKeeper with JMX.\n          </p>\n\n          \n<p>See the script <em>bin/zkServer.sh</em>,\n            which is included in the release, for an example\n            of starting server instances.</p>\n\n        \n</li>\n\n        \n<li>\n          \n<p>Test your deployment by connecting to the hosts:</p>\n\n          \n<p>In Java, you can run the following command to execute\n          simple operations:</p>\n\n          \n<p>\n<span class=\"codefrag computeroutput\">$ bin/zkCli.sh -server 127.0.0.1:2181</span>\n</p>\n        \n</li>\n      \n</ol>\n<a name=\"sc_singleAndDevSetup\"></a>\n<h3 class=\"h4\">Single Server and Developer Setup</h3>\n<p>If you want to setup ZooKeeper for development purposes, you will\n      probably want to setup a single server instance of ZooKeeper, and then\n      install either the Java or C client-side libraries and bindings on your\n      development machine.</p>\n<p>The steps to setting up a single server instance are the similar\n      to the above, except the configuration file is simpler. You can find the\n      complete instructions in the <a href=\"zookeeperStarted.html#sc_InstallingSingleMode\">Installing and\n      Running ZooKeeper in Single Server Mode</a> section of the <a href=\"zookeeperStarted.html\">ZooKeeper Getting Started\n      Guide</a>.</p>\n<p>For information on installing the client side libraries, refer to\n      the <a href=\"zookeeperProgrammers.html#Bindings\">Bindings</a>\n      section of the <a href=\"zookeeperProgrammers.html\">ZooKeeper\n      Programmer's Guide</a>.</p>\n</div>\n\n  \n<a name=\"ch_administration\"></a>\n<h2 class=\"h3\">Administration</h2>\n<div class=\"section\">\n<p>This section contains information about running and maintaining\n    ZooKeeper and covers these topics: </p>\n<ul>\n        \n<li>\n          \n<p>\n<a href=\"#sc_designing\">Designing a ZooKeeper Deployment</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_provisioning\">Provisioning</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_strengthsAndLimitations\">Things to Consider: ZooKeeper Strengths and Limitations</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_administering\">Administering</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_maintenance\">Maintenance</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_supervision\">Supervision</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_monitoring\">Monitoring</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_logging\">Logging</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_troubleshooting\">Troubleshooting</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_configuration\">Configuration Parameters</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_zkCommands\">ZooKeeper Commands: The Four Letter Words</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_dataFileManagement\">Data File Management</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_commonProblems\">Things to Avoid</a>\n</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<a href=\"#sc_bestPractices\">Best Practices</a>\n</p>\n        \n</li>\n      \n</ul>\n<a name=\"sc_designing\"></a>\n<h3 class=\"h4\">Designing a ZooKeeper Deployment</h3>\n<p>The reliablity of ZooKeeper rests on two basic assumptions.</p>\n<ol>\n        \n<li>\n<p> Only a minority of servers in a deployment\n            will fail. <em>Failure</em> in this context\n            means a machine crash, or some error in the network that\n            partitions a server off from the majority.</p>\n        \n</li>\n        \n<li>\n<p> Deployed machines operate correctly. To\n            operate correctly means to execute code correctly, to have\n            clocks that work properly, and to have storage and network\n            components that perform consistently.</p>\n        \n</li>\n      \n</ol>\n<p>The sections below contain considerations for ZooKeeper\n      administrators to maximize the probability for these assumptions\n      to hold true. Some of these are cross-machines considerations,\n      and others are things you should consider for each and every\n      machine in your deployment.</p>\n<a name=\"sc_CrossMachineRequirements\"></a>\n<h4>Cross Machine Requirements</h4>\n<p>For the ZooKeeper service to be active, there must be a\n        majority of non-failing machines that can communicate with\n        each other. To create a deployment that can tolerate the\n        failure of F machines, you should count on deploying 2xF+1\n        machines.  Thus, a deployment that consists of three machines\n        can handle one failure, and a deployment of five machines can\n        handle two failures. Note that a deployment of six machines\n        can only handle two failures since three machines is not a\n        majority.  For this reason, ZooKeeper deployments are usually\n        made up of an odd number of machines.</p>\n<p>To achieve the highest probability of tolerating a failure\n        you should try to make machine failures independent. For\n        example, if most of the machines share the same switch,\n        failure of that switch could cause a correlated failure and\n        bring down the service. The same holds true of shared power\n        circuits, cooling systems, etc.</p>\n<a name=\"Single+Machine+Requirements\"></a>\n<h4>Single Machine Requirements</h4>\n<p>If ZooKeeper has to contend with other applications for\n        access to resourses like storage media, CPU, network, or\n        memory, its performance will suffer markedly.  ZooKeeper has\n        strong durability guarantees, which means it uses storage\n        media to log changes before the operation responsible for the\n        change is allowed to complete. You should be aware of this\n        dependency then, and take great care if you want to ensure\n        that ZooKeeper operations aren&rsquo;t held up by your media. Here\n        are some things you can do to minimize that sort of\n        degradation:\n      </p>\n<ul>\n        \n<li>\n          \n<p>ZooKeeper's transaction log must be on a dedicated\n            device. (A dedicated partition is not enough.) ZooKeeper\n            writes the log sequentially, without seeking Sharing your\n            log device with other processes can cause seeks and\n            contention, which in turn can cause multi-second\n            delays.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Do not put ZooKeeper in a situation that can cause a\n            swap. In order for ZooKeeper to function with any sort of\n            timeliness, it simply cannot be allowed to swap.\n            Therefore, make certain that the maximum heap size given\n            to ZooKeeper is not bigger than the amount of real memory\n            available to ZooKeeper.  For more on this, see\n            <a href=\"#sc_commonProblems\">Things to Avoid</a>\n            below. </p>\n        \n</li>\n      \n</ul>\n<a name=\"sc_provisioning\"></a>\n<h3 class=\"h4\">Provisioning</h3>\n<p></p>\n<a name=\"sc_strengthsAndLimitations\"></a>\n<h3 class=\"h4\">Things to Consider: ZooKeeper Strengths and Limitations</h3>\n<p></p>\n<a name=\"sc_administering\"></a>\n<h3 class=\"h4\">Administering</h3>\n<p></p>\n<a name=\"sc_maintenance\"></a>\n<h3 class=\"h4\">Maintenance</h3>\n<p>Little long term maintenance is required for a ZooKeeper\n        cluster however you must be aware of the following:</p>\n<a name=\"Ongoing+Data+Directory+Cleanup\"></a>\n<h4>Ongoing Data Directory Cleanup</h4>\n<p>The ZooKeeper <a href=\"#var_datadir\">Data\n          Directory</a> contains files which are a persistent copy\n          of the znodes stored by a particular serving ensemble. These\n          are the snapshot and transactional log files. As changes are\n          made to the znodes these changes are appended to a\n          transaction log. Occasionally, when a log grows large, a\n          snapshot of the current state of all znodes will be written\n          to the filesystem and a new transaction log file is created\n          for future transactions. During snapshotting, ZooKeeper may\n          continue appending incoming transactions to the old log file.\n          Therefore, some transactions which are newer than a snapshot\n          may be found in the last transaction log preceding the\n          snapshot.\n        </p>\n<p>A ZooKeeper server <strong>will not remove\n        old snapshots and log files</strong> when using the default\n        configuration (see autopurge below), this is the\n        responsibility of the operator. Every serving environment is\n        different and therefore the requirements of managing these\n        files may differ from install to install (backup for example).\n        </p>\n<p>The PurgeTxnLog utility implements a simple retention\n        policy that administrators can use. The <a href=\"api/index.html\">API docs</a> contains details on\n        calling conventions (arguments, etc...).\n        </p>\n<p>In the following example the last count snapshots and\n        their corresponding logs are retained and the others are\n        deleted.  The value of &lt;count&gt; should typically be\n        greater than 3 (although not required, this provides 3 backups\n        in the unlikely event a recent log has become corrupted). This\n        can be run as a cron job on the ZooKeeper server machines to\n        clean up the logs daily.</p>\n<pre class=\"code\"> java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.PurgeTxnLog &lt;dataDir&gt; &lt;snapDir&gt; -n &lt;count&gt;</pre>\n<p>Automatic purging of the snapshots and corresponding\n        transaction logs was introduced in version 3.4.0 and can be\n        enabled via the following configuration parameters <strong>autopurge.snapRetainCount</strong> and <strong>autopurge.purgeInterval</strong>. For more on\n        this, see <a href=\"#sc_advancedConfiguration\">Advanced Configuration</a>\n        below.</p>\n<a name=\"Debug+Log+Cleanup+%28log4j%29\"></a>\n<h4>Debug Log Cleanup (log4j)</h4>\n<p>See the section on <a href=\"#sc_logging\">logging</a> in this document. It is\n        expected that you will setup a rolling file appender using the\n        in-built log4j feature. The sample configuration file in the\n        release tar's conf/log4j.properties provides an example of\n        this.\n        </p>\n<a name=\"sc_supervision\"></a>\n<h3 class=\"h4\">Supervision</h3>\n<p>You will want to have a supervisory process that manages\n      each of your ZooKeeper server processes (JVM). The ZK server is\n      designed to be \"fail fast\" meaning that it will shutdown\n      (process exit) if an error occurs that it cannot recover\n      from. As a ZooKeeper serving cluster is highly reliable, this\n      means that while the server may go down the cluster as a whole\n      is still active and serving requests. Additionally, as the\n      cluster is \"self healing\" the failed server once restarted will\n      automatically rejoin the ensemble w/o any manual\n      interaction.</p>\n<p>Having a supervisory process such as <a href=\"http://cr.yp.to/daemontools.html\">daemontools</a> or\n      <a href=\"http://en.wikipedia.org/wiki/Service_Management_Facility\">SMF</a>\n      (other options for supervisory process are also available, it's\n      up to you which one you would like to use, these are just two\n      examples) managing your ZooKeeper server ensures that if the\n      process does exit abnormally it will automatically be restarted\n      and will quickly rejoin the cluster.</p>\n<a name=\"sc_monitoring\"></a>\n<h3 class=\"h4\">Monitoring</h3>\n<p>The ZooKeeper service can be monitored in one of two\n      primary ways; 1) the command port through the use of <a href=\"#sc_zkCommands\">4 letter words</a> and 2) <a href=\"zookeeperJMX.html\">JMX</a>. See the appropriate section for\n      your environment/requirements.</p>\n<a name=\"sc_logging\"></a>\n<h3 class=\"h4\">Logging</h3>\n<p>ZooKeeper uses <strong>log4j</strong> version 1.2 as \n      its logging infrastructure. The  ZooKeeper default <span class=\"codefrag filename\">log4j.properties</span> \n      file resides in the <span class=\"codefrag filename\">conf</span> directory. Log4j requires that \n      <span class=\"codefrag filename\">log4j.properties</span> either be in the working directory \n      (the directory from which ZooKeeper is run) or be accessible from the classpath.</p>\n<p>For more information, see \n      <a href=\"http://logging.apache.org/log4j/1.2/manual.html#defaultInit\">Log4j Default Initialization Procedure</a> \n      of the log4j manual.</p>\n<a name=\"sc_troubleshooting\"></a>\n<h3 class=\"h4\">Troubleshooting</h3>\n<dl>\n\t\t\n<dt>\n<term> Server not coming up because of file corruption</term>\n</dt>\n<dd>\n<p>A server might not be able to read its database and fail to come up because of \n\t\tsome file corruption in the transaction logs of the ZooKeeper server. You will\n\t\tsee some IOException on loading ZooKeeper database. In such a case,\n\t\tmake sure all the other servers in your ensemble are up and  working. Use \"stat\" \n\t\tcommand on the command port to see if they are in good health. After you have verified that\n\t\tall the other servers of the ensemble are up, you can go ahead and clean the database\n\t\tof the corrupt server. Delete all the files in datadir/version-2 and datalogdir/version-2/.\n\t\tRestart the server.\n\t\t</p>\n</dd>\n\t\t\n</dl>\n<a name=\"sc_configuration\"></a>\n<h3 class=\"h4\">Configuration Parameters</h3>\n<p>ZooKeeper's behavior is governed by the ZooKeeper configuration\n      file. This file is designed so that the exact same file can be used by\n      all the servers that make up a ZooKeeper server assuming the disk\n      layouts are the same. If servers use different configuration files, care\n      must be taken to ensure that the list of servers in all of the different\n      configuration files match.</p>\n<a name=\"sc_minimumConfiguration\"></a>\n<h4>Minimum Configuration</h4>\n<p>Here are the minimum configuration keywords that must be defined\n        in the configuration file:</p>\n<dl>\n          \n<dt>\n<term>clientPort</term>\n</dt>\n<dd>\n<p>the port to listen for client connections; that is, the\n              port that clients attempt to connect to.</p>\n</dd>\n\n          \n<dt>\n<term>dataDir</term>\n</dt>\n<dd>\n<p>the location where ZooKeeper will store the in-memory\n              database snapshots and, unless specified otherwise, the\n              transaction log of updates to the database.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n                \n<p>Be careful where you put the transaction log. A\n                dedicated transaction log device is key to consistent good\n                performance. Putting the log on a busy device will adversely\n                effect performance.</p>\n              \n</div>\n</div>\n</dd>\n\n          \n<dt>\n<term>tickTime</term>\n</dt>\n<dd>\n<p>the length of a single tick, which is the basic time unit\n              used by ZooKeeper, as measured in milliseconds. It is used to\n              regulate heartbeats, and timeouts. For example, the minimum\n              session timeout will be two ticks.</p>\n</dd>\n        \n</dl>\n<a name=\"sc_advancedConfiguration\"></a>\n<h4>Advanced Configuration</h4>\n<p>The configuration settings in the section are optional. You can\n        use them to further fine tune the behaviour of your ZooKeeper servers.\n        Some can also be set using Java system properties, generally of the\n        form <em>zookeeper.keyword</em>. The exact system\n        property, when available, is noted below.</p>\n<dl>\n          \n<dt>\n<term>dataLogDir</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>This option will direct the machine to write the\n              transaction log to the <strong>dataLogDir</strong> rather than the <strong>dataDir</strong>. This allows a dedicated log\n              device to be used, and helps avoid competition between logging\n              and snaphots.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n                \n<p>Having a dedicated log device has a large impact on\n                throughput and stable latencies. It is highly recommened to\n                dedicate a log device and set <strong>dataLogDir</strong> to point to a directory on\n                that device, and then make sure to point <strong>dataDir</strong> to a directory\n                <em>not</em> residing on that device.</p>\n              \n</div>\n</div>\n</dd>\n\n          \n<dt>\n<term>globalOutstandingLimit</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.globalOutstandingLimit.</strong>)</p>\n<p>Clients can submit requests faster than ZooKeeper can\n              process them, especially if there are a lot of clients. To\n              prevent ZooKeeper from running out of memory due to queued\n              requests, ZooKeeper will throttle clients so that there is no\n              more than globalOutstandingLimit outstanding requests in the\n              system. The default limit is 1,000.</p>\n</dd>\n\n          \n<dt>\n<term>preAllocSize</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.preAllocSize</strong>)</p>\n<p>To avoid seeks ZooKeeper allocates space in the\n              transaction log file in blocks of preAllocSize kilobytes. The\n              default block size is 64M. One reason for changing the size of\n              the blocks is to reduce the block size if snapshots are taken\n              more often. (Also, see <strong>snapCount</strong>).</p>\n</dd>\n\n          \n<dt>\n<term>snapCount</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.snapCount</strong>)</p>\n<p>ZooKeeper records its transactions using snapshots and\n              a transaction log (think write-ahead log).The number of\n              transactions recorded in the transaction log before a snapshot\n              can be taken (and the transaction log rolled) is determined\n              by snapCount. In order to prevent all of the machines in the quorum\n              from taking a snapshot at the same time, each ZooKeeper server\n              will take a snapshot when the number of transactions in the transaction log\n              reaches a runtime generated random value in the [snapCount/2+1, snapCount] \n              range.The default snapCount is 100,000.</p>\n</dd>\n\n          \n<dt>\n<term>maxClientCnxns</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Limits the number of concurrent connections (at the socket \n              level) that a single client, identified by IP address, may make\n              to a single member of the ZooKeeper ensemble. This is used to \n              prevent certain classes of DoS attacks, including file \n              descriptor exhaustion. The default is 60. Setting this to 0\n              entirely removes the limit on concurrent connections.</p>\n</dd>\n\n           \n<dt>\n<term>clientPortAddress</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> the\n               address (ipv4, ipv6 or hostname) to listen for client\n               connections; that is, the address that clients attempt\n               to connect to. This is optional, by default we bind in\n               such a way that any connection to the <strong>clientPort</strong> for any\n               address/interface/nic on the server will be\n               accepted.</p>\n</dd>\n\n          \n<dt>\n<term>minSessionTimeout</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>\n<strong>New in 3.3.0:</strong> the\n              minimum session timeout in milliseconds that the server\n              will allow the client to negotiate. Defaults to 2 times\n              the <strong>tickTime</strong>.</p>\n</dd>\n\n          \n<dt>\n<term>maxSessionTimeout</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>\n<strong>New in 3.3.0:</strong> the\n              maximum session timeout in milliseconds that the server\n              will allow the client to negotiate. Defaults to 20 times\n              the <strong>tickTime</strong>.</p>\n</dd>\n           \n           \n<dt>\n<term>fsync.warningthresholdms</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.fsync.warningthresholdms</strong>)</p>\n<p>\n<strong>New in 3.3.4:</strong> A\n               warning message will be output to the log whenever an\n               fsync in the Transactional Log (WAL) takes longer than\n               this value. The values is specified in milliseconds and\n               defaults to 1000. This value can only be set as a\n               system property.</p>\n</dd>\n\n          \n<dt>\n<term>autopurge.snapRetainCount</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>\n<strong>New in 3.4.0:</strong> \n              When enabled, ZooKeeper auto purge feature retains\n              the <strong>autopurge.snapRetainCount</strong> most\n              recent snapshots and the corresponding transaction logs in the \n              <strong>dataDir</strong> and <strong>dataLogDir</strong> respectively and deletes the rest.\n              Defaults to 3. Minimum value is 3.</p>\n</dd>\n          \n          \n<dt>\n<term>autopurge.purgeInterval</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>\n<strong>New in 3.4.0:</strong> The\n              time interval in hours for which the purge task has to\n              be triggered. Set to a positive integer (1 and above)\n              to enable the auto purging. Defaults to 0.</p>\n</dd>\n\n          \n<dt>\n<term>syncEnabled</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.observer.syncEnabled</strong>)</p>\n<p>\n<strong>New in 3.4.6, 3.5.0:</strong>\n              The observers now log transaction and write snapshot to disk\n              by default like the participants. This reduces the recovery time\n              of the observers on restart. Set to \"false\" to disable this\n              feature. Default is \"true\"</p>\n</dd>\n        \n</dl>\n<a name=\"sc_clusterOptions\"></a>\n<h4>Cluster Options</h4>\n<p>The options in this section are designed for use with an ensemble\n        of servers -- that is, when deploying clusters of servers.</p>\n<dl>\n          \n<dt>\n<term>electionAlg</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Election implementation to use. A value of \"0\" corresponds\n              to the original UDP-based version, \"1\" corresponds to the\n              non-authenticated UDP-based version of fast leader election, \"2\"\n              corresponds to the authenticated UDP-based version of fast\n              leader election, and \"3\" corresponds to TCP-based version of\n              fast leader election. Currently, algorithm 3 is the default</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n              \n<p> The implementations of leader election 0, 1, and 2 are now \n              <strong> deprecated </strong>. We have the intention\n              of removing them in the next release, at which point only the \n              FastLeaderElection will be available. \n              </p>\n              \n</div>\n</div>\n</dd>\n\n          \n<dt>\n<term>initLimit</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Amount of time, in ticks (see <a href=\"#id_tickTime\">tickTime</a>), to allow followers to\n              connect and sync to a leader. Increased this value as needed, if\n              the amount of data managed by ZooKeeper is large.</p>\n</dd>\n\n          \n<dt>\n<term>leaderServes</term>\n</dt>\n<dd>\n<p>(Java system property: zookeeper.<strong>leaderServes</strong>)</p>\n<p>Leader accepts client connections. Default value is \"yes\".\n              The leader machine coordinates updates. For higher update\n              throughput at thes slight expense of read throughput the leader\n              can be configured to not accept clients and focus on\n              coordination. The default to this option is yes, which means\n              that a leader will accept client connections.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n                \n<p>Turning on leader selection is highly recommended when\n                you have more than three ZooKeeper servers in an ensemble.</p>\n              \n</div>\n</div>\n</dd>\n\n          \n<dt>\n<term>server.x=[hostname]:nnnnn[:nnnnn], etc</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>servers making up the ZooKeeper ensemble. When the server\n              starts up, it determines which server it is by looking for the\n              file <span class=\"codefrag filename\">myid</span> in the data directory. That file\n              contains the server number, in ASCII, and it should match\n              <strong>x</strong> in <strong>server.x</strong> in the left hand side of this\n              setting.</p>\n<p>The list of servers that make up ZooKeeper servers that is\n              used by the clients must match the list of ZooKeeper servers\n              that each ZooKeeper server has.</p>\n<p>There are two port numbers <strong>nnnnn</strong>. \n              The first followers use to connect to the leader, and the second is for \n              leader election. The leader election port is only necessary if electionAlg \n              is 1, 2, or 3 (default). If electionAlg is 0, then the second port is not \n              necessary. If you want to test multiple servers on a single machine, then \n              different ports can be used for each server.</p>\n</dd>\n\n          \n<dt>\n<term>syncLimit</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Amount of time, in ticks (see <a href=\"#id_tickTime\">tickTime</a>), to allow followers to sync\n              with ZooKeeper. If followers fall too far behind a leader, they\n              will be dropped.</p>\n</dd>\n\n          \n<dt>\n<term>group.x=nnnnn[:nnnnn]</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Enables a hierarchical quorum construction.\"x\" is a group identifier\n              and the numbers following the \"=\" sign correspond to server identifiers. \n              The left-hand side of the assignment is a colon-separated list of server\n              identifiers. Note that groups must be disjoint and the union of all groups\n              must be the ZooKeeper ensemble. </p>\n<p> You will find an example <a href=\"zookeeperHierarchicalQuorums.html\">here</a>\n              \n</p>\n</dd>\n\n          \n<dt>\n<term>weight.x=nnnnn</term>\n</dt>\n<dd>\n<p>(No Java system property)</p>\n<p>Used along with \"group\", it assigns a weight to a server when\n              forming quorums. Such a value corresponds to the weight of a server\n              when voting. There are a few parts of ZooKeeper that require voting\n              such as leader election and the atomic broadcast protocol. By default\n              the weight of server is 1. If the configuration defines groups, but not\n              weights, then a value of 1 will be assigned to all servers.  \n              </p>\n<p> You will find an example <a href=\"zookeeperHierarchicalQuorums.html\">here</a>\n              \n</p>\n</dd>\n          \n          \n<dt>\n<term>cnxTimeout</term>\n</dt>\n<dd>\n<p>(Java system property: zookeeper.<strong>cnxTimeout</strong>)</p>\n<p>Sets the timeout value for opening connections for leader election notifications. \n              Only applicable if you are using electionAlg 3. \n              </p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n                \n<p>Default value is 5 seconds.</p>\n              \n</div>\n</div>\n</dd>\n\n          \n<dt>\n<term>4lw.commands.whitelist</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.4lw.commands.whitelist</strong>)</p>\n<p>\n<strong>New in 3.4.10:</strong>\n                This property contains a list of comma separated\n                <a href=\"#sc_zkCommands\">Four Letter Words</a> commands. It is introduced\n                to provide fine grained control over the set of commands ZooKeeper can execute,\n                so users can turn off certain commands if necessary.\n                By default it contains all supported four letter word commands except \"wchp\" and \"wchc\",\n                if the property is not specified. If the property is specified, then only commands listed\n                in the whitelist are enabled.\n              </p>\n<p>Here's an example of the configuration that enables stat, ruok, conf, and isro\n                command while disabling the rest of Four Letter Words command:</p>\n<pre class=\"code\">\n                4lw.commands.whitelist=stat, ruok, conf, isro\n              </pre>\n<p>Users can also use asterisk option so they don't have to include every command one by one in the list.\n                As an example, this will enable all four letter word commands:\n              </p>\n<pre class=\"code\">\n                4lw.commands.whitelist=*\n              </pre>\n</dd>\n\n          \n<dt>\n<term>ipReachableTimeout</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.ipReachableTimeout</strong>)</p>\n<p>\n<strong>New in 3.4.11:</strong>\n                Set this timeout value for IP addresses reachable checking when hostname is resolved, as mesured in\n                milliseconds.\n                By default, ZooKeeper will use the first IP address of the hostname(without any reachable checking).\n                When zookeeper.ipReachableTimeout is set(larger than 0), ZooKeeper will will try to pick up the first \n                IP address which is reachable. This is done by calling Java API InetAddress.isReachable(long timeout)\n                function, in which this timeout value is used. If none of such reachable IP address can be found, the\n                first IP address of the hostname will be used anyway.\n              </p>\n</dd>\n\n          \n<dt>\n<term>tcpKeepAlive</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.tcpKeepAlive</strong>)</p>\n<p>\n<strong>New in 3.4.11:</strong>\n                Setting this to true sets the TCP keepAlive flag on the\n                sockets used by quorum members to perform elections.\n                This will allow for connections between quorum members to\n                remain up when there is network infrastructure that may\n                otherwise break them. Some NATs and firewalls may terminate\n                or lose state for long running or idle connections.</p>\n<p> Enabling this option relies on OS level settings to work\n                properly, check your operating system's options regarding TCP\n                keepalive for more information.  Defaults to\n                <strong>false</strong>.\n              </p>\n</dd>\n\n        \n</dl>\n<p></p>\n<a name=\"sc_authOptions\"></a>\n<h4>Authentication &amp; Authorization Options</h4>\n<p>The options in this section allow control over\n        authentication/authorization performed by the service.</p>\n<dl>\n          \n<dt>\n<term>zookeeper.DigestAuthenticationProvider.superDigest</term>\n</dt>\n<dd>\n<p>(Java system property only: <strong>zookeeper.DigestAuthenticationProvider.superDigest</strong>)</p>\n<p>By default this feature is <strong>disabled</strong>\n</p>\n<p>\n<strong>New in 3.2:</strong>\n              Enables a ZooKeeper ensemble administrator to access the\n              znode hierarchy as a \"super\" user. In particular no ACL\n              checking occurs for a user authenticated as\n              super.</p>\n<p>org.apache.zookeeper.server.auth.DigestAuthenticationProvider\n              can be used to generate the superDigest, call it with\n              one parameter of \"super:&lt;password&gt;\". Provide the\n              generated \"super:&lt;data&gt;\" as the system property value\n              when starting each server of the ensemble.</p>\n<p>When authenticating to a ZooKeeper server (from a\n              ZooKeeper client) pass a scheme of \"digest\" and authdata\n              of \"super:&lt;password&gt;\". Note that digest auth passes\n              the authdata in plaintext to the server, it would be\n              prudent to use this authentication method only on\n              localhost (not over the network) or over an encrypted\n              connection.</p>\n</dd>\n\n          \n<dt>\n<term>isro</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.4.0:</strong> Tests if\n              server is running in read-only mode.  The server will respond with\n              \"ro\" if in read-only mode or \"rw\" if not in read-only mode.</p>\n</dd>\n\n          \n<dt>\n<term>gtmk</term>\n</dt>\n<dd>\n<p>Gets the current trace mask as a 64-bit signed long value in\n              decimal format.  See <span class=\"codefrag command\">stmk</span> for an explanation of\n              the possible values.</p>\n</dd>\n\n          \n<dt>\n<term>stmk</term>\n</dt>\n<dd>\n<p>Sets the current trace mask.  The trace mask is 64 bits,\n              where each bit enables or disables a specific category of trace\n              logging on the server.  Log4J must be configured to enable\n              <span class=\"codefrag command\">TRACE</span> level first in order to see trace logging\n              messages.  The bits of the trace mask correspond to the following\n              trace logging categories.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<caption>Trace Mask Bit Values</caption>\n                \n<title>Trace Mask Bit Values</title>\n                \n                    \n<tr>\n                      \n<td>0b0000000000</td>\n                      <td>Unused, reserved for future use.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0000000010</td>\n                      <td>Logs client requests, excluding ping\n                      requests.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0000000100</td>\n                      <td>Unused, reserved for future use.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0000001000</td>\n                      <td>Logs client ping requests.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0000010000</td>\n                      <td>Logs packets received from the quorum peer that is\n                      the current leader, excluding ping requests.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0000100000</td>\n                      <td>Logs addition, removal and validation of client\n                      sessions.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0001000000</td>\n                      <td>Logs delivery of watch events to client\n                      sessions.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0010000000</td>\n                      <td>Logs ping packets received from the quorum peer\n                      that is the current leader.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b0100000000</td>\n                      <td>Unused, reserved for future use.</td>\n                    \n</tr>\n                    \n<tr>\n                      \n<td>0b1000000000</td>\n                      <td>Unused, reserved for future use.</td>\n                    \n</tr>\n                  \n              \n</table>\n<p>All remaining bits in the 64-bit value are unused and\n              reserved for future use.  Multiple trace logging categories are\n              specified by calculating the bitwise OR of the documented values.\n              The default trace mask is 0b0100110010.  Thus, by default, trace\n              logging includes client requests, packets received from the\n              leader and sessions.</p>\n<p>To set a different trace mask, send a request containing the\n              <span class=\"codefrag command\">stmk</span> four-letter word followed by the trace\n              mask represented as a 64-bit signed long value.  This example uses\n              the Perl <span class=\"codefrag command\">pack</span> function to construct a trace\n              mask that enables all trace logging categories described above and\n              convert it to a 64-bit signed long value with big-endian byte\n              order.  The result is appended to <span class=\"codefrag command\">stmk</span> and sent\n              to the server using netcat.  The server responds with the new\n              trace mask in decimal format.</p>\n<pre class=\"code\">$ perl -e \"print 'stmk', pack('q&gt;', 0b0011111010)\" | nc localhost 2181\n250\n              </pre>\n</dd>\n        \n</dl>\n<a name=\"Experimental+Options%2FFeatures\"></a>\n<h4>Experimental Options/Features</h4>\n<p>New features that are currently considered experimental.</p>\n<dl>\n          \n<dt>\n<term>Read Only Mode Server</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>readonlymode.enabled</strong>)</p>\n<p>\n<strong>New in 3.4.0:</strong>\n              Setting this value to true enables Read Only Mode server\n              support (disabled by default). ROM allows clients\n              sessions which requested ROM support to connect to the\n              server even when the server might be partitioned from\n              the quorum. In this mode ROM clients can still read\n              values from the ZK service, but will be unable to write\n              values and see changes from other clients. See\n              ZOOKEEPER-784 for more details.\n              </p>\n</dd>\n\n        \n</dl>\n<a name=\"Unsafe+Options\"></a>\n<h4>Unsafe Options</h4>\n<p>The following options can be useful, but be careful when you use\n        them. The risk of each is explained along with the explanation of what\n        the variable does.</p>\n<dl>\n          \n<dt>\n<term>forceSync</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.forceSync</strong>)</p>\n<p>Requires updates to be synced to media of the transaction\n              log before finishing processing the update. If this option is\n              set to no, ZooKeeper will not require updates to be synced to\n              the media.</p>\n</dd>\n\n          \n<dt>\n<term>jute.maxbuffer:</term>\n</dt>\n<dd>\n<p>(Java system property:<strong>\n              jute.maxbuffer</strong>)</p>\n<p>This option can only be set as a Java system property.\n              There is no zookeeper prefix on it. It specifies the maximum\n              size of the data that can be stored in a znode. The default is\n              0xfffff, or just under 1M. If this option is changed, the system\n              property must be set on all servers and clients otherwise\n              problems will arise. This is really a sanity check. ZooKeeper is\n              designed to store data on the order of kilobytes in size.</p>\n</dd>\n\n          \n<dt>\n<term>skipACL</term>\n</dt>\n<dd>\n<p>(Java system property: <strong>zookeeper.skipACL</strong>)</p>\n<p>Skips ACL checks. This results in a boost in throughput,\n              but opens up full access to the data tree to everyone.</p>\n</dd>\n\n          \n<dt>\n<term>quorumListenOnAllIPs</term>\n</dt>\n<dd>\n<p>When set to true the ZooKeeper server will listen  \n              for connections from its peers on all available IP addresses,\n              and not only the address configured in the server list of the\n              configuration file. It affects the connections handling the \n              ZAB protocol and the Fast Leader Election protocol. Default\n              value is <strong>false</strong>.</p>\n</dd>\n\n        \n</dl>\n<a name=\"Communication+using+the+Netty+framework\"></a>\n<h4>Communication using the Netty framework</h4>\n<p>\n<strong>New in\n            3.4:</strong> <a href=\"http://jboss.org/netty\">Netty</a>\n            is an NIO based client/server communication framework, it\n            simplifies (over NIO being used directly) many of the\n            complexities of network level communication for java\n            applications. Additionally the Netty framework has built\n            in support for encryption (SSL) and authentication\n            (certificates). These are optional features and can be\n            turned on or off individually.\n        </p>\n<p>Prior to version 3.4 ZooKeeper has always used NIO\n            directly, however in versions 3.4 and later Netty is\n            supported as an option to NIO (replaces). NIO continues to\n            be the default, however Netty based communication can be\n            used in place of NIO by setting the environment variable\n            \"zookeeper.serverCnxnFactory\" to\n            \"org.apache.zookeeper.server.NettyServerCnxnFactory\". You\n            have the option of setting this on either the client(s) or\n            server(s), typically you would want to set this on both,\n            however that is at your discretion.\n        </p>\n<p>\n          TBD - tuning options for netty - currently there are none that are netty specific but we should add some. Esp around max bound on the number of reader worker threads netty creates.\n        </p>\n<p>\n          TBD - how to manage encryption\n        </p>\n<p>\n          TBD - how to manage certificates\n        </p>\n<a name=\"sc_zkCommands\"></a>\n<h3 class=\"h4\">ZooKeeper Commands: The Four Letter Words</h3>\n<p>ZooKeeper responds to a small set of commands. Each command is\n      composed of four letters. You issue the commands to ZooKeeper via telnet\n      or nc, at the client port.</p>\n<p>Three of the more interesting commands: \"stat\" gives some\n      general information about the server and connected clients,\n      while \"srvr\" and \"cons\" give extended details on server and\n      connections respectively.</p>\n<dl>\n        \n<dt>\n<term>conf</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Print\n            details about serving configuration.</p>\n</dd>\n\n        \n<dt>\n<term>cons</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> List\n            full connection/session details for all clients connected\n            to this server. Includes information on numbers of packets\n            received/sent, session id, operation latencies, last\n            operation performed, etc...</p>\n</dd>\n\n        \n<dt>\n<term>crst</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Reset\n            connection/session statistics for all connections.</p>\n</dd>\n\n        \n<dt>\n<term>dump</term>\n</dt>\n<dd>\n<p>Lists the outstanding sessions and ephemeral nodes. This\n            only works on the leader.</p>\n</dd>\n\n        \n<dt>\n<term>envi</term>\n</dt>\n<dd>\n<p>Print details about serving environment</p>\n</dd>\n\n        \n<dt>\n<term>ruok</term>\n</dt>\n<dd>\n<p>Tests if server is running in a non-error state. The server\n            will respond with imok if it is running. Otherwise it will not\n            respond at all.</p>\n<p>A response of \"imok\" does not necessarily indicate that the\n            server has joined the quorum, just that the server process is active\n            and bound to the specified client port. Use \"stat\" for details on\n            state wrt quorum and client connection information.</p>\n</dd>\n\n        \n<dt>\n<term>srst</term>\n</dt>\n<dd>\n<p>Reset server statistics.</p>\n</dd>\n\n        \n<dt>\n<term>srvr</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Lists\n            full details for the server.</p>\n</dd>\n\n        \n<dt>\n<term>stat</term>\n</dt>\n<dd>\n<p>Lists brief details for the server and connected\n            clients.</p>\n</dd>\n\n        \n<dt>\n<term>wchs</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Lists\n            brief information on watches for the server.</p>\n</dd>\n\n        \n<dt>\n<term>wchc</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Lists\n            detailed information on watches for the server, by\n            session.  This outputs a list of sessions(connections)\n            with associated watches (paths). Note, depending on the\n            number of watches this operation may be expensive (ie\n            impact server performance), use it carefully.</p>\n</dd>\n\n        \n<dt>\n<term>wchp</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.3.0:</strong> Lists\n            detailed information on watches for the server, by path.\n            This outputs a list of paths (znodes) with associated\n            sessions. Note, depending on the number of watches this\n            operation may be expensive (ie impact server performance),\n            use it carefully.</p>\n</dd>\n\n\n        \n<dt>\n<term>mntr</term>\n</dt>\n<dd>\n<p>\n<strong>New in 3.4.0:</strong> Outputs a list \n            of variables that could be used for monitoring the health of the cluster.</p>\n<pre class=\"code\">$ echo mntr | nc localhost 2185\n\nzk_version  3.4.0\nzk_avg_latency  0\nzk_max_latency  0\nzk_min_latency  0\nzk_packets_received 70\nzk_packets_sent 69\nzk_outstanding_requests 0\nzk_server_state leader\nzk_znode_count   4\nzk_watch_count  0\nzk_ephemerals_count 0\nzk_approximate_data_size    27\nzk_followers    4                   - only exposed by the Leader\nzk_synced_followers 4               - only exposed by the Leader\nzk_pending_syncs    0               - only exposed by the Leader\nzk_open_file_descriptor_count 23    - only available on Unix platforms\nzk_max_file_descriptor_count 1024   - only available on Unix platforms\n</pre>\n<p>The output is compatible with java properties format and the content \n        may change over time (new keys added). Your scripts should expect changes.</p>\n<p>ATTENTION: Some of the keys are platform specific and some of the keys are only exported by the Leader. </p>\n<p>The output contains multiple lines with the following format:</p>\n<pre class=\"code\">key \\t value</pre>\n</dd>\n      \n</dl>\n<p>Here's an example of the <strong>ruok</strong>\n      command:</p>\n<pre class=\"code\">$ echo ruok | nc 127.0.0.1 5111\nimok\n</pre>\n<a name=\"sc_dataFileManagement\"></a>\n<h3 class=\"h4\">Data File Management</h3>\n<p>ZooKeeper stores its data in a data directory and its transaction\n      log in a transaction log directory. By default these two directories are\n      the same. The server can (and should) be configured to store the\n      transaction log files in a separate directory than the data files.\n      Throughput increases and latency decreases when transaction logs reside\n      on a dedicated log devices.</p>\n<a name=\"The+Data+Directory\"></a>\n<h4>The Data Directory</h4>\n<p>This directory has two files in it:</p>\n<ul>\n          \n<li>\n            \n<p>\n<span class=\"codefrag filename\">myid</span> - contains a single integer in\n            human readable ASCII text that represents the server id.</p>\n          \n</li>\n\n          \n<li>\n            \n<p>\n<span class=\"codefrag filename\">snapshot.&lt;zxid&gt;</span> - holds the fuzzy\n            snapshot of a data tree.</p>\n          \n</li>\n        \n</ul>\n<p>Each ZooKeeper server has a unique id. This id is used in two\n        places: the <span class=\"codefrag filename\">myid</span> file and the configuration file.\n        The <span class=\"codefrag filename\">myid</span> file identifies the server that\n        corresponds to the given data directory. The configuration file lists\n        the contact information for each server identified by its server id.\n        When a ZooKeeper server instance starts, it reads its id from the\n        <span class=\"codefrag filename\">myid</span> file and then, using that id, reads from the\n        configuration file, looking up the port on which it should\n        listen.</p>\n<p>The <span class=\"codefrag filename\">snapshot</span> files stored in the data\n        directory are fuzzy snapshots in the sense that during the time the\n        ZooKeeper server is taking the snapshot, updates are occurring to the\n        data tree. The suffix of the <span class=\"codefrag filename\">snapshot</span> file names\n        is the <em>zxid</em>, the ZooKeeper transaction id, of the\n        last committed transaction at the start of the snapshot. Thus, the\n        snapshot includes a subset of the updates to the data tree that\n        occurred while the snapshot was in process. The snapshot, then, may\n        not correspond to any data tree that actually existed, and for this\n        reason we refer to it as a fuzzy snapshot. Still, ZooKeeper can\n        recover using this snapshot because it takes advantage of the\n        idempotent nature of its updates. By replaying the transaction log\n        against fuzzy snapshots ZooKeeper gets the state of the system at the\n        end of the log.</p>\n<a name=\"The+Log+Directory\"></a>\n<h4>The Log Directory</h4>\n<p>The Log Directory contains the ZooKeeper transaction logs.\n        Before any update takes place, ZooKeeper ensures that the transaction\n        that represents the update is written to non-volatile storage. A new\n        log file is started when the number of transactions written to the\n        current log file reaches a (variable) threshold. The threshold is\n        computed using the same parameter which influences the frequency of\n        snapshotting (see snapCount above). The log file's suffix is the first\n        zxid written to that log.</p>\n<a name=\"sc_filemanagement\"></a>\n<h4>File Management</h4>\n<p>The format of snapshot and log files does not change between\n        standalone ZooKeeper servers and different configurations of\n        replicated ZooKeeper servers. Therefore, you can pull these files from\n        a running replicated ZooKeeper server to a development machine with a\n        stand-alone ZooKeeper server for trouble shooting.</p>\n<p>Using older log and snapshot files, you can look at the previous\n        state of ZooKeeper servers and even restore that state. The\n        LogFormatter class allows an administrator to look at the transactions\n        in a log.</p>\n<p>The ZooKeeper server creates snapshot and log files, but\n        never deletes them. The retention policy of the data and log\n        files is implemented outside of the ZooKeeper server. The\n        server itself only needs the latest complete fuzzy snapshot, all log\n        files following it, and the last log file preceding it.  The latter\n        requirement is necessary to include updates which happened after this\n        snapshot was started but went into the existing log file at that time.\n        This is possible because snapshotting and rolling over of logs\n        proceed somewhat independently in ZooKeeper. See the\n        <a href=\"#sc_maintenance\">maintenance</a> section in\n        this document for more details on setting a retention policy\n        and maintenance of ZooKeeper storage.\n        </p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n        \n<p>The data stored in these files is not encrypted. In the case of\n        storing sensitive data in ZooKeeper, necessary measures need to be\n        taken to prevent unauthorized access. Such measures are external to\n        ZooKeeper (e.g., control access to the files) and depend on the\n        individual settings in which it is being deployed. </p>\n        \n</div>\n</div>\n<a name=\"sc_commonProblems\"></a>\n<h3 class=\"h4\">Things to Avoid</h3>\n<p>Here are some common problems you can avoid by configuring\n      ZooKeeper correctly:</p>\n<dl>\n        \n<dt>\n<term>inconsistent lists of servers</term>\n</dt>\n<dd>\n<p>The list of ZooKeeper servers used by the clients must match\n            the list of ZooKeeper servers that each ZooKeeper server has.\n            Things work okay if the client list is a subset of the real list,\n            but things will really act strange if clients have a list of\n            ZooKeeper servers that are in different ZooKeeper clusters. Also,\n            the server lists in each Zookeeper server configuration file\n            should be consistent with one another.</p>\n</dd>\n\n        \n<dt>\n<term>incorrect placement of transaction log</term>\n</dt>\n<dd>\n<p>The most performance critical part of ZooKeeper is the\n            transaction log. ZooKeeper syncs transactions to media before it\n            returns a response. A dedicated transaction log device is key to\n            consistent good performance. Putting the log on a busy device will\n            adversely effect performance. If you only have one storage device,\n            put trace files on NFS and increase the snapshotCount; it doesn't\n            eliminate the problem, but it should mitigate it.</p>\n</dd>\n\n        \n<dt>\n<term>incorrect Java heap size</term>\n</dt>\n<dd>\n<p>You should take special care to set your Java max heap size\n            correctly. In particular, you should not create a situation in\n            which ZooKeeper swaps to disk. The disk is death to ZooKeeper.\n            Everything is ordered, so if processing one request swaps the\n            disk, all other queued requests will probably do the same. the\n            disk. DON'T SWAP.</p>\n<p>Be conservative in your estimates: if you have 4G of RAM, do\n            not set the Java max heap size to 6G or even 4G. For example, it\n            is more likely you would use a 3G heap for a 4G machine, as the\n            operating system and the cache also need memory. The best and only\n            recommend practice for estimating the heap size your system needs\n            is to run load tests, and then make sure you are well below the\n            usage limit that would cause the system to swap.</p>\n</dd>\n\n        \n<dt>\n<term>Publicly accessible deployment</term>\n</dt>\n<dd>\n<p>\n              A ZooKeeper ensemble is expected to operate in a trusted computing environment.\n              It is thus recommended to deploy ZooKeeper behind a firewall.\n            </p>\n</dd>\n      \n</dl>\n<a name=\"sc_bestPractices\"></a>\n<h3 class=\"h4\">Best Practices</h3>\n<p>For best results, take note of the following list of good\n      Zookeeper practices:</p>\n<p>For multi-tennant installations see the <a href=\"zookeeperProgrammers.html#ch_zkSessions\">section</a>\n      detailing ZooKeeper \"chroot\" support, this can be very useful\n      when deploying many applications/services interfacing to a\n      single ZooKeeper cluster.</p>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperHierarchicalQuorums.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>Introduction to hierarchical quorums</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperHierarchicalQuorums.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>Introduction to hierarchical quorums</h1>\n<div id=\"front-matter\"></div>\n  \n\n  \n\n    \n<p>\n    This document gives an example of how to use hierarchical quorums. The basic idea is\n    very simple. First, we split servers into groups, and add a line for each group listing\n    the servers that form this group. Next we have to assign a weight to each server.  \n    </p>\n    \n    \n<p>\n    The following example shows how to configure a system with three groups of three servers\n    each, and we assign a weight of 1 to each server:\n    </p>\n    \n    \n<pre class=\"code\">\n    group.1=1:2:3\n    group.2=4:5:6\n    group.3=7:8:9\n   \n    weight.1=1\n    weight.2=1\n    weight.3=1\n    weight.4=1\n    weight.5=1\n    weight.6=1\n    weight.7=1\n    weight.8=1\n    weight.9=1\n \t</pre>\n\n\t\n<p>    \n    When running the system, we are able to form a quorum once we have a majority of votes from\n    a majority of non-zero-weight groups. Groups that have zero weight are discarded and not\n    considered when forming quorums. Looking at the example, we are able to form a quorum once\n    we have votes from at least two servers from each of two different groups.\n    </p> \n \n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperInternals.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Internals</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.5', 'skin/')\" id=\"menu_selected_1.5Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Contributor</div>\n<div id=\"menu_selected_1.5\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menupage\">\n<div class=\"menupagetitle\">ZooKeeper Internals</div>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperInternals.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Internals</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_Introduction\">Introduction</a>\n</li>\n<li>\n<a href=\"#sc_atomicBroadcast\">Atomic Broadcast</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_guaranteesPropertiesDefinitions\">Guarantees, Properties, and Definitions</a>\n</li>\n<li>\n<a href=\"#sc_leaderElection\">Leader Activation</a>\n</li>\n<li>\n<a href=\"#sc_activeMessaging\">Active Messaging</a>\n</li>\n<li>\n<a href=\"#sc_summary\">Summary</a>\n</li>\n<li>\n<a href=\"#sc_comparisons\">Comparisons</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_quorum\">Quorums</a>\n</li>\n<li>\n<a href=\"#sc_logging\">Logging</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_developerGuidelines\">Developer Guidelines</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_rightLevel\">Logging at the Right Level</a>\n</li>\n<li>\n<a href=\"#sc_slf4jIdioms\">Use of Standard slf4j Idioms</a>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_Introduction\"></a>\n<h2 class=\"h3\">Introduction</h2>\n<div class=\"section\">\n<p>This document contains information on the inner workings of ZooKeeper. \n    So far, it discusses these topics:\n    </p>\n<ul>    \n\n<li>\n<p>\n<a href=\"#sc_atomicBroadcast\">Atomic Broadcast</a>\n</p>\n</li>\n\n<li>\n<p>\n<a href=\"#sc_logging\">Logging</a>\n</p>\n</li>\n\n</ul>\n</div>\n\n\n<a name=\"sc_atomicBroadcast\"></a>\n<h2 class=\"h3\">Atomic Broadcast</h2>\n<div class=\"section\">\n<p>\nAt the heart of ZooKeeper is an atomic messaging system that keeps all of the servers in sync.</p>\n<a name=\"sc_guaranteesPropertiesDefinitions\"></a>\n<h3 class=\"h4\">Guarantees, Properties, and Definitions</h3>\n<p>\nThe specific guarantees provided by the messaging system used by ZooKeeper are the following:</p>\n<dl>\n\n\n<dt>\n<term>\n<em>Reliable delivery</em>\n</term>\n</dt>\n<dd>\n<p>If a message, m, is delivered \nby one server, it will be eventually delivered by all servers.</p>\n</dd>\n\n\n<dt>\n<term>\n<em>Total order</em>\n</term>\n</dt>\n<dd>\n<p> If a message is \ndelivered before message b by one server, a will be delivered before b by all \nservers. If a and b are delivered messages, either a will be delivered before b \nor b will be delivered before a.</p>\n</dd>\n\n\n<dt>\n<term>\n<em>Causal order</em> \n</term>\n</dt>\n<dd>\n<p>\nIf a message b is sent after a message a has been delivered by the sender of b, \na must be ordered before b. If a sender sends c after sending b, c must be ordered after b.\n</p>\n</dd>\n\n\n</dl>\n<p>\nThe ZooKeeper messaging system also needs to be efficient, reliable, and easy to \nimplement and maintain. We make heavy use of messaging, so we need the system to \nbe able to handle thousands of requests per second. Although we can require at \nleast k+1 correct servers to send new messages, we must be able to recover from \ncorrelated failures such as power outages. When we implemented the system we had \nlittle time and few engineering resources, so we needed a protocol that is \naccessible to engineers and is easy to implement. We found that our protocol \nsatisfied all of these goals.\n\n</p>\n<p>\nOur protocol assumes that we can construct point-to-point FIFO channels between \nthe servers. While similar services usually assume message delivery that can \nlose or reorder messages, our assumption of FIFO channels is very practical \ngiven that we use TCP for communication. Specifically we rely on the following property of TCP:</p>\n<dl>\n\n\n<dt>\n<term>\n<em>Ordered delivery</em>\n</term>\n</dt>\n<dd>\n<p>Data is delivered in the same order it is sent and a message m is \ndelivered only after all messages sent before m have been delivered. \n(The corollary to this is that if message m is lost all messages after m will be lost.)</p>\n</dd>\n\n\n<dt>\n<term>\n<em>No message after close</em>\n</term>\n</dt>\n<dd>\n<p>Once a FIFO channel is closed, no messages will be received from it.</p>\n</dd>\n\n\n</dl>\n<p>\nFLP proved that consensus cannot be achieved in asynchronous distributed systems \nif failures are possible. To ensure we achieve consensus in the presence of failures \nwe use timeouts. However, we rely on times for liveness not for correctness. So, \nif timeouts stop working (clocks malfunction for example) the messaging system may \nhang, but it will not violate its guarantees.</p>\n<p>When describing the ZooKeeper messaging protocol we will talk of packets, \nproposals, and messages:</p>\n<dl>\n\n<dt>\n<term>\n<em>Packet</em>\n</term>\n</dt>\n<dd>\n<p>a sequence of bytes sent through a FIFO channel</p>\n</dd>\n<dt>\n<term>\n<em>Proposal</em>\n</term>\n</dt>\n<dd>\n<p>a unit of agreement. Proposals are agreed upon by exchanging packets \nwith a quorum of ZooKeeper servers. Most proposals contain messages, however the \nNEW_LEADER proposal is an example of a proposal that does not correspond to a message.</p>\n</dd>\n<dt>\n<term>\n<em>Message</em>\n</term>\n</dt>\n<dd>\n<p>a sequence of bytes to be atomically broadcast to all ZooKeeper \nservers. A message put into a proposal and agreed upon before it is delivered.</p>\n</dd>\n\n\n</dl>\n<p>\nAs stated above, ZooKeeper guarantees a total order of messages, and it also \nguarantees a total order of proposals. ZooKeeper exposes the total ordering using\na ZooKeeper transaction id (<em>zxid</em>). All proposals will be stamped with a zxid when \nit is proposed and exactly reflects the total ordering. Proposals are sent to all \nZooKeeper servers and committed when a quorum of them acknowledge the proposal. \nIf a proposal contains a message, the message will be delivered when the proposal \nis committed. Acknowledgement means the server has recorded the proposal to persistent storage. \nOur quorums have the requirement that any pair of quorum must have at least one server \nin common. We ensure this by requiring that all quorums have size (<em>n/2+1</em>) where \nn is the number of servers that make up a ZooKeeper service.\n</p>\n<p>\nThe zxid has two parts: the epoch and a counter. In our implementation the zxid \nis a 64-bit number. We use the high order 32-bits for the epoch and the low order \n32-bits for the counter. Because it has two parts represent the zxid both as a \nnumber and as a pair of integers, (<em>epoch, count</em>). The epoch number represents a \nchange in leadership. Each time a new leader comes into power it will have its \nown epoch number. We have a simple algorithm to assign a unique zxid to a proposal: \nthe leader simply increments the zxid to obtain a unique zxid for each proposal. \n<em>Leadership activation will ensure that only one leader uses a given epoch, so our \nsimple algorithm guarantees that every proposal will have a unique id.</em>\n\n</p>\n<p>\nZooKeeper messaging consists of two phases:</p>\n<dl>\n\n<dt>\n<term>\n<em>Leader activation</em>\n</term>\n</dt>\n<dd>\n<p>In this phase a leader establishes the correct state of the system \nand gets ready to start making proposals.</p>\n</dd>\n\n\n<dt>\n<term>\n<em>Active messaging</em>\n</term>\n</dt>\n<dd>\n<p>In this phase a leader accepts messages to propose and coordinates message delivery.</p>\n</dd>\n\n</dl>\n<p>\nZooKeeper is a holistic protocol. We do not focus on individual proposals, rather \nlook at the stream of proposals as a whole. Our strict ordering allows us to do this \nefficiently and greatly simplifies our protocol. Leadership activation embodies \nthis holistic concept. A leader becomes active only when a quorum of followers \n(The leader counts as a follower as well. You can always vote for yourself ) has synced \nup with the leader, they have the same state. This state consists of all of the \nproposals that the leader believes have been committed and the proposal to follow \nthe leader, the NEW_LEADER proposal. (Hopefully you are thinking to \nyourself, <em>Does the set of proposals that the leader believes has been committed \nincluded all the proposals that really have been committed?</em> The answer is <em>yes</em>. \nBelow, we make clear why.)\n</p>\n<a name=\"sc_leaderElection\"></a>\n<h3 class=\"h4\">Leader Activation</h3>\n<p>\nLeader activation includes leader election. We currently have two leader election \nalgorithms in ZooKeeper: LeaderElection and FastLeaderElection (AuthFastLeaderElection \nis a variant of FastLeaderElection that uses UDP and allows servers to perform a simple\nform of authentication to avoid IP spoofing). ZooKeeper messaging doesn't care about the \nexact method of electing a leader has long as the following holds:\n</p>\n<ul>\n\n\n<li>\n<p>The leader has seen the highest zxid of all the followers.</p>\n</li>\n\n<li>\n<p>A quorum of servers have committed to following the leader.</p>\n</li>\n\n\n</ul>\n<p>\nOf these two requirements only the first, the highest zxid amoung the followers \nneeds to hold for correct operation. The second requirement, a quorum of followers, \njust needs to hold with high probability. We are going to recheck the second requirement, \nso if a failure happens during or after the leader election and quorum is lost, \nwe will recover by abandoning leader activation and running another election.\n</p>\n<p>\nAfter leader election a single server will be designated as a leader and start \nwaiting for followers to connect. The rest of the servers will try to connect to \nthe leader. The leader will sync up with followers by sending any proposals they \nare missing, or if a follower is missing too many proposals, it will send a full \nsnapshot of the state to the follower.\n</p>\n<p>\nThere is a corner case in which a follower that has proposals, U, not seen \nby a leader arrives. Proposals are seen in order, so the proposals of U will have a zxids \nhigher than zxids seen by the leader. The follower must have arrived after the \nleader election, otherwise the follower would have been elected leader given that \nit has seen a higher zxid. Since committed proposals must be seen by a quorum of \nservers, and a quorum of servers that elected the leader did not see U, the proposals \nof you have not been committed, so they can be discarded. When the follower connects \nto the leader, the leader will tell the follower to discard U.\n</p>\n<p>\nA new leader establishes a zxid to start using for new proposals by getting the \nepoch, e, of the highest zxid it has seen and setting the next zxid to use to be \n(e+1, 0), fter the leader syncs with a follower, it will propose a NEW_LEADER \nproposal. Once the NEW_LEADER proposal has been committed, the leader will activate \nand start receiving and issuing proposals.\n</p>\n<p>\nIt all sounds complicated but here are the basic rules of operation during leader \nactivation:\n</p>\n<ul>\n\n<li>\n<p>A follower will ACK the NEW_LEADER proposal after it has synced with the leader.</p>\n</li>\n\n<li>\n<p>A follower will only ACK a NEW_LEADER proposal with a given zxid from a single server.</p>\n</li>\n\n<li>\n<p>A new leader will COMMIT the NEW_LEADER proposal when a quorum of followers have ACKed it.</p>\n</li>\n\n<li>\n<p>A follower will commit any state it received from the leader when the NEW_LEADER proposal is COMMIT.</p>\n</li>\n\n<li>\n<p>A new leader will not accept new proposals until the NEW_LEADER proposal has been COMMITED.</p>\n</li>\n\n</ul>\n<p>\nIf leader election terminates erroneously, we don't have a problem since the \nNEW_LEADER proposal will not be committed since the leader will not have quorum. \nWhen this happens, the leader and any remaining followers will timeout and go back \nto leader election.\n</p>\n<a name=\"sc_activeMessaging\"></a>\n<h3 class=\"h4\">Active Messaging</h3>\n<p>\nLeader Activation does all the heavy lifting. Once the leader is coronated he can \nstart blasting out proposals. As long as he remains the leader no other leader can \nemerge since no other leader will be able to get a quorum of followers. If a new \nleader does emerge, \nit means that the leader has lost quorum, and the new leader will clean up any \nmess left over during her leadership activation.\n</p>\n<p>ZooKeeper messaging operates similar to a classic two-phase commit.</p>\n<img alt=\"\" src=\"images/2pc.jpg\"><p>\nAll communication channels are FIFO, so everything is done in order. Specifically \nthe following operating constraints are observed:</p>\n<ul>\n\n\n<li>\n<p>The leader sends proposals to all followers using \nthe same order. Moreover, this order follows the order in which requests have been \nreceived. Because we use FIFO channels this means that followers also receive proposals in order.\n</p>\n</li>\n\n\n<li>\n<p>Followers process messages in the order they are received. This \nmeans that messages will be ACKed in order and the leader will receive ACKs from \nfollowers in order, due to the FIFO channels. It also means that if message $m$ \nhas been written to non-volatile storage, all messages that were proposed before \n$m$ have been written to non-volatile storage.</p>\n</li>\n\n\n<li>\n<p>The leader will issue a COMMIT to all followers as soon as a \nquorum of followers have ACKed a message. Since messages are ACKed in order, \nCOMMITs will be sent by the leader as received by the followers in order.</p>\n</li>\n\n\n<li>\n<p>COMMITs are processed in order. Followers deliver a proposals \nmessage when that proposal is committed.</p>\n</li>\n\n\n</ul>\n<a name=\"sc_summary\"></a>\n<h3 class=\"h4\">Summary</h3>\n<p>So there you go. Why does it work? Specifically, why does is set of proposals \nbelieved by a new leader always contain any proposal that has actually been committed? \nFirst, all proposals have a unique zxid, so unlike other protocols, we never have \nto worry about two different values being proposed for the same zxid; followers \n(a leader is also a follower) see and record proposals in order; proposals are \ncommitted in order; there is only one active leader at a time since followers only \nfollow a single leader at a time; a new leader has seen all committed proposals \nfrom the previous epoch since it has seen the highest zxid from a quorum of servers; \nany uncommited proposals from a previous epoch seen by a new leader will be committed \nby that leader before it becomes active.</p>\n<a name=\"sc_comparisons\"></a>\n<h3 class=\"h4\">Comparisons</h3>\n<p>\nIsn't this just Multi-Paxos? No, Multi-Paxos requires some way of assuring that \nthere is only a single coordinator. We do not count on such assurances. Instead \nwe use the leader activation to recover from leadership change or old leaders \nbelieving they are still active.\n</p>\n<p>\nIsn't this just Paxos? Your active messaging phase looks just like phase 2 of Paxos? \nActually, to us active messaging looks just like 2 phase commit without the need to \nhandle aborts. Active messaging is different from both in the sense that it has \ncross proposal ordering requirements. If we do not maintain strict FIFO ordering of \nall packets, it all falls apart. Also, our leader activation phase is different from \nboth of them. In particular, our use of epochs allows us to skip blocks of uncommitted\nproposals and to not worry about duplicate proposals for a given zxid.\n</p>\n</div>\n\n\n<a name=\"sc_quorum\"></a>\n<h2 class=\"h3\">Quorums</h2>\n<div class=\"section\">\n<p>\nAtomic broadcast and leader election use the notion of quorum to guarantee a consistent\nview of the system. By default, ZooKeeper uses majority quorums, which means that every\nvoting that happens in one of these protocols requires a majority to vote on. One example is\nacknowledging a leader proposal: the leader can only commit once it receives an\nacknowledgement from a quorum of servers.\n</p>\n<p>\nIf we extract the properties that we really need from our use of majorities, we have that we only\nneed to guarantee that groups of processes used to validate an operation by voting (e.g., acknowledging\na leader proposal) pairwise intersect in at least one server. Using majorities guarantees such a property.\nHowever, there are other ways of constructing quorums different from majorities. For example, we can assign\nweights to the votes of servers, and say that the votes of some servers are more important. To obtain a quorum,\nwe get enough votes so that the sum of weights of all votes is larger than half of the total sum of all weights.    \n</p>\n<p>\nA different construction that uses weights and is useful in wide-area deployments (co-locations) is a hierarchical\none. With this construction, we split the servers into disjoint groups and assign weights to processes. To form \na quorum, we have to get a hold of enough servers from a majority of groups G, such that for each group g in G,\nthe sum of votes from g is larger than half of the sum of weights in g. Interestingly, this construction enables\nsmaller quorums. If we have, for example, 9 servers, we split them into 3 groups, and assign a weight of 1 to each\nserver, then we are able to form quorums of size 4. Note that two subsets of processes composed each of a majority\nof servers from each of a majority of groups necessarily have a non-empty intersection. It is reasonable to expect\nthat a majority of co-locations will have a majority of servers available with high probability. \n</p>\n<p>\nWith ZooKeeper, we provide a user with the ability of configuring servers to use majority quorums, weights, or a \nhierarchy of groups.\n</p>\n</div>\n\n\n<a name=\"sc_logging\"></a>\n<h2 class=\"h3\">Logging</h2>\n<div class=\"section\">\n<p>\nZookeeper uses \n<a href=\"http://www.slf4j.org/index.html\">slf4j</a> as an abstraction layer for logging. \n<a href=\"http://logging.apache.org/log4j\">log4j</a> in version 1.2 is chosen as the final logging implementation for now.\nFor better embedding support, it is planned in the future to leave the decision of choosing the final logging implementation to the end user.\nTherefore, always use the slf4j api to write log statements in the code, but configure log4j for how to log at runtime.\nNote that slf4j has no FATAL level, former messages at FATAL level have been moved to ERROR level. \nFor information on configuring log4j for\nZooKeeper, see the <a href=\"zookeeperAdmin.html#sc_logging\">Logging</a> section \nof the <a href=\"zookeeperAdmin.html\">ZooKeeper Administrator's Guide.</a>\n\n\n</p>\n<a name=\"sc_developerGuidelines\"></a>\n<h3 class=\"h4\">Developer Guidelines</h3>\n<p>Please follow the  \n<a href=\"http://www.slf4j.org/manual.html\">slf4j manual</a> when creating log statements within code.\nAlso read the\n<a href=\"http://www.slf4j.org/faq.html#logging_performance\">FAQ on performance</a>\n, when creating log statements. Patch reviewers will look for the following:</p>\n<a name=\"sc_rightLevel\"></a>\n<h4>Logging at the Right Level</h4>\n<p>\nThere are several levels of logging in slf4j. \nIt's important to pick the right one. In order of higher to lower severity:</p>\n<ol>\n   \n<li>\n<p>ERROR level designates error events that might still allow the application to continue running.</p>\n</li>\n   \n<li>\n<p>WARN level designates potentially harmful situations.</p>\n</li>\n   \n<li>\n<p>INFO level designates informational messages that highlight the progress of the application at coarse-grained level.</p>\n</li>\n   \n<li>\n<p>DEBUG Level designates fine-grained informational events that are most useful to debug an application.</p>\n</li>\n   \n<li>\n<p>TRACE Level designates finer-grained informational events than the DEBUG.</p>\n</li>\n\n</ol>\n<p>\nZooKeeper is typically run in production such that log messages of INFO level \nseverity and higher (more severe) are output to the log.</p>\n<a name=\"sc_slf4jIdioms\"></a>\n<h4>Use of Standard slf4j Idioms</h4>\n<p>\n<em>Static Message Logging</em>\n</p>\n<pre class=\"code\">\nLOG.debug(\"process completed successfully!\");\n</pre>\n<p>\nHowever when creating parameterized messages are required, use formatting anchors.\n</p>\n<pre class=\"code\">\nLOG.debug(\"got {} messages in {} minutes\",new Object[]{count,time});    \n</pre>\n<p>\n<em>Naming</em>\n</p>\n<p>\nLoggers should be named after the class in which they are used.\n</p>\n<pre class=\"code\">\npublic class Foo {\n    private static final Logger LOG = LoggerFactory.getLogger(Foo.class);\n    ....\n    public Foo() {\n       LOG.info(\"constructing Foo\");\n</pre>\n<p>\n<em>Exception handling</em>\n</p>\n<pre class=\"code\">\ntry {\n  // code\n} catch (XYZException e) {\n  // do this\n  LOG.error(\"Something bad happened\", e);\n  // don't do this (generally)\n  // LOG.error(e);\n  // why? because \"don't do\" case hides the stack trace\n \n  // continue process here as you need... recover or (re)throw\n}\n</pre>\n</div>\n\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperJMX.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper JMX</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.4', 'skin/')\" id=\"menu_selected_1.4Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Admin &amp; Ops</div>\n<div id=\"menu_selected_1.4\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">JMX</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperJMX.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper JMX</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_jmx\">JMX</a>\n</li>\n<li>\n<a href=\"#ch_starting\">Starting ZooKeeper with JMX enabled</a>\n</li>\n<li>\n<a href=\"#ch_console\">Run a JMX console</a>\n</li>\n<li>\n<a href=\"#ch_reference\">ZooKeeper MBean Reference</a>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_jmx\"></a>\n<h2 class=\"h3\">JMX</h2>\n<div class=\"section\">\n<p>Apache ZooKeeper has extensive support for JMX, allowing you\n    to view and manage a ZooKeeper serving ensemble.</p>\n<p>This document assumes that you have basic knowledge of\n    JMX. See <a href=\"http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/\">\n    Sun JMX Technology</a> page to get started with JMX.\n    </p>\n<p>See the <a href=\"http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html\">\n    JMX Management Guide</a> for details on setting up local and\n    remote management of VM instances. By default the included\n    <em>zkServer.sh</em> supports only local management -\n    review the linked document to enable support for remote management\n    (beyond the scope of this document).\n    </p>\n</div>\n\n  \n<a name=\"ch_starting\"></a>\n<h2 class=\"h3\">Starting ZooKeeper with JMX enabled</h2>\n<div class=\"section\">\n<p>The class\n      <em>org.apache.zookeeper.server.quorum.QuorumPeerMain</em>\n      will start a JMX manageable ZooKeeper server. This class\n      registers the proper MBeans during initalization to support JMX\n      monitoring and management of the\n      instance. See <em>bin/zkServer.sh</em> for one\n      example of starting ZooKeeper using QuorumPeerMain.</p>\n</div>\n\n  \n<a name=\"ch_console\"></a>\n<h2 class=\"h3\">Run a JMX console</h2>\n<div class=\"section\">\n<p>There are a number of JMX consoles available which can connect\n      to the running server. For this example we will use Sun's\n      <em>jconsole</em>.</p>\n<p>The Java JDK ships with a simple JMX console\n      named <a href=\"http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html\">jconsole</a>\n      which can be used to connect to ZooKeeper and inspect a running\n      server. Once you've started ZooKeeper using QuorumPeerMain\n      start <em>jconsole</em>, which typically resides in\n      <em>JDK_HOME/bin/jconsole</em>\n</p>\n<p>When the \"new connection\" window is displayed either connect\n      to local process (if jconsole started on same host as Server) or\n      use the remote process connection.</p>\n<p>By default the \"overview\" tab for the VM is displayed (this\n      is a great way to get insight into the VM btw). Select\n      the \"MBeans\" tab.</p>\n<p>You should now see <em>org.apache.ZooKeeperService</em>\n      on the left hand side. Expand this item and depending on how you've\n      started the server you will be able to monitor and manage various\n      service related features.</p>\n<p>Also note that ZooKeeper will register log4j MBeans as\n    well. In the same section along the left hand side you will see\n    \"log4j\". Expand that to manage log4j through JMX. Of particular\n    interest is the ability to dynamically change the logging levels\n    used by editing the appender and root thresholds. Log4j MBean\n    registration can be disabled by passing\n    <em>-Dzookeeper.jmx.log4j.disable=true</em> to the JVM\n    when starting ZooKeeper.\n    </p>\n</div>\n\n  \n<a name=\"ch_reference\"></a>\n<h2 class=\"h3\">ZooKeeper MBean Reference</h2>\n<div class=\"section\">\n<p>This table details JMX for a server participating in a\n    replicated ZooKeeper ensemble (ie not standalone). This is the\n    typical case for a production environment.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<caption>MBeans, their names and description</caption>\n      \n<title>MBeans, their names and description</title>\n\n      \n          \n<tr>\n            \n<th>MBean</th>\n            <th>MBean Object Name</th>\n            <th>Description</th>\n          \n</tr>\n        \n          \n<tr>\n            \n<td>Quorum</td>\n            <td>ReplicatedServer_id&lt;#&gt;</td>\n            <td>Represents the Quorum, or Ensemble - parent of all\n            cluster members. Note that the object name includes the\n            \"myid\" of the server (name suffix) that your JMX agent has\n            connected to.</td>\n          \n</tr>\n          \n<tr>\n            \n<td>LocalPeer|RemotePeer</td>\n            <td>replica.&lt;#&gt;</td>\n            <td>Represents a local or remote peer (ie server\n            participating in the ensemble). Note that the object name\n            includes the \"myid\" of the server (name suffix).</td>\n          \n</tr>\n          \n<tr>\n            \n<td>LeaderElection</td>\n            <td>LeaderElection</td>\n            <td>Represents a ZooKeeper cluster leader election which is\n            in progress. Provides information about the election, such as\n            when it started.</td>\n          \n</tr>\n          \n<tr>\n            \n<td>Leader</td>\n            <td>Leader</td>\n            <td>Indicates that the parent replica is the leader and\n            provides attributes/operations for that server. Note that\n            Leader is a subclass of ZooKeeperServer, so it provides\n            all of the information normally associated with a\n            ZooKeeperServer node.</td>\n          \n</tr>\n          \n<tr>\n            \n<td>Follower</td>\n            <td>Follower</td>\n            <td>Indicates that the parent replica is a follower and\n            provides attributes/operations for that server. Note that\n            Follower is a subclass of ZooKeeperServer, so it provides\n            all of the information normally associated with a\n            ZooKeeperServer node.</td>\n          \n</tr>\n          \n<tr>\n            \n<td>DataTree</td>\n            <td>InMemoryDataTree</td>\n            <td>Statistics on the in memory znode database, also\n            operations to access finer (and more computationally\n            intensive) statistics on the data (such as ephemeral\n            count). InMemoryDataTrees are children of ZooKeeperServer\n            nodes.</td>\n          \n</tr>\n          \n<tr>\n            \n<td>ServerCnxn</td>\n            <td>&lt;session_id&gt;</td>\n            <td>Statistics on each client connection, also\n            operations on those connections (such as\n            termination). Note the object name is the session id of\n            the connection in hex form.</td>\n          \n</tr>\n    \n</table>\n<p>This table details JMX for a standalone server. Typically\n    standalone is only used in development situations.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<caption>MBeans, their names and description</caption>\n      \n<title>MBeans, their names and description</title>\n\n      \n          \n<tr>\n            \n<th>MBean</th>\n            <th>MBean Object Name</th>\n            <th>Description</th>\n          \n</tr>\n        \n          \n<tr>\n            \n<td>ZooKeeperServer</td>\n            <td>StandaloneServer_port&lt;#&gt;</td>\n            <td>Statistics on the running server, also operations\n            to reset these attributes. Note that the object name\n            includes the client port of the server (name\n            suffix).</td>\n          \n</tr>\n          \n<tr>\n            \n<td>DataTree</td>\n            <td>InMemoryDataTree</td>\n            <td>Statistics on the in memory znode database, also\n            operations to access finer (and more computationally\n            intensive) statistics on the data (such as ephemeral\n            count).</td>\n          \n</tr>\n          \n<tr>\n            \n<td>ServerCnxn</td>\n            <td>&lt;session_id&gt;</td>\n            <td>Statistics on each client connection, also\n            operations on those connections (such as\n            termination). Note the object name is the session id of\n            the connection in hex form.</td>\n          \n</tr>\n    \n</table>\n</div>\n\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperObservers.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Observers</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.4', 'skin/')\" id=\"menu_selected_1.4Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Admin &amp; Ops</div>\n<div id=\"menu_selected_1.4\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Observers Guide</div>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperObservers.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Observers</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_Introduction\">Observers: Scaling ZooKeeper Without Hurting Write Performance\n      </a>\n</li>\n<li>\n<a href=\"#sc_UsingObservers\">How to use Observers</a>\n</li>\n<li>\n<a href=\"#ch_UseCases\">Example use cases</a>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_Introduction\"></a>\n<h2 class=\"h3\">Observers: Scaling ZooKeeper Without Hurting Write Performance\n      </h2>\n<div class=\"section\">\n<p>\n      Although ZooKeeper performs very well by having clients connect directly\n      to voting members of the ensemble, this architecture makes it hard to\n      scale out to huge numbers of clients. The problem is that as we add more\n      voting members, the write performance drops. This is due to the fact that\n      a write operation requires the agreement of (in general) at least half the\n      nodes in an ensemble and therefore the cost of a vote can increase\n      significantly as more voters are added.\n    </p>\n<p>\n      We have introduced a new type of ZooKeeper node called\n      an <em>Observer</em> which helps address this problem and\n      further improves ZooKeeper's scalability. Observers are non-voting members\n      of an ensemble which only hear the results of votes, not the agreement\n      protocol that leads up to them. Other than this simple distinction,\n      Observers function exactly the same as Followers - clients may connect to\n      them and send read and write requests to them. Observers forward these\n      requests to the Leader like Followers do, but they then simply wait to\n      hear the result of the vote. Because of this, we can increase the number\n      of Observers as much as we like without harming the performance of votes.\n    </p>\n<p>\n      Observers have other advantages. Because they do not vote, they are not a\n      critical part of the ZooKeeper ensemble. Therefore they can fail, or be\n      disconnected from the cluster, without harming the availability of the\n      ZooKeeper service. The benefit to the user is that Observers may connect\n      over less reliable network links than Followers. In fact, Observers may be\n      used to talk to a ZooKeeper server from another data center. Clients of\n      the Observer will see fast reads, as all reads are served locally, and\n      writes result in minimal network traffic as the number of messages\n      required in the absence of the vote protocol is smaller.\n    </p>\n</div>\n  \n<a name=\"sc_UsingObservers\"></a>\n<h2 class=\"h3\">How to use Observers</h2>\n<div class=\"section\">\n<p>Setting up a ZooKeeper ensemble that uses Observers is very simple,\n    and requires just two changes to your config files. Firstly, in the config\n    file of every node that is to be an Observer, you must place this line:\n    </p>\n<pre class=\"code\">\n      peerType=observer\n    </pre>\n<p>\n      This line tells ZooKeeper that the server is to be an Observer. Secondly,\n      in every server config file, you must add :observer to the server\n      definition line of each Observer. For example:\n    </p>\n<pre class=\"code\">\n      server.1:localhost:2181:3181:observer\n    </pre>\n<p>\n      This tells every other server that server.1 is an Observer, and that they\n      should not expect it to vote. This is all the configuration you need to do\n      to add an Observer to your ZooKeeper cluster. Now you can connect to it as\n      though it were an ordinary Follower. Try it out, by running:</p>\n<pre class=\"code\">\n      $ bin/zkCli.sh -server localhost:2181\n    </pre>\n<p>\n      where localhost:2181 is the hostname and port number of the Observer as\n      specified in every config file. You should see a command line prompt\n      through which you can issue commands like <em>ls</em> to query\n      the ZooKeeper service.\n    </p>\n</div>\n  \n  \n<a name=\"ch_UseCases\"></a>\n<h2 class=\"h3\">Example use cases</h2>\n<div class=\"section\">\n<p>\n      Two example use cases for Observers are listed below. In fact, wherever\n      you wish to scale the numbe of clients of your ZooKeeper ensemble, or\n      where you wish to insulate the critical part of an ensemble from the load\n      of dealing with client requests, Observers are a good architectural\n      choice.\n    </p>\n<ul>\n      \n<li>\n\t\n<p> As a datacenter bridge: Forming a ZK ensemble between two\n\tdatacenters is a problematic endeavour as the high variance in latency\n\tbetween the datacenters could lead to false positive failure detection\n\tand partitioning. However if the ensemble runs entirely in one\n\tdatacenter, and the second datacenter runs only Observers, partitions\n\taren't problematic as the ensemble remains connected. Clients of the\n\tObservers may still see and issue proposals.</p>\n      \n</li>\n      \n<li>\n\t\n<p>As a link to a message bus: Some companies have expressed an\n\tinterest in using ZK as a component of a persistent reliable message\n\tbus. Observers would give a natural integration point for this work: a\n\tplug-in mechanism could be used to attach the stream of proposals an\n\tObserver sees to a publish-subscribe system, again without loading the\n\tcore ensemble.\n\t</p>\n      \n</li>\n    \n</ul>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperOtherInfo.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.8\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://hadoop.apache.org/\">Hadoop</a> &gt; <a href=\"http://hadoop.apache.org/zookeeper/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://hadoop.apache.org/zookeeper/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"The Hadoop database\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"hadoop.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://hadoop.apache.org/zookeeper/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"http://wiki.apache.org/hadoop/ZooKeeper\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.5', 'skin/')\" id=\"menu_selected_1.5Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Informal Documentation</div>\n<div id=\"menu_selected_1.5\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"http://wiki.apache.org/hadoop/ZooKeeper\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://wiki.apache.org/hadoop/ZooKeeper/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://hadoop.apache.org/zookeeper/mailing_lists.html\">Mailing Lists</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Other Info</div>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperOtherInfo.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper</h1>\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_placeholder\">Other Info</a>\n</li>\n</ul>\n</div>\n  \n\n  \n\n  \n<a name=\"N10009\"></a><a name=\"ch_placeholder\"></a>\n<h2 class=\"h3\">Other Info</h2>\n<div class=\"section\">\n<p> currently empty </p>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n         2008 <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperOver.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_selected_1.1', 'skin/')\" id=\"menu_selected_1.1Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Overview</div>\n<div id=\"menu_selected_1.1\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Overview</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperOver.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_DesignOverview\">ZooKeeper: A Distributed Coordination Service for Distributed\n    Applications</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_designGoals\">Design Goals</a>\n</li>\n<li>\n<a href=\"#sc_dataModelNameSpace\">Data model and the hierarchical namespace</a>\n</li>\n<li>\n<a href=\"#Nodes+and+ephemeral+nodes\">Nodes and ephemeral nodes</a>\n</li>\n<li>\n<a href=\"#Conditional+updates+and+watches\">Conditional updates and watches</a>\n</li>\n<li>\n<a href=\"#Guarantees\">Guarantees</a>\n</li>\n<li>\n<a href=\"#Simple+API\">Simple API</a>\n</li>\n<li>\n<a href=\"#Implementation\">Implementation</a>\n</li>\n<li>\n<a href=\"#Uses\">Uses</a>\n</li>\n<li>\n<a href=\"#Performance\">Performance</a>\n</li>\n<li>\n<a href=\"#Reliability\">Reliability</a>\n</li>\n<li>\n<a href=\"#The+ZooKeeper+Project\">The ZooKeeper Project</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_DesignOverview\"></a>\n<h2 class=\"h3\">ZooKeeper: A Distributed Coordination Service for Distributed\n    Applications</h2>\n<div class=\"section\">\n<p>ZooKeeper is a distributed, open-source coordination service for\n    distributed applications. It exposes a simple set of primitives that\n    distributed applications can build upon to implement higher level services\n    for synchronization, configuration maintenance, and groups and naming. It\n    is designed to be easy to program to, and uses a data model styled after\n    the familiar directory tree structure of file systems. It runs in Java and\n    has bindings for both Java and C.</p>\n<p>Coordination services are notoriously hard to get right. They are\n    especially prone to errors such as race conditions and deadlock. The\n    motivation behind ZooKeeper is to relieve distributed applications the\n    responsibility of implementing coordination services from scratch.</p>\n<a name=\"sc_designGoals\"></a>\n<h3 class=\"h4\">Design Goals</h3>\n<p>\n<strong>ZooKeeper is simple.</strong> ZooKeeper\n      allows distributed processes to coordinate with each other through a\n      shared hierarchal namespace which is organized similarly to a standard\n      file system. The name space consists of data registers - called znodes,\n      in ZooKeeper parlance - and these are similar to files and directories.\n      Unlike a typical file system, which is designed for storage, ZooKeeper\n      data is kept in-memory, which means ZooKeeper can acheive high\n      throughput and low latency numbers.</p>\n<p>The ZooKeeper implementation puts a premium on high performance,\n      highly available, strictly ordered access. The performance aspects of\n      ZooKeeper means it can be used in large, distributed systems. The\n      reliability aspects keep it from being a single point of failure. The\n      strict ordering means that sophisticated synchronization primitives can\n      be implemented at the client.</p>\n<p>\n<strong>ZooKeeper is replicated.</strong> Like the\n      distributed processes it coordinates, ZooKeeper itself is intended to be\n      replicated over a sets of hosts called an ensemble.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>ZooKeeper Service</td>\n</tr>\n<tr>\n<td>\n          \n            <img alt=\"\" src=\"images/zkservice.jpg\">\n          \n        </td>\n</tr>\n</table>\n<p>The servers that make up the ZooKeeper service must all know about\n      each other. They maintain an in-memory image of state, along with a\n      transaction logs and snapshots in a persistent store. As long as a\n      majority of the servers are available, the ZooKeeper service will be\n      available.</p>\n<p>Clients connect to a single ZooKeeper server. The client maintains\n      a TCP connection through which it sends requests, gets responses, gets\n      watch events, and sends heart beats. If the TCP connection to the server\n      breaks, the client will connect to a different server.</p>\n<p>\n<strong>ZooKeeper is ordered.</strong> ZooKeeper\n      stamps each update with a number that reflects the order of all\n      ZooKeeper transactions. Subsequent operations can use the order to\n      implement higher-level abstractions, such as synchronization\n      primitives.</p>\n<p>\n<strong>ZooKeeper is fast.</strong> It is\n      especially fast in \"read-dominant\" workloads. ZooKeeper applications run\n      on thousands of machines, and it performs best where reads are more\n      common than writes, at ratios of around 10:1.</p>\n<a name=\"sc_dataModelNameSpace\"></a>\n<h3 class=\"h4\">Data model and the hierarchical namespace</h3>\n<p>The name space provided by ZooKeeper is much like that of a\n      standard file system. A name is a sequence of path elements separated by\n      a slash (/). Every node in ZooKeeper's name space is identified by a\n      path.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>ZooKeeper's Hierarchical Namespace</td>\n</tr>\n<tr>\n<td>\n          \n            <img alt=\"\" src=\"images/zknamespace.jpg\">\n          \n        </td>\n</tr>\n</table>\n<a name=\"Nodes+and+ephemeral+nodes\"></a>\n<h3 class=\"h4\">Nodes and ephemeral nodes</h3>\n<p>Unlike is standard file systems, each node in a ZooKeeper\n      namespace can have data associated with it as well as children. It is\n      like having a file-system that allows a file to also be a directory.\n      (ZooKeeper was designed to store coordination data: status information,\n      configuration, location information, etc., so the data stored at each\n      node is usually small, in the byte to kilobyte range.) We use the term\n      <em>znode</em> to make it clear that we are talking about\n      ZooKeeper data nodes.</p>\n<p>Znodes maintain a stat structure that includes version numbers for\n      data changes, ACL changes, and timestamps, to allow cache validations\n      and coordinated updates. Each time a znode's data changes, the version\n      number increases. For instance, whenever a client retrieves data it also\n      receives the version of the data.</p>\n<p>The data stored at each znode in a namespace is read and written\n      atomically. Reads get all the data bytes associated with a znode and a\n      write replaces all the data. Each node has an Access Control List (ACL)\n      that restricts who can do what.</p>\n<p>ZooKeeper also has the notion of ephemeral nodes. These znodes\n      exists as long as the session that created the znode is active. When the\n      session ends the znode is deleted. Ephemeral nodes are useful when you\n      want to implement <em>[tbd]</em>.</p>\n<a name=\"Conditional+updates+and+watches\"></a>\n<h3 class=\"h4\">Conditional updates and watches</h3>\n<p>ZooKeeper supports the concept of <em>watches</em>.\n      Clients can set a watch on a znodes. A watch will be triggered and\n      removed when the znode changes. When a watch is triggered the client\n      receives a packet saying that the znode has changed. And if the\n      connection between the client and one of the Zoo Keeper servers is\n      broken, the client will receive a local notification. These can be used\n      to <em>[tbd]</em>.</p>\n<a name=\"Guarantees\"></a>\n<h3 class=\"h4\">Guarantees</h3>\n<p>ZooKeeper is very fast and very simple. Since its goal, though, is\n      to be a basis for the construction of more complicated services, such as\n      synchronization, it provides a set of guarantees. These are:</p>\n<ul>\n        \n<li>\n          \n<p>Sequential Consistency - Updates from a client will be applied\n          in the order that they were sent.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Atomicity - Updates either succeed or fail. No partial\n          results.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Single System Image - A client will see the same view of the\n          service regardless of the server that it connects to.</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>Reliability - Once an update has been applied, it will persist\n          from that time forward until a client overwrites the update.</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>Timeliness - The clients view of the system is guaranteed to\n          be up-to-date within a certain time bound.</p>\n        \n</li>\n      \n</ul>\n<p>For more information on these, and how they can be used, see\n      <em>[tbd]</em>\n</p>\n<a name=\"Simple+API\"></a>\n<h3 class=\"h4\">Simple API</h3>\n<p>One of the design goals of ZooKeeper is provide a very simple\n      programming interface. As a result, it supports only these\n      operations:</p>\n<dl>\n        \n<dt>\n<term>create</term>\n</dt>\n<dd>\n<p>creates a node at a location in the tree</p>\n</dd>\n\n        \n<dt>\n<term>delete</term>\n</dt>\n<dd>\n<p>deletes a node</p>\n</dd>\n\n        \n<dt>\n<term>exists</term>\n</dt>\n<dd>\n<p>tests if a node exists at a location</p>\n</dd>\n\n        \n<dt>\n<term>get data</term>\n</dt>\n<dd>\n<p>reads the data from a node</p>\n</dd>\n\n        \n<dt>\n<term>set data</term>\n</dt>\n<dd>\n<p>writes data to a node</p>\n</dd>\n\n        \n<dt>\n<term>get children</term>\n</dt>\n<dd>\n<p>retrieves a list of children of a node</p>\n</dd>\n\n        \n<dt>\n<term>sync</term>\n</dt>\n<dd>\n<p>waits for data to be propagated</p>\n</dd>\n      \n</dl>\n<p>For a more in-depth discussion on these, and how they can be used\n      to implement higher level operations, please refer to\n      <em>[tbd]</em>\n</p>\n<a name=\"Implementation\"></a>\n<h3 class=\"h4\">Implementation</h3>\n<p>\n<a href=\"#fg_zkComponents\">ZooKeeper Components</a> shows the high-level components\n      of the ZooKeeper service. With the exception of the request processor,\n     each of\n      the servers that make up the ZooKeeper service replicates its own copy\n      of each of components.</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>ZooKeeper Components</td>\n</tr>\n<tr>\n<td>\n          \n            <img alt=\"\" src=\"images/zkcomponents.jpg\">\n          \n        </td>\n</tr>\n</table>\n<p>The replicated database is an in-memory database containing the\n      entire data tree. Updates are logged to disk for recoverability, and\n      writes are serialized to disk before they are applied to the in-memory\n      database.</p>\n<p>Every ZooKeeper server services clients. Clients connect to\n      exactly one server to submit irequests. Read requests are serviced from\n      the local replica of each server database. Requests that change the\n      state of the service, write requests, are processed by an agreement\n      protocol.</p>\n<p>As part of the agreement protocol all write requests from clients\n      are forwarded to a single server, called the\n      <em>leader</em>. The rest of the ZooKeeper servers, called\n      <em>followers</em>, receive message proposals from the\n      leader and agree upon message delivery. The messaging layer takes care\n      of replacing leaders on failures and syncing followers with\n      leaders.</p>\n<p>ZooKeeper uses a custom atomic messaging protocol. Since the\n      messaging layer is atomic, ZooKeeper can guarantee that the local\n      replicas never diverge. When the leader receives a write request, it\n      calculates what the state of the system is when the write is to be\n      applied and transforms this into a transaction that captures this new\n      state.</p>\n<a name=\"Uses\"></a>\n<h3 class=\"h4\">Uses</h3>\n<p>The programming interface to ZooKeeper is deliberately simple.\n      With it, however, you can implement higher order operations, such as\n      synchronizations primitives, group membership, ownership, etc. Some\n      distributed applications have used it to: <em>[tbd: add uses from\n      white paper and video presentation.]</em> For more information, see\n      <em>[tbd]</em>\n</p>\n<a name=\"Performance\"></a>\n<h3 class=\"h4\">Performance</h3>\n<p>ZooKeeper is designed to be highly performant. But is it? The\n      results of the ZooKeeper's development team at Yahoo! Research indicate\n      that it is. (See <a href=\"#fg_zkPerfRW\">ZooKeeper Throughput as the Read-Write Ratio Varies</a>.) It is especially high\n      performance in applications where reads outnumber writes, since writes\n      involve synchronizing the state of all servers. (Reads outnumbering\n      writes is typically the case for a coordination service.)</p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>ZooKeeper Throughput as the Read-Write Ratio Varies</td>\n</tr>\n<tr>\n<td>\n          \n            <img alt=\"\" src=\"images/zkperfRW-3.2.jpg\">\n          \n        </td>\n</tr>\n</table>\n<p>The figure <a href=\"#fg_zkPerfRW\">ZooKeeper Throughput as the Read-Write Ratio Varies</a> is a throughput\n      graph of ZooKeeper release 3.2 running on servers with dual 2Ghz\n      Xeon and two SATA 15K RPM drives.  One drive was used as a\n      dedicated ZooKeeper log device. The snapshots were written to\n      the OS drive. Write requests were 1K writes and the reads were\n      1K reads.  \"Servers\" indicate the size of the ZooKeeper\n      ensemble, the number of servers that make up the\n      service. Approximately 30 other servers were used to simulate\n      the clients. The ZooKeeper ensemble was configured such that\n      leaders do not allow connections from clients.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n<p>In version 3.2 r/w performance improved by ~2x\n      compared to the <a href=\"http://zookeeper.apache.org/docs/r3.1.1/zookeeperOver.html#Performance\">previous\n      3.1 release</a>.</p>\n</div>\n</div>\n<p>Benchmarks also indicate that it is reliable, too. <a href=\"#fg_zkPerfReliability\">Reliability in the Presence of Errors</a> shows how a deployment responds to\n      various failures. The events marked in the figure are the\n      following:</p>\n<ol>\n        \n<li>\n          \n<p>Failure and recovery of a follower</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Failure and recovery of a different follower</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Failure of the leader</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Failure and recovery of two followers</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Failure of another leader</p>\n        \n</li>\n      \n</ol>\n<a name=\"Reliability\"></a>\n<h3 class=\"h4\">Reliability</h3>\n<p>To show the behavior of the system over time as\n        failures are injected we ran a ZooKeeper service made up of\n        7 machines. We ran the same saturation benchmark as before,\n        but this time we kept the write percentage at a constant\n        30%, which is a conservative ratio of our expected\n        workloads.\n      </p>\n<table class=\"ForrestTable\" cellspacing=\"1\" cellpadding=\"4\">\n<tr>\n<td>Reliability in the Presence of Errors</td>\n</tr>\n<tr>\n<td>\n          \n            <img alt=\"\" src=\"images/zkperfreliability.jpg\">\n          \n        </td>\n</tr>\n</table>\n<p>The are a few important observations from this graph. First, if\n      followers fail and recover quickly, then ZooKeeper is able to sustain a\n      high throughput despite the failure. But maybe more importantly, the\n      leader election algorithm allows for the system to recover fast enough\n      to prevent throughput from dropping substantially. In our observations,\n      ZooKeeper takes less than 200ms to elect a new leader. Third, as\n      followers recover, ZooKeeper is able to raise throughput again once they\n      start processing requests.</p>\n<a name=\"The+ZooKeeper+Project\"></a>\n<h3 class=\"h4\">The ZooKeeper Project</h3>\n<p>ZooKeeper has been\n          <a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/PoweredBy\">\n          successfully used\n        </a>\n        in many industrial applications.  It is used at Yahoo! as the\n        coordination and failure recovery service for Yahoo! Message\n        Broker, which is a highly scalable publish-subscribe system\n        managing thousands of topics for replication and data\n        delivery.  It is used by the Fetching Service for Yahoo!\n        crawler, where it also manages failure recovery. A number of\n        Yahoo! advertising systems also use ZooKeeper to implement\n        reliable services.\n      </p>\n<p>All users and developers are encouraged to join the\n        community and contribute their expertise. See the\n        <a href=\"http://zookeeper.apache.org/\">\n          Zookeeper Project on Apache\n        </a>\n        for more information.\n      </p>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperProgrammers.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Programmer's Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.2', 'skin/')\" id=\"menu_selected_1.2Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Developer</div>\n<div id=\"menu_selected_1.2\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Programmer's Guide</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperProgrammers.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Programmer's Guide</h1>\n<h3>Developing Distributed Applications that use ZooKeeper</h3>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#_introduction\">Introduction</a>\n</li>\n<li>\n<a href=\"#ch_zkDataModel\">The ZooKeeper Data Model</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_zkDataModel_znodes\">ZNodes</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_zkDataMode_watches\">Watches</a>\n</li>\n<li>\n<a href=\"#Data+Access\">Data Access</a>\n</li>\n<li>\n<a href=\"#Ephemeral+Nodes\">Ephemeral Nodes</a>\n</li>\n<li>\n<a href=\"#Sequence+Nodes+--+Unique+Naming\">Sequence Nodes -- Unique Naming</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_timeInZk\">Time in ZooKeeper</a>\n</li>\n<li>\n<a href=\"#sc_zkStatStructure\">ZooKeeper Stat Structure</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#ch_zkSessions\">ZooKeeper Sessions</a>\n</li>\n<li>\n<a href=\"#ch_zkWatches\">ZooKeeper Watches</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_WatchSemantics\">Semantics of Watches</a>\n</li>\n<li>\n<a href=\"#sc_WatchGuarantees\">What ZooKeeper Guarantees about Watches</a>\n</li>\n<li>\n<a href=\"#sc_WatchRememberThese\">Things to Remember about Watches</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_ZooKeeperAccessControl\">ZooKeeper access control using ACLs</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_ACLPermissions\">ACL Permissions</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_BuiltinACLSchemes\">Builtin ACL Schemes</a>\n</li>\n<li>\n<a href=\"#ZooKeeper+C+client+API\">ZooKeeper C client API</a>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#sc_ZooKeeperPluggableAuthentication\">Pluggable ZooKeeper authentication</a>\n</li>\n<li>\n<a href=\"#ch_zkGuarantees\">Consistency Guarantees</a>\n</li>\n<li>\n<a href=\"#ch_bindings\">Bindings</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Java+Binding\">Java Binding</a>\n</li>\n<li>\n<a href=\"#C+Binding\">C Binding</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Installation\">Installation</a>\n</li>\n<li>\n<a href=\"#Building+Your+Own+C+Client\">Building Your Own C Client</a>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#ch_guideToZkOperations\">Building Blocks: A Guide to ZooKeeper Operations</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_errorsZk\">Handling Errors</a>\n</li>\n<li>\n<a href=\"#sc_connectingToZk\">Connecting to ZooKeeper</a>\n</li>\n<li>\n<a href=\"#sc_readOps\">Read Operations</a>\n</li>\n<li>\n<a href=\"#sc_writeOps\">Write Operations</a>\n</li>\n<li>\n<a href=\"#sc_handlingWatches\">Handling Watches</a>\n</li>\n<li>\n<a href=\"#sc_miscOps\">Miscelleaneous ZooKeeper Operations</a>\n</li>\n</ul>\n</li>\n<li>\n<a href=\"#ch_programStructureWithExample\">Program Structure, with Simple Example</a>\n</li>\n<li>\n<a href=\"#ch_gotchas\">Gotchas: Common Problems and Troubleshooting</a>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n\n  \n<a name=\"_introduction\"></a>\n<h2 class=\"h3\">Introduction</h2>\n<div class=\"section\">\n<p>This document is a guide for developers wishing to create\n    distributed applications that take advantage of ZooKeeper's coordination\n    services. It contains conceptual and practical information.</p>\n<p>The first four sections of this guide present higher level\n    discussions of various ZooKeeper concepts. These are necessary both for an\n    understanding of how ZooKeeper works as well how to work with it. It does\n    not contain source code, but it does assume a familiarity with the\n    problems associated with distributed computing. The sections in this first\n    group are:</p>\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#ch_zkDataModel\">The ZooKeeper Data Model</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_zkSessions\">ZooKeeper Sessions</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_zkWatches\">ZooKeeper Watches</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_zkGuarantees\">Consistency Guarantees</a>\n</p>\n      \n</li>\n    \n</ul>\n<p>The next four sections provide practical programming\n    information. These are:</p>\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#ch_guideToZkOperations\">Building Blocks: A Guide to ZooKeeper Operations</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_bindings\">Bindings</a>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_programStructureWithExample\">Program Structure, with Simple Example</a>\n        <em>[tbd]</em>\n</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<a href=\"#ch_gotchas\">Gotchas: Common Problems and Troubleshooting</a>\n</p>\n      \n</li>\n    \n</ul>\n<p>The book concludes with an <a href=\"#apx_linksToOtherInfo\">appendix</a> containing links to other\n    useful, ZooKeeper-related information.</p>\n<p>Most of information in this document is written to be accessible as\n    stand-alone reference material. However, before starting your first\n    ZooKeeper application, you should probably at least read the chaptes on\n    the <a href=\"#ch_zkDataModel\">ZooKeeper Data Model</a> and <a href=\"#ch_guideToZkOperations\">ZooKeeper Basic Operations</a>. Also,\n    the <a href=\"#ch_programStructureWithExample\">Simple Programmming\n    Example</a> <em>[tbd]</em> is helpful for understanding the basic\n    structure of a ZooKeeper client application.</p>\n</div>\n\n  \n<a name=\"ch_zkDataModel\"></a>\n<h2 class=\"h3\">The ZooKeeper Data Model</h2>\n<div class=\"section\">\n<p>ZooKeeper has a hierarchal name space, much like a distributed file\n    system. The only difference is that each node in the namespace can have\n    data associated with it as well as children. It is like having a file\n    system that allows a file to also be a directory. Paths to nodes are\n    always expressed as canonical, absolute, slash-separated paths; there are\n    no relative reference. Any unicode character can be used in a path subject\n    to the following constraints:</p>\n<ul>\n      \n<li>\n        \n<p>The null character (\\u0000) cannot be part of a path name. (This\n        causes problems with the C binding.)</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The following characters can't be used because they don't\n        display well, or render in confusing ways: \\u0001 - \\u0019 and \\u007F\n        - \\u009F.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The following characters are not allowed: \\ud800 -uF8FFF,\n        \\uFFF0 - uFFFF.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The \".\" character can be used as part of another name, but \".\"\n        and \"..\" cannot alone be used to indicate a node along a path,\n        because ZooKeeper doesn't use relative paths. The following would be\n        invalid: \"/a/b/./c\" or \"/a/b/../c\".</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The token \"zookeeper\" is reserved.</p>\n      \n</li>\n    \n</ul>\n<a name=\"sc_zkDataModel_znodes\"></a>\n<h3 class=\"h4\">ZNodes</h3>\n<p>Every node in a ZooKeeper tree is referred to as a\n      <em>znode</em>. Znodes maintain a stat structure that\n      includes version numbers for data changes, acl changes. The stat\n      structure also has timestamps. The version number, together with the\n      timestamp, allows ZooKeeper to validate the cache and to coordinate\n      updates. Each time a znode's data changes, the version number increases.\n      For instance, whenever a client retrieves data, it also receives the\n      version of the data. And when a client performs an update or a delete,\n      it must supply the version of the data of the znode it is changing. If\n      the version it supplies doesn't match the actual version of the data,\n      the update will fail. (This behavior can be overridden. For more\n      information see... )<em>[tbd...]</em>\n</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n        \n<p>In distributed application engineering, the word\n        <em>node</em> can refer to a generic host machine, a\n        server, a member of an ensemble, a client process, etc. In the ZooKeeper\n        documentation, <em>znodes</em> refer to the data nodes.\n        <em>Servers</em>  refer to machines that make up the\n        ZooKeeper service; <em>quorum peers</em> refer to the\n        servers that make up an ensemble; client refers to any host or process\n        which uses a ZooKeeper service.</p>\n      \n</div>\n</div>\n<p> A znode is the main abstraction a programmer needs to be aware of. Znodes have\n      several characteristics that are worth mentioning here.</p>\n<a name=\"sc_zkDataMode_watches\"></a>\n<h4>Watches</h4>\n<p>Clients can set watches on znodes. Changes to that znode trigger\n        the watch and then clear the watch. When a watch triggers, ZooKeeper\n        sends the client a notification. More information about watches can be\n        found in the section \n\t    <a href=\"#ch_zkWatches\">ZooKeeper Watches</a>.</p>\n<a name=\"Data+Access\"></a>\n<h4>Data Access</h4>\n<p>The data stored at each znode in a namespace is read and written\n        atomically. Reads get all the data bytes associated with a znode and a\n        write replaces all the data. Each node has an Access Control List\n        (ACL) that restricts who can do what.</p>\n<p>ZooKeeper was not designed to be a general database or large\n        object store. Instead, it manages coordination data. This data can\n        come in the form of configuration, status information, rendezvous, etc.\n        A common property of the various forms of coordination data is that\n        they are relatively small: measured in kilobytes.\n        The ZooKeeper client and the server implementations have sanity checks\n        to ensure that znodes have less than 1M of data, but the data should\n        be much less than that on average. Operating on relatively large data\n        sizes will cause some operations to take much more time than others and\n        will affect the latencies of some operations because of the extra time\n        needed to move more data over the network and onto storage media. If\n        large data storage is needed, the usually pattern of dealing with such\n        data is to store it on a bulk storage system, such as NFS or HDFS, and\n        store pointers to the storage locations in ZooKeeper.</p>\n<a name=\"Ephemeral+Nodes\"></a>\n<h4>Ephemeral Nodes</h4>\n<p>ZooKeeper also has the notion of ephemeral nodes. These znodes\n        exists as long as the session that created the znode is active. When\n        the session ends the znode is deleted. Because of this behavior\n        ephemeral znodes are not allowed to have children.</p>\n<a name=\"Sequence+Nodes+--+Unique+Naming\"></a>\n<h4>Sequence Nodes -- Unique Naming</h4>\n<p>When creating a znode you can also request that\n        ZooKeeper append a monotonically increasing counter to the end\n        of path. This counter is unique to the parent znode. The\n        counter has a format of %010d -- that is 10 digits with 0\n        (zero) padding (the counter is formatted in this way to\n        simplify sorting), i.e. \"&lt;path&gt;0000000001\". See\n        <a href=\"recipes.html#sc_recipes_Queues\">Queue\n        Recipe</a> for an example use of this feature. Note: the\n        counter used to store the next sequence number is a signed int\n        (4bytes) maintained by the parent node, the counter will\n        overflow when incremented beyond 2147483647 (resulting in a\n        name \"&lt;path&gt;-2147483648\").</p>\n<a name=\"sc_timeInZk\"></a>\n<h3 class=\"h4\">Time in ZooKeeper</h3>\n<p>ZooKeeper tracks time multiple ways:</p>\n<ul>\n        \n<li>\n          \n<p>\n<strong>Zxid</strong>\n</p>\n\n          \n<p>Every change to the ZooKeeper state receives a stamp in the\n          form of a <em>zxid</em> (ZooKeeper Transaction Id).\n          This exposes the total ordering of all changes to ZooKeeper. Each\n          change will have a unique zxid and if zxid1 is smaller than zxid2\n          then zxid1 happened before zxid2.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>Version numbers</strong>\n</p>\n\n          \n<p>Every change to a node will cause an increase to one of the\n          version numbers of that node. The three version numbers are version\n          (number of changes to the data of a znode), cversion (number of\n          changes to the children of a znode), and aversion (number of changes\n          to the ACL of a znode).</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>Ticks</strong>\n</p>\n\n          \n<p>When using multi-server ZooKeeper, servers use ticks to define\n          timing of events such as status uploads, session timeouts,\n          connection timeouts between peers, etc. The tick time is only\n          indirectly exposed through the minimum session timeout (2 times the\n          tick time); if a client requests a session timeout less than the\n          minimum session timeout, the server will tell the client that the\n          session timeout is actually the minimum session timeout.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>Real time</strong>\n</p>\n\n          \n<p>ZooKeeper doesn't use real time, or clock time, at all except\n          to put timestamps into the stat structure on znode creation and\n          znode modification.</p>\n        \n</li>\n      \n</ul>\n<a name=\"sc_zkStatStructure\"></a>\n<h3 class=\"h4\">ZooKeeper Stat Structure</h3>\n<p>The Stat structure for each znode in ZooKeeper is made up of the\n      following fields:</p>\n<ul>\n        \n<li>\n          \n<p>\n<strong>czxid</strong>\n</p>\n\n          \n<p>The zxid of the change that caused this znode to be\n          created.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>mzxid</strong>\n</p>\n\n          \n<p>The zxid of the change that last modified this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>pzxid</strong>\n</p>\n\n          \n<p>The zxid of the change that last modified children of this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>ctime</strong>\n</p>\n\n          \n<p>The time in milliseconds from epoch when this znode was\n          created.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>mtime</strong>\n</p>\n\n          \n<p>The time in milliseconds from epoch when this znode was last\n          modified.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>version</strong>\n</p>\n\n          \n<p>The number of changes to the data of this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>cversion</strong>\n</p>\n\n          \n<p>The number of changes to the children of this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>aversion</strong>\n</p>\n\n          \n<p>The number of changes to the ACL of this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>ephemeralOwner</strong>\n</p>\n\n          \n<p>The session id of the owner of this znode if the znode is an\n          ephemeral node. If it is not an ephemeral node, it will be\n          zero.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>dataLength</strong>\n</p>\n\n          \n<p>The length of the data field of this znode.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<strong>numChildren</strong>\n</p>\n\n          \n<p>The number of children of this znode.</p>\n        \n</li>\n\n      \n</ul>\n</div>\n\n  \n<a name=\"ch_zkSessions\"></a>\n<h2 class=\"h3\">ZooKeeper Sessions</h2>\n<div class=\"section\">\n<p>A ZooKeeper client establishes a session with the ZooKeeper\n    service by creating a handle to the service using a language\n    binding. Once created, the handle starts of in the CONNECTING state\n    and the client library tries to connect to one of the servers that\n    make up the ZooKeeper service at which point it switches to the\n    CONNECTED state. During normal operation will be in one of these\n    two states. If an unrecoverable error occurs, such as session\n    expiration or authentication failure, or if the application explicitly\n    closes the handle, the handle will move to the CLOSED state.\n    The following figure shows the possible state transitions of a\n    ZooKeeper client:</p>\n<img alt=\"\" src=\"images/state_dia.jpg\"><p>To create a client session the application code must provide\n    a connection string containing a comma separated list of host:port pairs,\n    each corresponding to a ZooKeeper server (e.g. \"127.0.0.1:4545\" or\n    \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"). The ZooKeeper\n    client library will pick an arbitrary server and try to connect to\n    it. If this connection fails, or if the client becomes\n    disconnected from the server for any reason, the client will\n    automatically try the next server in the list, until a connection\n    is (re-)established.</p>\n<p> \n<strong>Added in 3.2.0</strong>: An\n    optional \"chroot\" suffix may also be appended to the connection\n    string. This will run the client commands while interpreting all\n    paths relative to this root (similar to the unix chroot\n    command). If used the example would look like:\n    \"127.0.0.1:4545/app/a\" or\n    \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\" where the\n    client would be rooted at \"/app/a\" and all paths would be relative\n    to this root - ie getting/setting/etc...  \"/foo/bar\" would result\n    in operations being run on \"/app/a/foo/bar\" (from the server\n    perspective). This feature is particularly useful in multi-tenant\n    environments where each user of a particular ZooKeeper service\n    could be rooted differently. This makes re-use much simpler as\n    each user can code his/her application as if it were rooted at\n    \"/\", while actual location (say /app/a) could be determined at\n    deployment time.</p>\n<p>When a client gets a handle to the ZooKeeper service,\n    ZooKeeper creates a ZooKeeper session, represented as a 64-bit\n    number, that it assigns to the client. If the client connects to a\n    different ZooKeeper server, it will send the session id as a part\n    of the connection handshake.  As a security measure, the server\n    creates a password for the session id that any ZooKeeper server\n    can validate.The password is sent to the client with the session\n    id when the client establishes the session. The client sends this\n    password with the session id whenever it reestablishes the session\n    with a new server.</p>\n<p>One of the parameters to the ZooKeeper client library call\n    to create a ZooKeeper session is the session timeout in\n    milliseconds. The client sends a requested timeout, the server\n    responds with the timeout that it can give the client. The current\n    implementation requires that the timeout be a minimum of 2 times\n    the tickTime (as set in the server configuration) and a maximum of\n    20 times the tickTime. The ZooKeeper client API allows access to\n    the negotiated timeout.</p>\n<p>When a client (session) becomes partitioned from the ZK\n    serving cluster it will begin searching the list of servers that\n    were specified during session creation. Eventually, when\n    connectivity between the client and at least one of the servers is\n    re-established, the session will either again transition to the\n    \"connected\" state (if reconnected within the session timeout\n    value) or it will transition to the \"expired\" state (if\n    reconnected after the session timeout). It is not advisable to\n    create a new session object (a new ZooKeeper.class or zookeeper\n    handle in the c binding) for disconnection. The ZK client library\n    will handle reconnect for you. In particular we have heuristics\n    built into the client library to handle things like \"herd effect\",\n    etc... Only create a new session when you are notified of session\n    expiration (mandatory).</p>\n<p>Session expiration is managed by the ZooKeeper cluster\n    itself, not by the client. When the ZK client establishes a\n    session with the cluster it provides a \"timeout\" value detailed\n    above. This value is used by the cluster to determine when the\n    client's session expires. Expirations happens when the cluster\n    does not hear from the client within the specified session timeout\n    period (i.e. no heartbeat). At session expiration the cluster will\n    delete any/all ephemeral nodes owned by that session and\n    immediately notify any/all connected clients of the change (anyone\n    watching those znodes). At this point the client of the expired\n    session is still disconnected from the cluster, it will not be\n    notified of the session expiration until/unless it is able to\n    re-establish a connection to the cluster. The client will stay in\n    disconnected state until the TCP connection is re-established with\n    the cluster, at which point the watcher of the expired session\n    will receive the \"session expired\" notification.</p>\n<p>Example state transitions for an expired session as seen by\n    the expired session's watcher:</p>\n<ol>\n      \n<li>\n<p>'connected' : session is established and client\n      is communicating with cluster (client/server communication is\n      operating properly)</p>\n</li>\n      \n<li>\n<p>.... client is partitioned from the\n      cluster</p>\n</li>\n      \n<li>\n<p>'disconnected' : client has lost connectivity\n      with the cluster</p>\n</li>\n      \n<li>\n<p>.... time elapses, after 'timeout' period the\n      cluster expires the session, nothing is seen by client as it is\n      disconnected from cluster</p>\n</li>\n      \n<li>\n<p>.... time elapses, the client regains network\n      level connectivity with the cluster</p>\n</li>\n      \n<li>\n<p>'expired' : eventually the client reconnects to\n      the cluster, it is then notified of the\n      expiration</p>\n</li>\n    \n</ol>\n<p>Another parameter to the ZooKeeper session establishment\n    call is the default watcher. Watchers are notified when any state\n    change occurs in the client. For example if the client loses\n    connectivity to the server the client will be notified, or if the\n    client's session expires, etc... This watcher should consider the\n    initial state to be disconnected (i.e. before any state changes\n    events are sent to the watcher by the client lib). In the case of\n    a new connection, the first event sent to the watcher is typically\n    the session connection event.</p>\n<p>The session is kept alive by requests sent by the client. If\n    the session is idle for a period of time that would timeout the\n    session, the client will send a PING request to keep the session\n    alive. This PING request not only allows the ZooKeeper server to\n    know that the client is still active, but it also allows the\n    client to verify that its connection to the ZooKeeper server is\n    still active. The timing of the PING is conservative enough to\n    ensure reasonable time to detect a dead connection and reconnect\n    to a new server.</p>\n<p>\n      Once a connection to the server is successfully established\n      (connected) there are basically two cases where the client lib generates\n      connectionloss (the result code in c binding, exception in Java -- see \n      the API documentation for binding specific details) when either a synchronous or\n      asynchronous operation is performed and one of the following holds:\n    </p>\n<ol>\n      \n<li>\n<p>The application calls an operation on a session that is no\n      longer alive/valid</p>\n</li>\n      \n<li>\n<p>The ZooKeeper client disconnects from a server when there\n      are pending operations to that server, i.e., there is a pending asynchronous call.\n      </p>\n</li>\n    \n</ol>\n<p> \n<strong>Added in 3.2.0 -- SessionMovedException</strong>. There is an internal\n      exception that is generally not seen by clients called the SessionMovedException.\n      This exception occurs because a request was received on a connection for a session\n      which has been reestablished on a different server. The normal cause of this error is\n      a client that sends a request to a server, but the network packet gets delayed, so\n      the client times out and connects to a new server. When the delayed packet arrives at\n      the first server, the old server detects that the session has moved, and closes the\n      client connection. Clients normally do not see this error since they do not read\n      from those old connections. (Old connections are usually closed.) One situation in which this\n      condition can be seen is when two clients try to reestablish the same connection using\n      a saved session id and password. One of the clients will reestablish the connection\n      and the second client will be disconnected (causing the pair to attempt to re-establish\n      its connection/session indefinitely).</p>\n</div>\n\n  \n<a name=\"ch_zkWatches\"></a>\n<h2 class=\"h3\">ZooKeeper Watches</h2>\n<div class=\"section\">\n<p>All of the read operations in ZooKeeper - <strong>getData()</strong>, <strong>getChildren()</strong>, and <strong>exists()</strong> - have the option of setting a watch as a\n    side effect. Here is ZooKeeper's definition of a watch: a watch event is\n    one-time trigger, sent to the client that set the watch, which occurs when\n    the data for which the watch was set changes. There are three key points\n    to consider in this definition of a watch:</p>\n<ul>\n      \n<li>\n        \n<p>\n<strong>One-time trigger</strong>\n</p>\n\n        \n<p>One watch event will be sent to the client when the data has changed.\n        For example, if a client does a getData(\"/znode1\", true) and later the\n        data for /znode1 is changed or deleted, the client will get a watch\n        event for /znode1. If /znode1 changes again, no watch event will be\n        sent unless the client has done another read that sets a new\n        watch.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<strong>Sent to the client</strong>\n</p>\n\n        \n<p>This implies that an event is on the way to the client, but may\n        not reach the client before the successful return code to the change\n        operation reaches the client that initiated the change. Watches are\n        sent asynchronously to watchers. ZooKeeper provides an ordering\n        guarantee: a client will never see a change for which it has set a\n        watch until it first sees the watch event. Network delays or other\n        factors may cause different clients to see watches and return codes\n        from updates at different times. The key point is that everything seen\n        by the different clients will have a consistent order.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>\n<strong>The data for which the watch was\n        set</strong>\n</p>\n\n        \n<p>This refers to the different ways a node can change.  It\n        helps to think of ZooKeeper as maintaining two lists of\n        watches: data watches and child watches.  getData() and\n        exists() set data watches. getChildren() sets child\n        watches. Alternatively, it may help to think of watches being\n        set according to the kind of data returned. getData() and\n        exists() return information about the data of the node,\n        whereas getChildren() returns a list of children.  Thus,\n        setData() will trigger data watches for the znode being set\n        (assuming the set is successful). A successful create() will\n        trigger a data watch for the znode being created and a child\n        watch for the parent znode. A successful delete() will trigger\n        both a data watch and a child watch (since there can be no\n        more children) for a znode being deleted as well as a child\n        watch for the parent znode.</p>\n      \n</li>\n    \n</ul>\n<p>Watches are maintained locally at the ZooKeeper server to which the\n    client is connected. This allows watches to be lightweight to set,\n    maintain, and dispatch. When a client connects to a new server, the watch\n    will be triggered for any session events. Watches will not be received\n    while disconnected from a server. When a client reconnects, any previously\n    registered watches will be reregistered and triggered if needed. In\n    general this all occurs transparently. There is one case where a watch\n    may be missed: a watch for the existence of a znode not yet created will\n    be missed if the znode is created and deleted while disconnected.</p>\n<a name=\"sc_WatchSemantics\"></a>\n<h3 class=\"h4\">Semantics of Watches</h3>\n<p> We can set watches with the three calls that read the state of \n\t  ZooKeeper: exists, getData, and getChildren. The following list details\n\t  the events that a watch can trigger and the calls that enable them:\n\t  </p>\n<ul>\n        \n<li>\n          \n<p>\n<strong>Created event:</strong>\n</p>\n          \n<p>Enabled with a call to exists.</p>\n        \n</li>\n        \n        \n<li>\n          \n<p>\n<strong>Deleted event:</strong>\n</p>\n          \n<p>Enabled with a call to exists, getData, and getChildren.</p>\n        \n</li>\n        \n        \n<li>\n          \n<p>\n<strong>Changed event:</strong>\n</p>\n          \n<p>Enabled with a call to exists and getData.</p>\n        \n</li>\n        \n        \n<li>\n          \n<p>\n<strong>Child event:</strong>\n</p>\n          \n<p>Enabled with a call to getChildren.</p>\n        \n</li>\n      \n</ul>\n<a name=\"sc_WatchGuarantees\"></a>\n<h3 class=\"h4\">What ZooKeeper Guarantees about Watches</h3>\n<p>With regard to watches, ZooKeeper maintains these\n      guarantees:</p>\n<ul>\n        \n<li>\n          \n<p>Watches are ordered with respect to other events, other\n          watches, and asynchronous replies. The ZooKeeper client libraries\n          ensures that everything is dispatched in order.</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>A client will see a watch event for a znode it is watching\n          before seeing the new data that corresponds to that znode.</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>The order of watch events from ZooKeeper corresponds to the\n          order of the updates as seen by the ZooKeeper service.</p>\n        \n</li>\n      \n</ul>\n<a name=\"sc_WatchRememberThese\"></a>\n<h3 class=\"h4\">Things to Remember about Watches</h3>\n<ul>\n        \n<li>\n          \n<p>Watches are one time triggers; if you get a watch event and\n          you want to get notified of future changes, you must set another\n          watch.</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>Because watches are one time triggers and there is latency\n          between getting the event and sending a new request to get a watch\n          you cannot reliably see every change that happens to a node in\n          ZooKeeper. Be prepared to handle the case where the znode changes\n          multiple times between getting the event and setting the watch\n          again. (You may not care, but at least realize it may\n          happen.)</p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>A watch object, or function/context pair, will only be\n          triggered once for a given notification. For example, if the same\n          watch object is registered for an exists and a getData call for the\n          same file and that file is then deleted, the watch object would\n          only be invoked once with the deletion notification for the file.\n          </p>\n        \n</li>\n      \n</ul>\n<ul>\n        \n<li>\n          \n<p>When you disconnect from a server (for example, when the\n          server fails), you will not get any watches until the connection\n          is reestablished. For this reason session events are sent to all\n          outstanding watch handlers. Use session events to go into a safe\n          mode: you will not be receiving events while disconnected, so your\n          process should act conservatively in that mode.</p>\n        \n</li>\n      \n</ul>\n</div>\n\n  \n<a name=\"sc_ZooKeeperAccessControl\"></a>\n<h2 class=\"h3\">ZooKeeper access control using ACLs</h2>\n<div class=\"section\">\n<p>ZooKeeper uses ACLs to control access to its znodes (the\n    data nodes of a ZooKeeper data tree). The ACL implementation is\n    quite similar to UNIX file access permissions: it employs\n    permission bits to allow/disallow various operations against a\n    node and the scope to which the bits apply. Unlike standard UNIX\n    permissions, a ZooKeeper node is not limited by the three standard\n    scopes for user (owner of the file), group, and world\n    (other). ZooKeeper does not have a notion of an owner of a\n    znode. Instead, an ACL specifies sets of ids and permissions that\n    are associated with those ids.</p>\n<p>Note also that an ACL pertains only to a specific znode. In\n    particular it does not apply to children. For example, if\n    <em>/app</em> is only readable by ip:172.16.16.1 and\n    <em>/app/status</em> is world readable, anyone will\n    be able to read <em>/app/status</em>; ACLs are not\n    recursive.</p>\n<p>ZooKeeper supports pluggable authentication schemes. Ids are\n    specified using the form <em>scheme:id</em>,\n    where <em>scheme</em> is a the authentication scheme\n    that the id corresponds to. For\n    example, <em>ip:172.16.16.1</em> is an id for a\n    host with the address <em>172.16.16.1</em>.</p>\n<p>When a client connects to ZooKeeper and authenticates\n    itself, ZooKeeper associates all the ids that correspond to a\n    client with the clients connection. These ids are checked against\n    the ACLs of znodes when a clients tries to access a node. ACLs are\n    made up of pairs of <em>(scheme:expression,\n    perms)</em>. The format of\n    the <em>expression</em> is specific to the scheme. For\n    example, the pair <em>(ip:19.22.0.0/16, READ)</em>\n    gives the <em>READ</em> permission to any clients with\n    an IP address that starts with 19.22.</p>\n<a name=\"sc_ACLPermissions\"></a>\n<h3 class=\"h4\">ACL Permissions</h3>\n<p>ZooKeeper supports the following permissions:</p>\n<ul>\n        \n<li>\n<p>\n<strong>CREATE</strong>: you can create a child node</p>\n</li>\n        \n<li>\n<p>\n<strong>READ</strong>: you can get data from a node and list its children.</p>\n</li>\n        \n<li>\n<p>\n<strong>WRITE</strong>: you can set data for a node</p>\n</li>\n        \n<li>\n<p>\n<strong>DELETE</strong>: you can delete a child node</p>\n</li>\n        \n<li>\n<p>\n<strong>ADMIN</strong>: you can set permissions</p>\n</li>\n      \n</ul>\n<p>The <em>CREATE</em>\n      and <em>DELETE</em> permissions have been broken out\n      of the <em>WRITE</em> permission for finer grained\n      access controls. The cases for <em>CREATE</em>\n      and <em>DELETE</em> are the following:</p>\n<p>You want A to be able to do a set on a ZooKeeper node, but\n      not be able to <em>CREATE</em>\n      or <em>DELETE</em> children.</p>\n<p>\n<em>CREATE</em>\n      without <em>DELETE</em>: clients create requests by\n      creating ZooKeeper nodes in a parent directory. You want all\n      clients to be able to add, but only request processor can\n      delete. (This is kind of like the APPEND permission for\n      files.)</p>\n<p>Also, the <em>ADMIN</em> permission is there\n      since ZooKeeper doesn&rsquo;t have a notion of file owner. In some\n      sense the <em>ADMIN</em> permission designates the\n      entity as the owner. ZooKeeper doesn&rsquo;t support the LOOKUP\n      permission (execute permission bit on directories to allow you\n      to LOOKUP even though you can't list the directory). Everyone\n      implicitly has LOOKUP permission. This allows you to stat a\n      node, but nothing more. (The problem is, if you want to call\n      zoo_exists() on a node that doesn't exist, there is no\n      permission to check.)</p>\n<a name=\"sc_BuiltinACLSchemes\"></a>\n<h4>Builtin ACL Schemes</h4>\n<p>ZooKeeeper has the following built in schemes:</p>\n<ul>\n        \n<li>\n<p>\n<strong>world</strong> has a\n        single id, <em>anyone</em>, that represents\n        anyone.</p>\n</li>\n\n        \n<li>\n<p>\n<strong>auth</strong> doesn't\n        use any id, represents any authenticated\n        user.</p>\n</li>\n\n        \n<li>\n<p>\n<strong>digest</strong> uses\n        a <em>username:password</em> string to generate\n        MD5 hash which is then used as an ACL ID\n        identity. Authentication is done by sending\n        the <em>username:password</em> in clear text. When\n        used in the ACL the expression will be\n        the <em>username:base64</em>\n        encoded <em>SHA1</em>\n        password <em>digest</em>.</p>\n        \n</li>\n\n        \n<li>\n<p>\n<strong>ip</strong> uses the\n        client host IP as an ACL ID identity. The ACL expression is of\n        the form <em>addr/bits</em> where the most\n        significant <em>bits</em>\n        of <em>addr</em> are matched against the most\n        significant <em>bits</em> of the client host\n        IP.</p>\n</li>\n\n      \n</ul>\n<a name=\"ZooKeeper+C+client+API\"></a>\n<h4>ZooKeeper C client API</h4>\n<p>The following constants are provided by the ZooKeeper C\n      library:</p>\n<ul>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_READ; //can read node&rsquo;s value and list its children</p>\n</li>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_WRITE;// can set the node&rsquo;s value</p>\n</li>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_CREATE; //can create children</p>\n</li>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_DELETE;// can delete children</p>\n</li>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_ADMIN; //can execute set_acl()</p>\n</li>\n        \n<li>\n<p>\n<em>const</em> <em>int</em> ZOO_PERM_ALL;// all of the above flags OR&rsquo;d together</p>\n</li>\n      \n</ul>\n<p>The following are the standard ACL IDs:</p>\n<ul>\n        \n<li>\n<p>\n<em>struct</em> Id ZOO_ANYONE_ID_UNSAFE; //(&lsquo;world&rsquo;,&rsquo;anyone&rsquo;)</p>\n</li>\n        \n<li>\n<p>\n<em>struct</em> Id ZOO_AUTH_IDS;// (&lsquo;auth&rsquo;,&rsquo;&rsquo;)</p>\n</li>\n      \n</ul>\n<p>ZOO_AUTH_IDS empty identity string should be interpreted as &ldquo;the identity of the creator&rdquo;.</p>\n<p>ZooKeeper client comes with three standard ACLs:</p>\n<ul>\n        \n<li>\n<p>\n<em>struct</em> ACL_vector ZOO_OPEN_ACL_UNSAFE; //(ZOO_PERM_ALL,ZOO_ANYONE_ID_UNSAFE)</p>\n</li>\n        \n<li>\n<p>\n<em>struct</em> ACL_vector ZOO_READ_ACL_UNSAFE;// (ZOO_PERM_READ, ZOO_ANYONE_ID_UNSAFE)</p>\n</li>\n        \n<li>\n<p>\n<em>struct</em> ACL_vector ZOO_CREATOR_ALL_ACL; //(ZOO_PERM_ALL,ZOO_AUTH_IDS)</p>\n</li>\n      \n</ul>\n<p>The ZOO_OPEN_ACL_UNSAFE is completely open free for all\n      ACL: any application can execute any operation on the node and\n      can create, list and delete its children. The\n      ZOO_READ_ACL_UNSAFE is read-only access for any\n      application. CREATE_ALL_ACL grants all permissions to the\n      creator of the node. The creator must have been authenticated by\n      the server (for example, using &ldquo;<em>digest</em>&rdquo;\n      scheme) before it can create nodes with this ACL.</p>\n<p>The following ZooKeeper operations deal with ACLs:</p>\n<ul>\n<li>\n          \n<p>\n<em>int</em> <em>zoo_add_auth</em>\n            (zhandle_t *zh,<em>const</em> <em>char</em>*\n            scheme,<em>const</em> <em>char</em>*\n            cert, <em>int</em> certLen, void_completion_t\n            completion, <em>const</em> <em>void</em>\n            *data);</p>\n      \n</li>\n</ul>\n<p>The application uses the zoo_add_auth function to\n      authenticate itself to the server. The function can be called\n      multiple times if the application wants to authenticate using\n      different schemes and/or identities.</p>\n<ul>\n<li>\n          \n<p>\n<em>int</em> <em>zoo_create</em>\n            (zhandle_t *zh, <em>const</em> <em>char</em>\n            *path, <em>const</em> <em>char</em>\n            *value,<em>int</em>\n            valuelen, <em>const</em> <em>struct</em>\n            ACL_vector *acl, <em>int</em>\n            flags,<em>char</em>\n            *realpath, <em>int</em>\n            max_realpath_len);</p>\n      \n</li>\n</ul>\n<p>zoo_create(...) operation creates a new node. The acl\n      parameter is a list of ACLs associated with the node. The parent\n      node must have the CREATE permission bit set.</p>\n<ul>\n<li>\n          \n<p>\n<em>int</em> <em>zoo_get_acl</em>\n            (zhandle_t *zh, <em>const</em> <em>char</em>\n            *path,<em>struct</em> ACL_vector\n            *acl, <em>struct</em> Stat *stat);</p>\n      \n</li>\n</ul>\n<p>This operation returns a node&rsquo;s ACL info.</p>\n<ul>\n<li>\n          \n<p>\n<em>int</em> <em>zoo_set_acl</em>\n            (zhandle_t *zh, <em>const</em> <em>char</em>\n            *path, <em>int</em>\n            version,<em>const</em> <em>struct</em>\n            ACL_vector *acl);</p>\n      \n</li>\n</ul>\n<p>This function replaces node&rsquo;s ACL list with a new one. The\n      node must have the ADMIN permission set.</p>\n<p>Here is a sample code that makes use of the above APIs to\n      authenticate itself using the &ldquo;<em>foo</em>&rdquo; scheme\n      and create an ephemeral node &ldquo;/xyz&rdquo; with create-only\n      permissions.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n<p>This is a very simple example which is intended to show\n        how to interact with ZooKeeper ACLs\n        specifically. See <span class=\"codefrag filename\">.../trunk/src/c/src/cli.c</span>\n        for an example of a C client implementation</p>\n      \n</div>\n</div>\n<pre class=\"code\">\n#include &lt;string.h&gt;\n#include &lt;errno.h&gt;\n\n#include \"zookeeper.h\"\n\nstatic zhandle_t *zh;\n\n/**\n * In this example this method gets the cert for your\n *   environment -- you must provide\n */\nchar *foo_get_cert_once(char* id) { return 0; }\n\n/** Watcher function -- empty for this example, not something you should\n * do in real code */\nvoid watcher(zhandle_t *zzh, int type, int state, const char *path,\n             void *watcherCtx) {}\n\nint main(int argc, char argv) {\n  char buffer[512];\n  char p[2048];\n  char *cert=0;\n  char appId[64];\n\n  strcpy(appId, \"example.foo_test\");\n  cert = foo_get_cert_once(appId);\n  if(cert!=0) {\n    fprintf(stderr,\n            \"Certificate for appid [%s] is [%s]\\n\",appId,cert);\n    strncpy(p,cert, sizeof(p)-1);\n    free(cert);\n  } else {\n    fprintf(stderr, \"Certificate for appid [%s] not found\\n\",appId);\n    strcpy(p, \"dummy\");\n  }\n\n  zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);\n\n  zh = zookeeper_init(\"localhost:3181\", watcher, 10000, 0, 0, 0);\n  if (!zh) {\n    return errno;\n  }\n  if(zoo_add_auth(zh,\"foo\",p,strlen(p),0,0)!=ZOK)\n    return 2;\n\n  struct ACL CREATE_ONLY_ACL[] = {{ZOO_PERM_CREATE, ZOO_AUTH_IDS}};\n  struct ACL_vector CREATE_ONLY = {1, CREATE_ONLY_ACL};\n  int rc = zoo_create(zh,\"/xyz\",\"value\", 5, &amp;CREATE_ONLY, ZOO_EPHEMERAL,\n                      buffer, sizeof(buffer)-1);\n\n  /** this operation will fail with a ZNOAUTH error */\n  int buflen= sizeof(buffer);\n  struct Stat stat;\n  rc = zoo_get(zh, \"/xyz\", 0, buffer, &amp;buflen, &amp;stat);\n  if (rc) {\n    fprintf(stderr, \"Error %d for %s\\n\", rc, __LINE__);\n  }\n\n  zookeeper_close(zh);\n  return 0;\n}\n      </pre>\n</div>\n\n  \n<a name=\"sc_ZooKeeperPluggableAuthentication\"></a>\n<h2 class=\"h3\">Pluggable ZooKeeper authentication</h2>\n<div class=\"section\">\n<p>ZooKeeper runs in a variety of different environments with\n    various different authentication schemes, so it has a completely\n    pluggable authentication framework. Even the builtin authentication\n    schemes use the pluggable authentication framework.</p>\n<p>To understand how the authentication framework works, first you must\n    understand the two main authentication operations. The framework \n    first must authenticate the client. This is usually done as soon as\n    the client connects to a server and consists of validating information\n    sent from or gathered about a client and associating it with the connection.\n    The second operation handled by the framework is finding the entries in an\n    ACL that correspond to client. ACL entries are &lt;<em>idspec, \n    permissions</em>&gt; pairs. The <em>idspec</em> may be\n    a simple string match against the authentication information associated\n    with the connection or it may be a expression that is evaluated against that\n    information. It is up to the implementation of the authentication plugin\n    to do the match. Here is the interface that an authentication plugin must\n    implement:</p>\n<pre class=\"code\">\npublic interface AuthenticationProvider {\n    String getScheme();\n    KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte authData[]);\n    boolean isValid(String id);\n    boolean matches(String id, String aclExpr);\n    boolean isAuthenticated();\n}\n    </pre>\n<p>The first method <em>getScheme</em> returns the string\n    that identifies the plugin. Because we support multiple methods of authentication,\n    an authentication credential or an <em>idspec</em> will always be\n    prefixed with <em>scheme:</em>. The ZooKeeper server uses the scheme\n    returned by the authentication plugin to determine which ids the scheme\n    applies to.</p>\n<p>\n<em>handleAuthentication</em> is called when a client\n    sends authentication information to be associated with a connection. The\n    client specifies the scheme to which the information corresponds. The\n    ZooKeeper server passes the information to the authentication plugin whose\n    <em>getScheme</em> matches the scheme passed by the client. The\n    implementor of <em>handleAuthentication</em> will usually return\n    an error if it determines that the information is bad, or it will associate information\n    with the connection using <em>cnxn.getAuthInfo().add(new Id(getScheme(), data))</em>.\n    </p>\n<p>The authentication plugin is involved in both setting and using ACLs. When an\n    ACL is set for a znode, the ZooKeeper server will pass the id part of the entry to\n    the <em>isValid(String id)</em> method. It is up to the plugin to verify\n    that the id has a correct form. For example, <em>ip:172.16.0.0/16</em>\n    is a valid id, but <em>ip:host.com</em> is not. If the new ACL includes\n    an \"auth\" entry, <em>isAuthenticated</em> is used to see if the \n    authentication information for this scheme that is assocatied with the connection\n    should be added to the ACL. Some schemes\n    should not be included in auth. For example, the IP address of the client is not\n    considered as an id that should be added to the ACL if auth is specified.</p>\n<p>ZooKeeper invokes\n    <em>matches(String id, String aclExpr)</em> when checking an ACL. It\n    needs to match authentication information of the client against the relevant ACL\n    entries. To find the entries which apply to the client, the ZooKeeper server will\n    find the scheme of each entry and if there is authentication information\n    from that client for that scheme, <em>matches(String id, String aclExpr)</em>\n    will be called with <em>id</em> set to the authentication information\n    that was previously added to the connection by <em>handleAuthentication</em> and\n    <em>aclExpr</em> set to the id of the ACL entry. The authentication plugin\n    uses its own logic and matching scheme to determine if <em>id</em> is included\n    in <em>aclExpr</em>. \n    </p>\n<p>There are two built in authentication plugins: <em>ip</em> and\n    <em>digest</em>. Additional plugins can adding using system properties. At\n    startup the ZooKeeper server will look for system properties that start with\n    \"zookeeper.authProvider.\" and interpret the value of those properties as the class name\n    of an authentication plugin. These properties can be set using the\n    <em>-Dzookeeeper.authProvider.X=com.f.MyAuth</em> or adding entries such as\n    the following in the server configuration file:</p>\n<pre class=\"code\">\nauthProvider.1=com.f.MyAuth\nauthProvider.2=com.f.MyAuth2\n    </pre>\n<p>Care should be taking to ensure that the suffix on the property is unique. If there are \n    duplicates such as <em>-Dzookeeeper.authProvider.X=com.f.MyAuth -Dzookeeper.authProvider.X=com.f.MyAuth2</em>,\n    only one will be used. Also all servers must have the same plugins defined, otherwise clients using\n    the authentication schemes provided by the plugins will have problems connecting to some servers.\n    </p>\n</div>\n      \n  \n<a name=\"ch_zkGuarantees\"></a>\n<h2 class=\"h3\">Consistency Guarantees</h2>\n<div class=\"section\">\n<p>ZooKeeper is a high performance, scalable service. Both reads and\n    write operations are designed to be fast, though reads are faster than\n    writes. The reason for this is that in the case of reads, ZooKeeper can\n    serve older data, which in turn is due to ZooKeeper's consistency\n    guarantees:</p>\n<dl>\n      \n<dt>\n<term>Sequential Consistency</term>\n</dt>\n<dd>\n<p>Updates from a client will be applied in the order that they\n          were sent.</p>\n</dd>\n\n      \n<dt>\n<term>Atomicity</term>\n</dt>\n<dd>\n<p>Updates either succeed or fail -- there are no partial\n          results.</p>\n</dd>\n\n      \n<dt>\n<term>Single System Image</term>\n</dt>\n<dd>\n<p>A client will see the same view of the service regardless of\n          the server that it connects to.</p>\n</dd>\n\n      \n<dt>\n<term>Reliability</term>\n</dt>\n<dd>\n<p>Once an update has been applied, it will persist from that\n          time forward until a client overwrites the update. This guarantee\n          has two corollaries:</p>\n<ol>\n            \n<li>\n              \n<p>If a client gets a successful return code, the update will\n              have been applied. On some failures (communication errors,\n              timeouts, etc) the client will not know if the update has\n              applied or not. We take steps to minimize the failures, but the\n              guarantee is only present with successful return codes.\n              (This is called the <em>monotonicity condition</em> in Paxos.)</p>\n            \n</li>\n\n            \n<li>\n              \n<p>Any updates that are seen by the client, through a read\n              request or successful update, will never be rolled back when\n              recovering from server failures.</p>\n            \n</li>\n          \n</ol>\n</dd>\n\n      \n<dt>\n<term>Timeliness</term>\n</dt>\n<dd>\n<p>The clients view of the system is guaranteed to be up-to-date\n          within a certain time bound (on the order of tens of seconds).\n          Either system changes will be seen by a client within this bound, or\n          the client will detect a service outage.</p>\n</dd>\n    \n</dl>\n<p>Using these consistency guarantees it is easy to build higher level\n    functions such as leader election, barriers, queues, and read/write\n    revocable locks solely at the ZooKeeper client (no additions needed to\n    ZooKeeper). See <a href=\"recipes.html\">Recipes and Solutions</a>\n    for more details.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n        \n<p>Sometimes developers mistakenly assume one other guarantee that\n        ZooKeeper does <em>not</em> in fact make. This is:</p>\n\n        \n<dl>\n          \n<dt>\n<term>Simultaneously Consistent Cross-Client Views</term>\n</dt>\n<dd>\n<p>ZooKeeper does not guarantee that at every instance in\n              time, two different clients will have identical views of\n              ZooKeeper data. Due to factors like network delays, one client\n              may perform an update before another client gets notified of the\n              change. Consider the scenario of two clients, A and B. If client\n              A sets the value of a znode /a from 0 to 1, then tells client B\n              to read /a, client B may read the old value of 0, depending on\n              which server it is connected to. If it\n              is important that Client A and Client B read the same value,\n              Client B should should call the <strong>sync()</strong> method from the ZooKeeper API\n              method before it performs its read.</p>\n<p>So, ZooKeeper by itself doesn't guarantee that changes occur \n              synchronously across all servers, but ZooKeeper\n              primitives can be used to construct higher level functions that\n              provide useful client synchronization. (For more information,\n              see the <a href=\"recipes.html\">ZooKeeper Recipes</a>.\n              <em>[tbd:..]</em>).</p>\n</dd>\n        \n</dl>\n      \n</div>\n</div>\n</div>\n\n  \n<a name=\"ch_bindings\"></a>\n<h2 class=\"h3\">Bindings</h2>\n<div class=\"section\">\n<p>The ZooKeeper client libraries come in two languages: Java and C.\n    The following sections describe these.</p>\n<a name=\"Java+Binding\"></a>\n<h3 class=\"h4\">Java Binding</h3>\n<p>There are two packages that make up the ZooKeeper Java binding:\n      <strong>org.apache.zookeeper</strong> and <strong>org.apache.zookeeper.data</strong>. The rest of the\n      packages that make up ZooKeeper are used internally or are part of the\n      server implementation. The <strong>org.apache.zookeeper.data</strong> package is made up of\n      generated classes that are used simply as containers.</p>\n<p>The main class used by a ZooKeeper Java client is the <strong>ZooKeeper</strong> class. Its two constructors differ only\n      by an optional session id and password. ZooKeeper supports session\n      recovery accross instances of a process. A Java program may save its\n      session id and password to stable storage, restart, and recover the\n      session that was used by the earlier instance of the program.</p>\n<p>When a ZooKeeper object is created, two threads are created as\n      well: an IO thread and an event thread. All IO happens on the IO thread\n      (using Java NIO). All event callbacks happen on the event thread.\n      Session maintenance such as reconnecting to ZooKeeper servers and\n      maintaining heartbeat is done on the IO thread. Responses for\n      synchronous methods are also processed in the IO thread. All responses\n      to asynchronous methods and watch events are processed on the event\n      thread. There are a few things to notice that result from this\n      design:</p>\n<ul>\n        \n<li>\n          \n<p>All completions for asynchronous calls and watcher callbacks\n          will be made in order, one at a time. The caller can do any\n          processing they wish, but no other callbacks will be processed\n          during that time.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Callbacks do not block the processing of the IO thread or the\n          processing of the synchronous calls.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>Synchronous calls may not return in the correct order. For\n          example, assume a client does the following processing: issues an\n          asynchronous read of node <strong>/a</strong> with\n          <em>watch</em> set to true, and then in the completion\n          callback of the read it does a synchronous read of <strong>/a</strong>. (Maybe not good practice, but not illegal\n          either, and it makes for a simple example.)</p>\n\n          \n<p>Note that if there is a change to <strong>/a</strong> between the asynchronous read and the\n          synchronous read, the client library will receive the watch event\n          saying <strong>/a</strong> changed before the\n          response for the synchronous read, but because the completion\n          callback is blocking the event queue, the synchronous read will\n          return with the new value of <strong>/a</strong>\n          before the watch event is processed.</p>\n        \n</li>\n      \n</ul>\n<p>Finally, the rules associated with shutdown are straightforward:\n      once a ZooKeeper object is closed or receives a fatal event\n      (SESSION_EXPIRED and AUTH_FAILED), the ZooKeeper object becomes invalid.\n      On a close, the two threads shut down and any further access on zookeeper\n      handle is undefined behavior and should be avoided. </p>\n<a name=\"C+Binding\"></a>\n<h3 class=\"h4\">C Binding</h3>\n<p>The C binding has a single-threaded and multi-threaded library.\n      The multi-threaded library is easiest to use and is most similar to the\n      Java API. This library will create an IO thread and an event dispatch\n      thread for handling connection maintenance and callbacks. The\n      single-threaded library allows ZooKeeper to be used in event driven\n      applications by exposing the event loop used in the multi-threaded\n      library.</p>\n<p>The package includes two shared libraries: zookeeper_st and\n      zookeeper_mt. The former only provides the asynchronous APIs and\n      callbacks for integrating into the application's event loop. The only\n      reason this library exists is to support the platforms were a\n      <em>pthread</em> library is not available or is unstable\n      (i.e. FreeBSD 4.x). In all other cases, application developers should\n      link with zookeeper_mt, as it includes support for both Sync and Async\n      API.</p>\n<a name=\"Installation\"></a>\n<h4>Installation</h4>\n<p>If you're building the client from a check-out from the Apache\n        repository, follow the steps outlined below. If you're building from a\n        project source package downloaded from apache, skip to step <strong>3</strong>.</p>\n<ol>\n          \n<li>\n            \n<p>Run <span class=\"codefrag command\">ant compile_jute</span> from the ZooKeeper\n            top level directory (<span class=\"codefrag filename\">.../trunk</span>).\n            This will create a directory named \"generated\" under\n            <span class=\"codefrag filename\">.../trunk/src/c</span>.</p>\n          \n</li>\n\n          \n<li>\n            \n<p>Change directory to the<span class=\"codefrag filename\">.../trunk/src/c</span>\n            and run <span class=\"codefrag command\">autoreconf -if</span> to bootstrap <strong>autoconf</strong>, <strong>automake</strong> and <strong>libtool</strong>. Make sure you have <strong>autoconf version 2.59</strong> or greater installed.\n            Skip to step<strong> 4</strong>.</p>\n          \n</li>\n\n          \n<li>\n            \n<p>If you are building from a project source package,\n            unzip/untar the source tarball and cd to the<span class=\"codefrag filename\">\n            zookeeper-x.x.x/src/c</span> directory.</p>\n          \n</li>\n\n          \n<li>\n            \n<p>Run <span class=\"codefrag command\">./configure &lt;your-options&gt;</span> to\n            generate the makefile. Here are some of options the <strong>configure</strong> utility supports that can be\n            useful in this step:</p>\n\n            \n<ul>\n              \n<li>\n                \n<p>\n<span class=\"codefrag command\">--enable-debug</span>\n</p>\n\n                \n<p>Enables optimization and enables debug info compiler\n                options. (Disabled by default.)</p>\n              \n</li>\n\n              \n<li>\n                \n<p>\n<span class=\"codefrag command\">--without-syncapi </span>\n</p>\n\n                \n<p>Disables Sync API support; zookeeper_mt library won't be\n                built. (Enabled by default.)</p>\n              \n</li>\n\n              \n<li>\n                \n<p>\n<span class=\"codefrag command\">--disable-static </span>\n</p>\n\n                \n<p>Do not build static libraries. (Enabled by\n                default.)</p>\n              \n</li>\n\n              \n<li>\n                \n<p>\n<span class=\"codefrag command\">--disable-shared</span>\n</p>\n\n                \n<p>Do not build shared libraries. (Enabled by\n                default.)</p>\n              \n</li>\n            \n</ul>\n\n            \n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n              \n<p>See INSTALL for general information about running\n              <strong>configure</strong>.</p>\n            \n</div>\n</div>\n          \n</li>\n\n          \n<li>\n            \n<p>Run <span class=\"codefrag command\">make</span> or <span class=\"codefrag command\">make\n            install</span> to build the libraries and install them.</p>\n          \n</li>\n\n          \n<li>\n            \n<p>To generate doxygen documentation for the ZooKeeper API, run\n            <span class=\"codefrag command\">make doxygen-doc</span>. All documentation will be\n            placed in a new subfolder named docs. By default, this command\n            only generates HTML. For information on other document formats,\n            run <span class=\"codefrag command\">./configure --help</span>\n</p>\n          \n</li>\n        \n</ol>\n<a name=\"Building+Your+Own+C+Client\"></a>\n<h4>Building Your Own C Client</h4>\n<p>In order to be able to use the ZooKeeper API in your application\n        you have to remember to</p>\n<ol>\n          \n<li>\n            \n<p>Include ZooKeeper header: #include\n              &lt;zookeeper/zookeeper.h&gt;</p>\n          \n</li>\n\n          \n<li>\n            \n<p>If you are building a multithreaded client, compile with\n            -DTHREADED compiler flag to enable the multi-threaded version of\n            the library, and then link against against the\n            <em>zookeeper_mt</em> library. If you are building a\n            single-threaded client, do not compile with -DTHREADED, and be\n            sure to link against the<em> zookeeper_st\n            </em>library.</p>\n          \n</li>\n        \n</ol>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n<p>\n          See <span class=\"codefrag filename\">.../trunk/src/c/src/cli.c</span>\n            for an example of a C client implementation</p>\n        \n</div>\n</div>\n</div>\n\n   \n<a name=\"ch_guideToZkOperations\"></a>\n<h2 class=\"h3\">Building Blocks: A Guide to ZooKeeper Operations</h2>\n<div class=\"section\">\n<p>This section surveys all the operations a developer can perform\n    against a ZooKeeper server. It is lower level information than the earlier\n    concepts chapters in this manual, but higher level than the ZooKeeper API\n    Reference. It covers these topics:</p>\n<ul>\n      \n<li>\n        \n<p>\n<a href=\"#sc_connectingToZk\">Connecting to ZooKeeper</a>\n</p>\n      \n</li>\n    \n</ul>\n<a name=\"sc_errorsZk\"></a>\n<h3 class=\"h4\">Handling Errors</h3>\n<p>Both the Java and C client bindings may report errors. The Java client binding does so by throwing KeeperException, calling code() on the exception will return the specific error code. The C client binding returns an error code as defined in the enum ZOO_ERRORS. API callbacks indicate result code for both language bindings. See the API documentation (javadoc for Java, doxygen for C) for full details on the possible errors and their meaning.</p>\n<a name=\"sc_connectingToZk\"></a>\n<h3 class=\"h4\">Connecting to ZooKeeper</h3>\n<p></p>\n<a name=\"sc_readOps\"></a>\n<h3 class=\"h4\">Read Operations</h3>\n<p></p>\n<a name=\"sc_writeOps\"></a>\n<h3 class=\"h4\">Write Operations</h3>\n<p></p>\n<a name=\"sc_handlingWatches\"></a>\n<h3 class=\"h4\">Handling Watches</h3>\n<p></p>\n<a name=\"sc_miscOps\"></a>\n<h3 class=\"h4\">Miscelleaneous ZooKeeper Operations</h3>\n<p></p>\n</div>\n\n  \n<a name=\"ch_programStructureWithExample\"></a>\n<h2 class=\"h3\">Program Structure, with Simple Example</h2>\n<div class=\"section\">\n<p>\n<em>[tbd]</em>\n</p>\n</div>\n\n  \n<a name=\"ch_gotchas\"></a>\n<h2 class=\"h3\">Gotchas: Common Problems and Troubleshooting</h2>\n<div class=\"section\">\n<p>So now you know ZooKeeper. It's fast, simple, your application\n    works, but wait ... something's wrong. Here are some pitfalls that\n    ZooKeeper users fall into:</p>\n<ol>\n      \n<li>\n        \n<p>If you are using watches, you must look for the connected watch\n        event. When a ZooKeeper client disconnects from a server, you will\n        not receive notification of changes until reconnected. If you are\n        watching for a znode to come into existence, you will miss the event\n        if the znode is created and deleted while you are disconnected.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>You must test ZooKeeper server failures. The ZooKeeper service\n        can survive failures as long as a majority of servers are active. The\n        question to ask is: can your application handle it? In the real world\n        a client's connection to ZooKeeper can break. (ZooKeeper server\n        failures and network partitions are common reasons for connection\n        loss.) The ZooKeeper client library takes care of recovering your\n        connection and letting you know what happened, but you must make sure\n        that you recover your state and any outstanding requests that failed.\n        Find out if you got it right in the test lab, not in production - test\n        with a ZooKeeper service made up of a several of servers and subject\n        them to reboots.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>The list of ZooKeeper servers used by the client must match the\n        list of ZooKeeper servers that each ZooKeeper server has. Things can\n        work, although not optimally, if the client list is a subset of the\n        real list of ZooKeeper servers, but not if the client lists ZooKeeper\n        servers not in the ZooKeeper cluster.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Be careful where you put that transaction log. The most\n        performance-critical part of ZooKeeper is the transaction log.\n        ZooKeeper must sync transactions to media before it returns a\n        response. A dedicated transaction log device is key to consistent good\n        performance. Putting the log on a busy device will adversely effect\n        performance. If you only have one storage device, put trace files on\n        NFS and increase the snapshotCount; it doesn't eliminate the problem,\n        but it can mitigate it.</p>\n      \n</li>\n\n      \n<li>\n        \n<p>Set your Java max heap size correctly. It is very important to\n        <em>avoid swapping.</em> Going to disk unnecessarily will\n        almost certainly degrade your performance unacceptably. Remember, in\n        ZooKeeper, everything is ordered, so if one request hits the disk, all\n        other queued requests hit the disk.</p>\n\n        \n<p>To avoid swapping, try to set the heapsize to the amount of\n        physical memory you have, minus the amount needed by the OS and cache.\n        The best way to determine an optimal heap size for your configurations\n        is to <em>run load tests</em>. If for some reason you\n        can't, be conservative in your estimates and choose a number well\n        below the limit that would cause your machine to swap. For example, on\n        a 4G machine, a 3G heap is a conservative estimate to start\n        with.</p>\n      \n</li>\n    \n</ol>\n</div>\n\n  \n<a name=\"apx_linksToOtherInfo\"></a>\n<appendix id=\"apx_linksToOtherInfo\">\n    \n<title>Links to Other Information</title>\n\n    \n<p>Outside the formal documentation, there're several other sources of\n    information for ZooKeeper developers.</p>\n\n    \n<dl>\n      \n<dt>\n<term>ZooKeeper Whitepaper <em>[tbd: find url]</em>\n</term>\n</dt>\n<dd>\n<p>The definitive discussion of ZooKeeper design and performance,\n          by Yahoo! Research</p>\n</dd>\n\n      \n<dt>\n<term>API Reference <em>[tbd: find url]</em>\n</term>\n</dt>\n<dd>\n<p>The complete reference to the ZooKeeper API</p>\n</dd>\n\n      \n<dt>\n<term>\n<a href=\"http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/zookeeper.m4v\">ZooKeeper\n        Talk at the Hadoup Summit 2008</a>\n</term>\n</dt>\n<dd>\n<p>A video introduction to ZooKeeper, by Benjamin Reed of Yahoo!\n          Research</p>\n</dd>\n\n      \n<dt>\n<term>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/Tutorial\">Barrier and\n        Queue Tutorial</a>\n</term>\n</dt>\n<dd>\n<p>The excellent Java tutorial by Flavio Junqueira, implementing\n          simple barriers and producer-consumer queues using ZooKeeper.</p>\n</dd>\n\n      \n<dt>\n<term>\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/ZooKeeperArticles\">ZooKeeper\n        - A Reliable, Scalable Distributed Coordination System</a>\n</term>\n</dt>\n<dd>\n<p>An article by Todd Hoff (07/15/2008)</p>\n</dd>\n\n      \n<dt>\n<term>\n<a href=\"recipes.html\">ZooKeeper Recipes</a>\n</term>\n</dt>\n<dd>\n<p>Pseudo-level discussion of the implementation of various\n          synchronization solutions with ZooKeeper: Event Handles, Queues,\n          Locks, and Two-phase Commits.</p>\n</dd>\n\n      \n<dt>\n<term>\n<em>[tbd]</em>\n</term>\n</dt>\n<dd>\n<p>Any other good sources anyone can think of...</p>\n</dd>\n    \n</dl>\n  \n</appendix>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperQuotas.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Quota's Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.4', 'skin/')\" id=\"menu_selected_1.4Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Admin &amp; Ops</div>\n<div id=\"menu_selected_1.4\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Quota Guide</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperQuotas.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Quota's Guide</h1>\n<h3>A Guide to Deployment and Administration</h3>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#zookeeper_quotas\">Quotas</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Setting+Quotas\">Setting Quotas</a>\n</li>\n<li>\n<a href=\"#Listing+Quotas\">Listing Quotas</a>\n</li>\n<li>\n<a href=\"#Deleting+Quotas\"> Deleting Quotas</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n\t\n\t\n\t\n\t\n<a name=\"zookeeper_quotas\"></a>\n<h2 class=\"h3\">Quotas</h2>\n<div class=\"section\">\n<p> ZooKeeper has both namespace and bytes quotas. You can use the ZooKeeperMain class to setup quotas.\n\tZooKeeper prints <em>WARN</em> messages if users exceed the quota assigned to them. The messages \n\tare printed in the log of the ZooKeeper. \n\t</p>\n<p>\n<span class=\"codefrag computeroutput\">$ bin/zkCli.sh -server host:port</span>\n</p>\n<p> The above command gives you a command line option of using quotas.</p>\n<a name=\"Setting+Quotas\"></a>\n<h3 class=\"h4\">Setting Quotas</h3>\n<p>You can use \n\t <em>setquota</em> to set a quota on a ZooKeeper node. It has an option of setting quota with\n\t  -n (for namespace)\n\t and -b (for bytes). </p>\n<p> The ZooKeeper quota are stored in ZooKeeper itself in /zookeeper/quota. To disable other people from\n\tchanging the quota's set the ACL for /zookeeper/quota such that only admins are able to read and write to it.\n\t</p>\n<a name=\"Listing+Quotas\"></a>\n<h3 class=\"h4\">Listing Quotas</h3>\n<p> You can use\n\t<em>listquota</em> to list a quota on a ZooKeeper node.\n\t</p>\n<a name=\"Deleting+Quotas\"></a>\n<h3 class=\"h4\"> Deleting Quotas</h3>\n<p> You can use\n\t<em>delquota</em> to delete quota on a ZooKeeper node.\n\t</p>\n</div>\n\t\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperStarted.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>ZooKeeper Getting Started Guide</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_selected_1.1', 'skin/')\" id=\"menu_selected_1.1Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Overview</div>\n<div id=\"menu_selected_1.1\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Getting Started</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.2', 'skin/')\" id=\"menu_1.2Title\" class=\"menutitle\">Developer</div>\n<div id=\"menu_1.2\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperStarted.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>ZooKeeper Getting Started Guide</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_GettingStarted\">Getting Started: Coordinating Distributed Applications with\n      ZooKeeper</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#sc_Prerequisites\">Pre-requisites</a>\n</li>\n<li>\n<a href=\"#sc_Download\">Download</a>\n</li>\n<li>\n<a href=\"#sc_InstallingSingleMode\">Standalone Operation</a>\n</li>\n<li>\n<a href=\"#sc_FileManagement\">Managing ZooKeeper Storage</a>\n</li>\n<li>\n<a href=\"#sc_ConnectingToZooKeeper\">Connecting to ZooKeeper</a>\n</li>\n<li>\n<a href=\"#sc_ProgrammingToZooKeeper\">Programming to ZooKeeper</a>\n</li>\n<li>\n<a href=\"#sc_RunningReplicatedZooKeeper\">Running Replicated ZooKeeper</a>\n</li>\n<li>\n<a href=\"#Other+Optimizations\">Other Optimizations</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_GettingStarted\"></a>\n<h2 class=\"h3\">Getting Started: Coordinating Distributed Applications with\n      ZooKeeper</h2>\n<div class=\"section\">\n<p>This document contains information to get you started quickly with\n    ZooKeeper. It is aimed primarily at developers hoping to try it out, and\n    contains simple installation instructions for a single ZooKeeper server, a\n    few commands to verify that it is running, and a simple programming\n    example. Finally, as a convenience, there are a few sections regarding\n    more complicated installations, for example running replicated\n    deployments, and optimizing the transaction log. However for the complete\n    instructions for commercial deployments, please refer to the <a href=\"zookeeperAdmin.html\">ZooKeeper\n    Administrator's Guide</a>.</p>\n<a name=\"sc_Prerequisites\"></a>\n<h3 class=\"h4\">Pre-requisites</h3>\n<p>See <a href=\"zookeeperAdmin.html#sc_systemReq\">\n          System Requirements</a> in the Admin guide.</p>\n<a name=\"sc_Download\"></a>\n<h3 class=\"h4\">Download</h3>\n<p>To get a ZooKeeper distribution, download a recent\n        <a href=\"http://zookeeper.apache.org/releases.html\">\n          stable</a> release from one of the Apache Download\n        Mirrors.</p>\n<a name=\"sc_InstallingSingleMode\"></a>\n<h3 class=\"h4\">Standalone Operation</h3>\n<p>Setting up a ZooKeeper server in standalone mode is\n      straightforward. The server is contained in a single JAR file,\n      so installation consists of creating a configuration.</p>\n<p>Once you've downloaded a stable ZooKeeper release unpack\n      it and cd to the root</p>\n<p>To start ZooKeeper you need a configuration file. Here is a sample,\n      create it in <strong>conf/zoo.cfg</strong>:</p>\n<pre class=\"code\">\ntickTime=2000\ndataDir=/var/lib/zookeeper\nclientPort=2181\n</pre>\n<p>This file can be called anything, but for the sake of this\n      discussion call\n      it <strong>conf/zoo.cfg</strong>. Change the\n      value of <strong>dataDir</strong> to specify an\n      existing (empty to start with) directory.  Here are the meanings\n      for each of the fields:</p>\n<dl>\n        \n<dt>\n<term>\n<strong>tickTime</strong>\n</term>\n</dt>\n<dd>\n<p>the basic time unit in milliseconds used by ZooKeeper. It is\n            used to do heartbeats and the minimum session timeout will be\n            twice the tickTime.</p>\n</dd>\n      \n</dl>\n<dl>\n        \n<dt>\n<term>\n<strong>dataDir</strong>\n</term>\n</dt>\n<dd>\n<p>the location to store the in-memory database snapshots and,\n            unless specified otherwise, the transaction log of updates to the\n            database.</p>\n</dd>\n\n        \n<dt>\n<term>\n<strong>clientPort</strong>\n</term>\n</dt>\n<dd>\n<p>the port to listen for client connections</p>\n</dd>\n      \n</dl>\n<p>Now that you created the configuration file, you can start\n      ZooKeeper:</p>\n<pre class=\"code\">bin/zkServer.sh start</pre>\n<p>ZooKeeper logs messages using log4j -- more detail\n      available in the\n      <a href=\"zookeeperProgrammers.html#Logging\">Logging</a>\n      section of the Programmer's Guide. You will see log messages\n      coming to the console (default) and/or a log file depending on\n      the log4j configuration.</p>\n<p>The steps outlined here run ZooKeeper in standalone mode. There is\n      no replication, so if ZooKeeper process fails, the service will go down.\n      This is fine for most development situations, but to run ZooKeeper in\n      replicated mode, please see <a href=\"#sc_RunningReplicatedZooKeeper\">Running Replicated\n      ZooKeeper</a>.</p>\n<a name=\"sc_FileManagement\"></a>\n<h3 class=\"h4\">Managing ZooKeeper Storage</h3>\n<p>For long running production systems ZooKeeper storage must\n      be managed externally (dataDir and logs). See the section on\n      <a href=\"zookeeperAdmin.html#sc_maintenance\">maintenance</a> for\n      more details.</p>\n<a name=\"sc_ConnectingToZooKeeper\"></a>\n<h3 class=\"h4\">Connecting to ZooKeeper</h3>\n<pre class=\"code\">$ bin/zkCli.sh -server 127.0.0.1:2181</pre>\n<p>This lets you perform simple, file-like operations.</p>\n<p>Once you have connected, you should see something like:\n        </p>\n<pre class=\"code\">\n\nConnecting to localhost:2181\nlog4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).\nlog4j:WARN Please initialize the log4j system properly.\nWelcome to ZooKeeper!\nJLine support is enabled\n[zkshell: 0]\n        </pre>\n<p>\n        From the shell, type <span class=\"codefrag command\">help</span> to get a listing of commands that can be executed from the client, as in:\n      </p>\n<pre class=\"code\">\n\n[zkshell: 0] help\nZooKeeper host:port cmd args\n        get path [watch]\n        ls path [watch]\n        set path data [version]\n        delquota [-n|-b] path\n        quit\n        printwatches on|off\n        createpath data acl\n        stat path [watch]\n        listquota path\n        history\n        setAcl path acl\n        getAcl path\n        sync path\n        redo cmdno\n        addauth scheme auth\n        delete path [version]\n        setquota -n|-b val path\n\n        </pre>\n<p>From here, you can try a few simple commands to get a feel for this simple command line interface.  First, start by issuing the list command, as\n      in <span class=\"codefrag command\">ls</span>, yielding:\n      </p>\n<pre class=\"code\">\n\n[zkshell: 8] ls /\n[zookeeper]\n        </pre>\n<p>Next, create a new znode by running <span class=\"codefrag command\">create /zk_test my_data</span>. This creates a new znode and associates the string \"my_data\" with the node.\n      You should see:</p>\n<pre class=\"code\">\n\n[zkshell: 9] create /zk_test my_data\nCreated /zk_test\n      </pre>\n<p>  Issue another <span class=\"codefrag command\">ls /</span> command to see what the directory looks like:\n        </p>\n<pre class=\"code\">\n\n[zkshell: 11] ls /\n[zookeeper, zk_test]\n\n        </pre>\n<p>\n      Notice that the zk_test directory has now been created.\n      </p>\n<p>Next, verify that the data was associated with the znode by running the <span class=\"codefrag command\">get</span> command, as in:\n      </p>\n<pre class=\"code\">\n\n[zkshell: 12] get /zk_test\nmy_data\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 5\nmtime = Fri Jun 05 13:57:06 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 0\naclVersion = 0\nephemeralOwner = 0\ndataLength = 7\nnumChildren = 0\n        </pre>\n<p>We can change the data associated with zk_test by issuing the <span class=\"codefrag command\">set</span> command, as in:\n        </p>\n<pre class=\"code\">\n\n[zkshell: 14] set /zk_test junk\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 6\nmtime = Fri Jun 05 14:01:52 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 1\naclVersion = 0\nephemeralOwner = 0\ndataLength = 4\nnumChildren = 0\n[zkshell: 15] get /zk_test\njunk\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 6\nmtime = Fri Jun 05 14:01:52 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 1\naclVersion = 0\nephemeralOwner = 0\ndataLength = 4\nnumChildren = 0\n      </pre>\n<p>\n       (Notice we did a <span class=\"codefrag command\">get</span> after setting the data and it did, indeed, change.</p>\n<p>Finally, let's <span class=\"codefrag command\">delete</span> the node by issuing:\n      </p>\n<pre class=\"code\">\n\n[zkshell: 16] delete /zk_test\n[zkshell: 17] ls /\n[zookeeper]\n[zkshell: 18]\n</pre>\n<p>That's it for now.  To explore more, continue with the rest of this document and see the <a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>. </p>\n<a name=\"sc_ProgrammingToZooKeeper\"></a>\n<h3 class=\"h4\">Programming to ZooKeeper</h3>\n<p>ZooKeeper has a Java bindings and C bindings. They are\n      functionally equivalent. The C bindings exist in two variants: single\n      threaded and multi-threaded. These differ only in how the messaging loop\n      is done. For more information, see the <a href=\"zookeeperProgrammers.html#ch_programStructureWithExample\">Programming\n      Examples in the ZooKeeper Programmer's Guide</a> for\n      sample code using of the different APIs.</p>\n<a name=\"sc_RunningReplicatedZooKeeper\"></a>\n<h3 class=\"h4\">Running Replicated ZooKeeper</h3>\n<p>Running ZooKeeper in standalone mode is convenient for evaluation,\n      some development, and testing. But in production, you should run\n      ZooKeeper in replicated mode. A replicated group of servers in the same\n      application is called a <em>quorum</em>, and in replicated\n      mode, all servers in the quorum have copies of the same configuration\n      file.</p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n      \n<p>\n         For replicated mode, a minimum of three servers are required,\n         and it is strongly recommended that you have an odd number of\n         servers. If you only have two servers, then you are in a\n         situation where if one of them fails, there are not enough\n         machines to form a majority quorum. Two servers is inherently\n         <strong>less</strong>\n         stable than a single server, because there are two single\n         points of failure.\n      </p>\n   \n</div>\n</div>\n<p>\n      The required\n      <strong>conf/zoo.cfg</strong>\n      file for replicated mode is similar to the one used in standalone\n      mode, but with a few differences. Here is an example:\n   </p>\n<pre class=\"code\">\ntickTime=2000\ndataDir=/var/lib/zookeeper\nclientPort=2181\ninitLimit=5\nsyncLimit=2\nserver.1=zoo1:2888:3888\nserver.2=zoo2:2888:3888\nserver.3=zoo3:2888:3888\n</pre>\n<p>The new entry, <strong>initLimit</strong> is\n      timeouts ZooKeeper uses to limit the length of time the ZooKeeper\n      servers in quorum have to connect to a leader. The entry <strong>syncLimit</strong> limits how far out of date a server can\n      be from a leader.</p>\n<p>With both of these timeouts, you specify the unit of time using\n      <strong>tickTime</strong>. In this example, the timeout\n      for initLimit is 5 ticks at 2000 milleseconds a tick, or 10\n      seconds.</p>\n<p>The entries of the form <em>server.X</em> list the\n      servers that make up the ZooKeeper service. When the server starts up,\n      it knows which server it is by looking for the file\n      <em>myid</em> in the data directory. That file has the \n      contains the server number, in ASCII.</p>\n<p>Finally, note the two port numbers after each server\n       name: \" 2888\" and \"3888\". Peers use the former port to connect\n       to other peers. Such a connection is necessary so that peers\n       can communicate, for example, to agree upon the order of\n       updates. More specifically, a ZooKeeper server uses this port\n       to connect followers to the leader. When a new leader arises, a\n       follower opens a TCP connection to the leader using this\n       port. Because the default leader election also uses TCP, we\n       currently require another port for leader election. This is the\n       second port in the server entry.\n       </p>\n<div class=\"note\">\n<div class=\"label\">Note</div>\n<div class=\"content\">\n        \n<p>If you want to test multiple servers on a single\n        machine, specify the servername\n        as <em>localhost</em> with unique quorum &amp;\n        leader election ports (i.e. 2888:3888, 2889:3889, 2890:3890 in\n        the example above) for each server.X in that server's config\n        file. Of course separate <em>dataDir</em>s and\n        distinct <em>clientPort</em>s are also necessary\n        (in the above replicated example, running on a\n        single <em>localhost</em>, you would still have\n        three config files).</p>\n        \n<p>Please be aware that setting up multiple servers on a single\n            machine will not create any redundancy. If something were to\n            happen which caused the machine to die, all of the zookeeper\n            servers would be offline. Full redundancy requires that each\n            server have its own machine. It must be a completely separate\n            physical server. Multiple virtual machines on the same physical\n            host are still vulnerable to the complete failure of that host.</p>\n      \n</div>\n</div>\n<a name=\"Other+Optimizations\"></a>\n<h3 class=\"h4\">Other Optimizations</h3>\n<p>There are a couple of other configuration parameters that can\n      greatly increase performance:</p>\n<ul>\n        \n<li>\n          \n<p>To get low latencies on updates it is important to\n          have a dedicated transaction log directory. By default\n          transaction logs are put in the same directory as the data\n          snapshots and <em>myid</em> file. The dataLogDir\n          parameters indicates a different directory to use for the\n          transaction logs.</p>\n        \n</li>\n\n        \n<li>\n          \n<p>\n<em>[tbd: what is the other config param?]</em>\n</p>\n        \n</li>\n      \n</ul>\n</div>\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zookeeperTutorial.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<meta content=\"Apache Forrest\" name=\"Generator\">\n<meta name=\"Forrest-version\" content=\"0.9\">\n<meta name=\"Forrest-skin-name\" content=\"pelt\">\n<title>Programming with ZooKeeper - A basic tutorial</title>\n<link type=\"text/css\" href=\"skin/basic.css\" rel=\"stylesheet\">\n<link media=\"screen\" type=\"text/css\" href=\"skin/screen.css\" rel=\"stylesheet\">\n<link media=\"print\" type=\"text/css\" href=\"skin/print.css\" rel=\"stylesheet\">\n<link type=\"text/css\" href=\"skin/profile.css\" rel=\"stylesheet\">\n<script src=\"skin/getBlank.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/getMenu.js\" language=\"javascript\" type=\"text/javascript\"></script><script src=\"skin/fontsize.js\" language=\"javascript\" type=\"text/javascript\"></script>\n<link rel=\"shortcut icon\" href=\"images/favicon.ico\">\n</head>\n<body onload=\"init()\">\n<script type=\"text/javascript\">ndeSetTextSize();</script>\n<div id=\"top\">\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n<a href=\"http://www.apache.org/\">Apache</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a> &gt; <a href=\"http://zookeeper.apache.org/\">ZooKeeper</a><script src=\"skin/breadcrumbs.js\" language=\"JavaScript\" type=\"text/javascript\"></script>\n</div>\n<!--+\n    |header\n    +-->\n<div class=\"header\">\n<!--+\n    |start group logo\n    +-->\n<div class=\"grouplogo\">\n<a href=\"http://hadoop.apache.org/\"><img class=\"logoImage\" alt=\"Hadoop\" src=\"images/hadoop-logo.jpg\" title=\"Apache Hadoop\"></a>\n</div>\n<!--+\n    |end group logo\n    +-->\n<!--+\n    |start Project Logo\n    +-->\n<div class=\"projectlogo\">\n<a href=\"http://zookeeper.apache.org/\"><img class=\"logoImage\" alt=\"ZooKeeper\" src=\"images/zookeeper_small.gif\" title=\"ZooKeeper: distributed coordination\"></a>\n</div>\n<!--+\n    |end Project Logo\n    +-->\n<!--+\n    |start Search\n    +-->\n<div class=\"searchbox\">\n<form action=\"http://www.google.com/search\" method=\"get\" class=\"roundtopsmall\">\n<input value=\"zookeeper.apache.org\" name=\"sitesearch\" type=\"hidden\"><input onFocus=\"getBlank (this, 'Search the site with google');\" size=\"25\" name=\"q\" id=\"query\" type=\"text\" value=\"Search the site with google\">&nbsp; \n                    <input name=\"Search\" value=\"Search\" type=\"submit\">\n</form>\n</div>\n<!--+\n    |end search\n    +-->\n<!--+\n    |start Tabs\n    +-->\n<ul id=\"tabs\">\n<li>\n<a class=\"unselected\" href=\"http://zookeeper.apache.org/\">Project</a>\n</li>\n<li>\n<a class=\"unselected\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\">Wiki</a>\n</li>\n<li class=\"current\">\n<a class=\"selected\" href=\"index.html\">ZooKeeper 3.4 Documentation</a>\n</li>\n</ul>\n<!--+\n    |end Tabs\n    +-->\n</div>\n</div>\n<div id=\"main\">\n<div id=\"publishedStrip\">\n<!--+\n    |start Subtabs\n    +-->\n<div id=\"level2tabs\"></div>\n<!--+\n    |end Endtabs\n    +-->\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<!--+\n    |breadtrail\n    +-->\n<div class=\"breadtrail\">\n\n             &nbsp;\n           </div>\n<!--+\n    |start Menu, mainarea\n    +-->\n<!--+\n    |start Menu\n    +-->\n<div id=\"menu\">\n<div onclick=\"SwitchMenu('menu_1.1', 'skin/')\" id=\"menu_1.1Title\" class=\"menutitle\">Overview</div>\n<div id=\"menu_1.1\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"index.html\">Welcome</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperOver.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperStarted.html\">Getting Started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"releasenotes.html\">Release Notes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_selected_1.2', 'skin/')\" id=\"menu_selected_1.2Title\" class=\"menutitle\" style=\"background-image: url('skin/images/chapter_open.gif');\">Developer</div>\n<div id=\"menu_selected_1.2\" class=\"selectedmenuitemgroup\" style=\"display: block;\">\n<div class=\"menuitem\">\n<a href=\"api/index.html\">API Docs</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperProgrammers.html\">Programmer's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"javaExample.html\">Java Example</a>\n</div>\n<div class=\"menupage\">\n<div class=\"menupagetitle\">Barrier and Queue Tutorial</div>\n</div>\n<div class=\"menuitem\">\n<a href=\"recipes.html\">Recipes</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.3', 'skin/')\" id=\"menu_1.3Title\" class=\"menutitle\">BookKeeper</div>\n<div id=\"menu_1.3\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"bookkeeperStarted.html\">Getting started</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperOverview.html\">Overview</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperConfig.html\">Setup guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"bookkeeperProgrammer.html\">Programmer's guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.4', 'skin/')\" id=\"menu_1.4Title\" class=\"menutitle\">Admin &amp; Ops</div>\n<div id=\"menu_1.4\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperAdmin.html\">Administrator's Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperQuotas.html\">Quota Guide</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperJMX.html\">JMX</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"zookeeperObservers.html\">Observers Guide</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.5', 'skin/')\" id=\"menu_1.5Title\" class=\"menutitle\">Contributor</div>\n<div id=\"menu_1.5\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"zookeeperInternals.html\">ZooKeeper Internals</a>\n</div>\n</div>\n<div onclick=\"SwitchMenu('menu_1.6', 'skin/')\" id=\"menu_1.6Title\" class=\"menutitle\">Miscellaneous</div>\n<div id=\"menu_1.6\" class=\"menuitemgroup\">\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\">Wiki</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\">FAQ</a>\n</div>\n<div class=\"menuitem\">\n<a href=\"http://zookeeper.apache.org/mailing_lists.html\">Mailing Lists</a>\n</div>\n</div>\n<div id=\"credit\"></div>\n<div id=\"roundbottom\">\n<img style=\"display: none\" class=\"corner\" height=\"15\" width=\"15\" alt=\"\" src=\"skin/images/rc-b-l-15-1body-2menu-3menu.png\"></div>\n<!--+\n  |alternative credits\n  +-->\n<div id=\"credit2\"></div>\n</div>\n<!--+\n    |end Menu\n    +-->\n<!--+\n    |start content\n    +-->\n<div id=\"content\">\n<div title=\"Portable Document Format\" class=\"pdflink\">\n<a class=\"dida\" href=\"zookeeperTutorial.pdf\"><img alt=\"PDF -icon\" src=\"skin/images/pdfdoc.gif\" class=\"skin\"><br>\n        PDF</a>\n</div>\n<h1>Programming with ZooKeeper - A basic tutorial</h1>\n<div id=\"front-matter\">\n<div id=\"minitoc-area\">\n<ul class=\"minitoc\">\n<li>\n<a href=\"#ch_Introduction\">Introduction</a>\n</li>\n<li>\n<a href=\"#sc_barriers\">Barriers</a>\n</li>\n<li>\n<a href=\"#sc_producerConsumerQueues\">Producer-Consumer Queues</a>\n</li>\n<li>\n<a href=\"#Complete+example\">Complete example</a>\n<ul class=\"minitoc\">\n<li>\n<a href=\"#Queue+test\">Queue test</a>\n</li>\n<li>\n<a href=\"#Barrier+test\">Barrier test</a>\n</li>\n<li>\n<a href=\"#sc_sourceListing\">Source Listing</a>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n  \n\n  \n\n  \n<a name=\"ch_Introduction\"></a>\n<h2 class=\"h3\">Introduction</h2>\n<div class=\"section\">\n<p>In this tutorial, we show simple implementations of barriers and \n    producer-consumer queues using ZooKeeper. We call the respective classes Barrier and Queue. \n    These examples assume that you have at least one ZooKeeper server running.</p>\n<p>Both primitives use the following common excerpt of code:</p>\n<pre class=\"code\">\n    static ZooKeeper zk = null;\n    static Integer mutex;\n\n    String root;\n\n    SyncPrimitive(String address) {\n        if(zk == null){\n            try {\n                System.out.println(\"Starting ZK:\");\n                zk = new ZooKeeper(address, 3000, this);\n                mutex = new Integer(-1);\n                System.out.println(\"Finished starting ZK: \" + zk);\n            } catch (IOException e) {\n                System.out.println(e.toString());\n                zk = null;\n            }\n        }\n    }\n\n    synchronized public void process(WatchedEvent event) {\n        synchronized (mutex) {\n            mutex.notify();\n        }\n    }\n</pre>\n<p>Both classes extend SyncPrimitive. In this way, we execute steps that are \ncommon to all primitives in the constructor of SyncPrimitive. To keep the examples \nsimple, we create a ZooKeeper object the first time we instantiate either a barrier \nobject or a queue object, and we declare a static variable that is a reference \nto this object. The subsequent instances of Barrier and Queue check whether a \nZooKeeper object exists. Alternatively, we could have the application creating a\nZooKeeper object and passing it to the constructor of Barrier and Queue.</p>\n<p>\nWe use the process() method to process notifications triggered due to watches. \nIn the following discussion, we present code that sets watches. A watch is internal \nstructure that enables ZooKeeper to notify a client of a change to a node. For example, \nif a client is waiting for other clients to leave a barrier, then it can set a watch and \nwait for modifications to a particular node, which can indicate that it is the end of the wait. \nThis point becomes clear once we go over the examples.\n</p>\n</div>\n   \n \n<a name=\"sc_barriers\"></a>\n<h2 class=\"h3\">Barriers</h2>\n<div class=\"section\">\n<p>\n A barrier is a primitive that enables a group of processes to synchronize the \n beginning and the end of a computation. The general idea of this implementation \n is to have a barrier node that serves the purpose of being a parent for individual \n process nodes. Suppose that we call the barrier node \"/b1\". Each process \"p\" then \n creates a node \"/b1/p\". Once enough processes have created their corresponding \n nodes, joined processes can start the computation.\n </p>\n<p>In this example, each process instantiates a Barrier object, and its constructor takes as parameters:</p>\n<ul>\n<li>\n<p>the address of a ZooKeeper server (e.g., \"zoo1.foo.com:2181\")</p>\n</li>\n\n<li>\n<p>the path of the barrier node on ZooKeeper (e.g., \"/b1\")</p>\n</li>\n\n<li>\n<p>the size of the group of processes</p>\n</li>\n\n</ul>\n<p>The constructor of Barrier passes the address of the Zookeeper server to the \nconstructor of the parent class. The parent class creates a ZooKeeper instance if \none does not exist. The constructor of Barrier then creates a \nbarrier node on ZooKeeper, which is the parent node of all process nodes, and \nwe call root (<strong>Note:</strong> This is not the ZooKeeper root \"/\").</p>\n<pre class=\"code\">\n        /**\n         * Barrier constructor\n         *\n         * @param address\n         * @param root\n         * @param size\n         */\n        Barrier(String address, String root, int size) {\n            super(address);\n            this.root = root;\n            this.size = size;\n\n            // Create barrier node\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n\n            // My node name\n            try {\n                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());\n            } catch (UnknownHostException e) {\n                System.out.println(e.toString());\n            }\n\n        }\n</pre>\n<p>\nTo enter the barrier, a process calls enter(). The process creates a node under \nthe root to represent it, using its host name to form the node name. It then wait \nuntil enough processes have entered the barrier. A process does it by checking \nthe number of children the root node has with \"getChildren()\", and waiting for \nnotifications in the case it does not have enough. To receive a notification when \nthere is a change to the root node, a process has to set a watch, and does it \nthrough the call to \"getChildren()\". In the code, we have that \"getChildren()\" \nhas two parameters. The first one states the node to read from, and the second is\na boolean flag that enables the process to set a watch. In the code the flag is true.\n</p>\n<pre class=\"code\">\n        /**\n         * Join barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean enter() throws KeeperException, InterruptedException{\n            zk.create(root + \"/\" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL_SEQUENTIAL);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n\n                    if (list.size() &lt; size) {\n                        mutex.wait();\n                    } else {\n                        return true;\n                    }\n                }\n            }\n        }\n</pre>\n<p>\nNote that enter() throws both KeeperException and InterruptedException, so it is \nthe reponsability of the application to catch and handle such exceptions.</p>\n<p>\nOnce the computation is finished, a process calls leave() to leave the barrier. \nFirst it deletes its corresponding node, and then it gets the children of the root \nnode. If there is at least one child, then it waits for a notification (obs: note \nthat the second parameter of the call to getChildren() is true, meaning that \nZooKeeper has to set a watch on the the root node). Upon reception of a notification, \nit checks once more whether the root node has any child.</p>\n<pre class=\"code\">\n        /**\n         * Wait until all reach barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean leave() throws KeeperException, InterruptedException{\n            zk.delete(root + \"/\" + name, 0);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                        if (list.size() &gt; 0) {\n                            mutex.wait();\n                        } else {\n                            return true;\n                        }\n                    }\n                }\n        }\n    }\n</pre>\n</div>\n\n<a name=\"sc_producerConsumerQueues\"></a>\n<h2 class=\"h3\">Producer-Consumer Queues</h2>\n<div class=\"section\">\n<p>\nA producer-consumer queue is a distributed data estructure thata group of processes \nuse to generate and consume items. Producer processes create new elements and add \nthem to the queue. Consumer processes remove elements from the list, and process them. \nIn this implementation, the elements are simple integers. The queue is represented \nby a root node, and to add an element to the queue, a producer process creates a new node, \na child of the root node.\n</p>\n<p>\nThe following excerpt of code corresponds to the constructor of the object. As \nwith Barrier objects, it first calls the constructor of the parent class, SyncPrimitive, \nthat creates a ZooKeeper object if one doesn't exist. It then verifies if the root \nnode of the queue exists, and creates if it doesn't.\n</p>\n<pre class=\"code\">\n        /**\n         * Constructor of producer-consumer queue\n         *\n         * @param address\n         * @param name\n         */\n        Queue(String address, String name) {\n            super(address);\n            this.root = name;\n            // Create ZK node name\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n        }\n</pre>\n<p>\nA producer process calls \"produce()\" to add an element to the queue, and passes \nan integer as an argument. To add an element to the queue, the method creates a \nnew node using \"create()\", and uses the SEQUENCE flag to instruct ZooKeeper to \nappend the value of the sequencer counter associated to the root node. In this way, \nwe impose a total order on the elements of the queue, thus guaranteeing that the \noldest element of the queue is the next one consumed.\n</p>\n<pre class=\"code\">\n        /**\n         * Add element to the queue.\n         *\n         * @param i\n         * @return\n         */\n\n        boolean produce(int i) throws KeeperException, InterruptedException{\n            ByteBuffer b = ByteBuffer.allocate(4);\n            byte[] value;\n\n            // Add child with value i\n            b.putInt(i);\n            value = b.array();\n            zk.create(root + \"/element\", value, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT_SEQUENTIAL);\n\n            return true;\n        }\n</pre>\n<p>\nTo consume an element, a consumer process obtains the children of the root node, \nreads the node with smallest counter value, and returns the element. Note that \nif there is a conflict, then one of the two contending processes won't be able to \ndelete the node and the delete operation will throw an exception.</p>\n<p>\nA call to getChildren() returns the list of children in lexicographic order. \nAs lexicographic order does not necessary follow the numerical order of the counter \nvalues, we need to decide which element is the smallest. To decide which one has \nthe smallest counter value, we traverse the list, and remove the prefix \"element\" \nfrom each one.</p>\n<pre class=\"code\">\n        /**\n         * Remove first element from the queue.\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n        int consume() throws KeeperException, InterruptedException{\n            int retvalue = -1;\n            Stat stat = null;\n\n            // Get the first element available\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                    if (list.size() == 0) {\n                        System.out.println(\"Going to wait\");\n                        mutex.wait();\n                    } else {\n                        Integer min = new Integer(list.get(0).substring(7));\n                        for(String s : list){\n                            Integer tempValue = new Integer(s.substring(7));\n                            //System.out.println(\"Temporary value: \" + tempValue);\n                            if(tempValue &lt; min) min = tempValue;\n                        }\n                        System.out.println(\"Temporary value: \" + root + \"/element\" + min);\n                        byte[] b = zk.getData(root + \"/element\" + min,\n                                    false, stat);\n                        zk.delete(root + \"/element\" + min, 0);\n                        ByteBuffer buffer = ByteBuffer.wrap(b);\n                        retvalue = buffer.getInt();\n\n                        return retvalue;\n                    }\n                }\n            }\n        }\n    }\n</pre>\n</div>\n\n\n<a name=\"Complete+example\"></a>\n<h2 class=\"h3\">Complete example</h2>\n<div class=\"section\">\n<p>\nIn the following section you can find a complete command line application to demonstrate the above mentioned\nrecipes. Use the following command to run it.\n</p>\n<pre class=\"code\">\nZOOBINDIR=\"[path_to_distro]/bin\"\n. \"$ZOOBINDIR\"/zkEnv.sh\njava SyncPrimitive [Test Type] [ZK server] [No of elements] [Client type]\n</pre>\n<a name=\"Queue+test\"></a>\n<h3 class=\"h4\">Queue test</h3>\n<p>Start a producer to create 100 elements</p>\n<pre class=\"code\">\njava SyncPrimitive qTest localhost 100 p\n</pre>\n<p>Start a consumer to consume 100 elements</p>\n<pre class=\"code\">\njava SyncPrimitive qTest localhost 100 c\n</pre>\n<a name=\"Barrier+test\"></a>\n<h3 class=\"h4\">Barrier test</h3>\n<p>Start a barrier with 2 participants (start as many times as many participants you'd like to enter)</p>\n<pre class=\"code\">\njava SyncPrimitive bTest localhost 2\n</pre>\n<a name=\"sc_sourceListing\"></a>\n<h3 class=\"h4\">Source Listing</h3>\n<div class=\"note example\">\n<div class=\"label\">SyncPrimitive.Java</div>\n<div class=\"content\">\n\n<title>SyncPrimitive.Java</title>\n\n<pre class=\"code\">\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.nio.ByteBuffer;\nimport java.util.List;\nimport java.util.Random;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\n\npublic class SyncPrimitive implements Watcher {\n\n    static ZooKeeper zk = null;\n    static Integer mutex;\n\n    String root;\n\n    SyncPrimitive(String address) {\n        if(zk == null){\n            try {\n                System.out.println(\"Starting ZK:\");\n                zk = new ZooKeeper(address, 3000, this);\n                mutex = new Integer(-1);\n                System.out.println(\"Finished starting ZK: \" + zk);\n            } catch (IOException e) {\n                System.out.println(e.toString());\n                zk = null;\n            }\n        }\n        //else mutex = new Integer(-1);\n    }\n\n    synchronized public void process(WatchedEvent event) {\n        synchronized (mutex) {\n            //System.out.println(\"Process: \" + event.getType());\n            mutex.notify();\n        }\n    }\n\n    /**\n     * Barrier\n     */\n    static public class Barrier extends SyncPrimitive {\n        int size;\n        String name;\n\n        /**\n         * Barrier constructor\n         *\n         * @param address\n         * @param root\n         * @param size\n         */\n        Barrier(String address, String root, int size) {\n            super(address);\n            this.root = root;\n            this.size = size;\n\n            // Create barrier node\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n\n            // My node name\n            try {\n                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());\n            } catch (UnknownHostException e) {\n                System.out.println(e.toString());\n            }\n\n        }\n\n        /**\n         * Join barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean enter() throws KeeperException, InterruptedException{\n            zk.create(root + \"/\" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL_SEQUENTIAL);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n\n                    if (list.size() &lt; size) {\n                        mutex.wait();\n                    } else {\n                        return true;\n                    }\n                }\n            }\n        }\n\n        /**\n         * Wait until all reach barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean leave() throws KeeperException, InterruptedException{\n            zk.delete(root + \"/\" + name, 0);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                        if (list.size() &gt; 0) {\n                            mutex.wait();\n                        } else {\n                            return true;\n                        }\n                    }\n                }\n        }\n    }\n\n    /**\n     * Producer-Consumer queue\n     */\n    static public class Queue extends SyncPrimitive {\n\n        /**\n         * Constructor of producer-consumer queue\n         *\n         * @param address\n         * @param name\n         */\n        Queue(String address, String name) {\n            super(address);\n            this.root = name;\n            // Create ZK node name\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n        }\n\n        /**\n         * Add element to the queue.\n         *\n         * @param i\n         * @return\n         */\n\n        boolean produce(int i) throws KeeperException, InterruptedException{\n            ByteBuffer b = ByteBuffer.allocate(4);\n            byte[] value;\n\n            // Add child with value i\n            b.putInt(i);\n            value = b.array();\n            zk.create(root + \"/element\", value, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT_SEQUENTIAL);\n\n            return true;\n        }\n\n\n        /**\n         * Remove first element from the queue.\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n        int consume() throws KeeperException, InterruptedException{\n            int retvalue = -1;\n            Stat stat = null;\n\n            // Get the first element available\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                    if (list.size() == 0) {\n                        System.out.println(\"Going to wait\");\n                        mutex.wait();\n                    } else {\n                        Integer min = new Integer(list.get(0).substring(7));\n                        String minNode = list.get(0);\n                        for(String s : list){\n                            Integer tempValue = new Integer(s.substring(7));\n                            //System.out.println(\"Temporary value: \" + tempValue);\n                            if(tempValue &lt; min) {\n                                min = tempValue;\n                                minNode = s;\n                            }\n                        }\n                        System.out.println(\"Temporary value: \" + root + \"/\" + minNode);\n                        byte[] b = zk.getData(root + \"/\" + minNode,\n                        false, stat);\n                        zk.delete(root + \"/\" + minNode, 0);\n                        ByteBuffer buffer = ByteBuffer.wrap(b);\n                        retvalue = buffer.getInt();\n\n                        return retvalue;\n                    }\n                }\n            }\n        }\n    }\n\n    public static void main(String args[]) {\n        if (args[0].equals(\"qTest\"))\n            queueTest(args);\n        else\n            barrierTest(args);\n\n    }\n\n    public static void queueTest(String args[]) {\n        Queue q = new Queue(args[1], \"/app1\");\n\n        System.out.println(\"Input: \" + args[1]);\n        int i;\n        Integer max = new Integer(args[2]);\n\n        if (args[3].equals(\"p\")) {\n            System.out.println(\"Producer\");\n            for (i = 0; i &lt; max; i++)\n                try{\n                    q.produce(10 + i);\n                } catch (KeeperException e){\n\n                } catch (InterruptedException e){\n\n                }\n        } else {\n            System.out.println(\"Consumer\");\n\n            for (i = 0; i &lt; max; i++) {\n                try{\n                    int r = q.consume();\n                    System.out.println(\"Item: \" + r);\n                } catch (KeeperException e){\n                    i--;\n                } catch (InterruptedException e){\n\n                }\n            }\n        }\n    }\n\n    public static void barrierTest(String args[]) {\n        Barrier b = new Barrier(args[1], \"/b1\", new Integer(args[2]));\n        try{\n            boolean flag = b.enter();\n            System.out.println(\"Entered barrier: \" + args[2]);\n            if(!flag) System.out.println(\"Error when entering the barrier\");\n        } catch (KeeperException e){\n\n        } catch (InterruptedException e){\n\n        }\n\n        // Generate random integer\n        Random rand = new Random();\n        int r = rand.nextInt(100);\n        // Loop for rand iterations\n        for (int i = 0; i &lt; r; i++) {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n\n            }\n        }\n        try{\n            b.leave();\n        } catch (KeeperException e){\n\n        } catch (InterruptedException e){\n\n        }\n        System.out.println(\"Left barrier\");\n    }\n}\n</pre>\n</div>\n</div>\n</div>\n\n\n<p align=\"right\">\n<font size=\"-2\"></font>\n</p>\n</div>\n<!--+\n    |end content\n    +-->\n<div class=\"clearboth\">&nbsp;</div>\n</div>\n<div id=\"footer\">\n<!--+\n    |start bottomstrip\n    +-->\n<div class=\"lastmodified\">\n<script type=\"text/javascript\"><!--\ndocument.write(\"Last Published: \" + document.lastModified);\n//  --></script>\n</div>\n<div class=\"copyright\">\n        Copyright &copy;\n          <a href=\"http://www.apache.org/licenses/\">The Apache Software Foundation.</a>\n</div>\n<!--+\n    |end bottomstrip\n    +-->\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "ivy.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<ivy-module version=\"2.0\"\n            xmlns:e=\"http://ant.apache.org/ivy/extra\">\n\n  <info organisation=\"org.apache.zookeeper\"\n        module=\"${name}\" revision=\"${version}\">\n    <license name=\"Apache 2.0\"/>\n    <ivyauthor name=\"Apache ZooKeeper\" url=\"http://zookeeper.apache.org\"/>\n    <description>ZooKeeper</description>\n  </info>\n\n  <configurations defaultconfmapping=\"default\">\n    <conf name=\"master\"/>\n    <conf name=\"default\"/>\n    <conf name=\"test\" extends=\"default\"/>\n    <conf name=\"mvn-ant-task\" visibility=\"private\"/>\n    <conf name=\"package\" extends=\"master\"/>\n    <conf name=\"jdiff\" visibility=\"private\"/>\n    <conf name=\"releaseaudit\" visibility=\"private\" description=\"Artifacts required for releaseaudit target\"/>\n    <conf name=\"owasp\" visibility=\"private\" description=\"Artifacts required for owasp target\"/>\n  </configurations>\n\n  <publications>\n    <artifact name='org.apache.zookeeper' type='jar' ext='jar' />\n  </publications>\n\n  <dependencies>\n    <dependency org=\"org.slf4j\" name=\"slf4j-api\" rev=\"${slf4j.version}\"/>\n    <dependency org=\"org.slf4j\" name=\"slf4j-log4j12\" rev=\"${slf4j.version}\" transitive=\"false\"/>\n\n    <dependency org=\"org.apache.maven.wagon\" name=\"wagon-http\" rev=\"${wagon-http.version}\"\n                conf=\"mvn-ant-task->default\"/>\n    <dependency org=\"org.apache.maven\" name=\"maven-ant-tasks\" rev=\"${maven-ant-tasks.version}\"\n                conf=\"mvn-ant-task->default\">\n        <exclude org=\"org.codehaus.plexus\" module=\"plexus-utils\"/>\n        <exclude org=\"org.apache.maven.wagon\" module=\"wagon-provider-api\" />\n    </dependency>\n    <!-- transitive false turns off dependency checking, log4j deps seem borked -->\n    <dependency org=\"log4j\" name=\"log4j\" rev=\"${log4j.version}\" transitive=\"false\" conf=\"default\"/>\n    <dependency org=\"jline\" name=\"jline\" rev=\"${jline.version}\" transitive=\"false\" conf=\"default\"/>\n\n    <dependency org=\"org.apache.yetus\" name=\"audience-annotations\" rev=\"${audience-annotations.version}\"/>\n\n    <dependency org=\"io.netty\" name=\"netty\" conf=\"default\" rev=\"${netty.version}\">\n      <artifact name=\"netty\" type=\"jar\" conf=\"default\"/>\n    </dependency>\n\n    <dependency org=\"org.vafer\" name=\"jdeb\" rev=\"${jdeb.version}\" conf=\"package->master\"/>\n\n    <dependency org=\"junit\" name=\"junit\" rev=\"${junit.version}\" conf=\"test->default\"/>\n    <dependency org=\"org.mockito\" name=\"mockito-all\" rev=\"${mockito.version}\"\n               conf=\"test->default\"/>\n    <dependency org=\"com.puppycrawl.tools\" name=\"checkstyle\" rev=\"${checkstyle.version}\"\n                conf=\"test->default\"/>\n    <dependency org=\"commons-collections\" name=\"commons-collections\" \n                rev=\"${commons-collections.version}\" conf=\"test->default\"/>\n\n    <dependency org=\"jdiff\" name=\"jdiff\" rev=\"${jdiff.version}\"\n                conf=\"jdiff->default\"/>\n    <dependency org=\"xerces\" name=\"xerces\" rev=\"${xerces.version}\"\n                conf=\"jdiff->default\"/>\n\n    <dependency org=\"org.apache.rat\" name=\"apache-rat-tasks\" \n                rev=\"${apache-rat-tasks.version}\" conf=\"releaseaudit->default\">\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"commons-lang\" module=\"commons-lang\"/>\n    </dependency>\n    <dependency org=\"commons-lang\" name=\"commons-lang\" \n                rev=\"${commons-lang.version}\" conf=\"releaseaudit->default\"/>\n    <dependency org=\"commons-collections\" name=\"commons-collections\"\n                rev=\"${commons-collections.version}\" conf=\"releaseaudit->default\"/>\n    <dependency org=\"org.owasp\" name=\"dependency-check-ant\"\n                rev=\"${dependency-check-ant.version}\" conf=\"owasp->default\"/>\n\n    <dependency org=\"commons-io\" name=\"commons-io\" rev=\"${commons-io.version}\"\n                conf=\"test->default\"/>\n\n\n    <!-- Apache directory server project, org.apache.directory.* packages for miniKdc tests -->\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-core-api\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-interceptor-kerberos\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-protocol-shared\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-protocol-kerberos\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-ldif-partition\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-mavibot-partition\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-log4j12\"/>\n        <exclude org=\"log4j\" module=\"log4j\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.api\" name=\"api-all\" rev=\"${apache-directory-api.version}\" conf=\"test->default\">\n        <exclude org=\"xml-apis\" module=\"xml-apis\"/>\n        <exclude org=\"xpp3\" module=\"xpp3\"/>\n        <exclude org=\"dom4j\" module=\"dom4j\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-jdbm-partition\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n    <dependency org=\"org.apache.directory.server\" name=\"apacheds-protocol-ldap\" rev=\"${apache-directory-server.version}\" conf=\"test->default\">\n        <exclude org=\"org.apache.directory.api\" module=\"api-ldap-schema-data\"/>\n        <exclude org=\"commons-collections\" module=\"commons-collections\"/>\n        <exclude org=\"org.slf4j\" module=\"slf4j-api\"/>\n    </dependency>\n\n    <conflict manager=\"strict\"/>\n\n  </dependencies>\n\n</ivy-module>\n"
  },
  {
    "path": "ivysettings.xml",
    "content": "<ivysettings>\n\n <!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n  <property name=\"repo.maven.org\"\n    value=\"https://repo1.maven.org/maven2/\" override=\"false\"/>\n  <property name=\"repo.jboss.org\"\n    value=\"https://repository.jboss.org/nexus/content/groups/public/\" override=\"false\"/>\n  <property name=\"maven2.pattern\"\n    value=\"[organisation]/[module]/[revision]/[module]-[revision]\"/>\n  <property name=\"maven2.pattern.ext\" value=\"${maven2.pattern}.[ext]\"/>\n  <include url=\"${ivy.default.conf.dir}/ivyconf-local.xml\"/>\n  <settings defaultResolver=\"default\"/>\n  <resolvers>\n    <ibiblio name=\"maven2\" root=\"${repo.maven.org}\"\n      pattern=\"${maven2.pattern.ext}\" m2compatible=\"true\"/>\n    <ibiblio name=\"jboss-maven2\" root=\"${repo.jboss.org}\"\n      pattern=\"${maven2.pattern.ext}\" m2compatible=\"true\"/>\n\n    <chain name=\"default\" dual=\"true\">\n      <resolver ref=\"maven2\"/>\n      <resolver ref=\"jboss-maven2\"/>\n    </chain>\n\n  </resolvers>\n</ivysettings>\n"
  },
  {
    "path": "readme.md",
    "content": "# Apache ZooKeeper .NET async Client\n\n<p>\n<img src=\"https://svn.apache.org/repos/asf/comdev/project-logos/originals/zookeeper.svg\" width=\"400\">\n</p>\n\n[![NuGet](https://img.shields.io/github/release/shayhatsor/zookeeper.svg?style=flat&label=Latest%20Release)](https://github.com/shayhatsor/zookeeper/releases/latest)\n* Supports .NET 4.61 and above, including .NET Core.\n* Fully Task-based Asynchronous (async/await).\n* Follows the logic of the official Java client to the letter, in fact the code is almost identical. \n* NuGets\n  * Client [ZooKeeperNetEx](https://www.nuget.org/packages/ZooKeeperNetEx)\n  * Recipes [ZooKeeperNetEx.Recipes](https://www.nuget.org/packages/ZooKeeperNetEx.Recipes)\n\n\n#### Build From Source\n##### Prerequisites\n1. [Oracle JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).\n1. [Apache Ant](http://ant.apache.org/manual/install.html).\n2. [Visual Studio](https://visualstudio.microsoft.com/vs/).\n\n##### Build Steps\n1. Run `ant` on the repository's root folder.\n3. Open `src\\csharp\\ZooKeeperNetEx.sln` with Visual Studio.\n4. Build.\n"
  },
  {
    "path": "src/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\nThis distribution bundles jline 0.9.94, which is available under the\n2-clause BSD License. For details, see a copy of the license in\nlib/jline-0.9.94.LICENSE.txt\n\nThis distribution bundles SLF4J 1.6.1, which is available under the MIT\nLicense. For details, see a copy of the license in\nlib/slf4j-1.6.1.LICENSE.txt\n\nThis distribution bundles a modified version of 'JZLib' as part of\nNetty-3.7.0, which is available under the 3-clause BSD licence. For\ndetails, see a copy of the licence in META-INF/license/LICENSE-jzlib.txt\nas part of the Netty jar in lib/netty-3.7.0.Final.jar.\n"
  },
  {
    "path": "src/NOTICE.txt",
    "content": "Apache ZooKeeper\nCopyright 2009-2018 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n\nThis product includes software developed by\nThe Netty Project (http://netty.io/)\nCopyright 2011 The Netty Project\n\nThe Netty NOTICE file contains the following items:\nThis product contains the extensions to Java Collections Framework which has\nbeen derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene:\n\n  * LICENSE:\n    * license/LICENSE.jsr166y.txt (Public Domain)\n  * HOMEPAGE:\n    * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/\n    * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/\n\nThis product contains a modified version of Robert Harder's Public Domain\nBase64 Encoder and Decoder, which can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.base64.txt (Public Domain)\n  * HOMEPAGE:\n    * http://iharder.sourceforge.net/current/java/base64/\n\nThis product contains a modified version of 'JZlib', a re-implementation of\nzlib in pure Java, which can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.jzlib.txt (BSD Style License)\n  * HOMEPAGE:\n    * http://www.jcraft.com/jzlib/\n\nThis product contains a modified version of 'Webbit', a Java event based\nWebSocket and HTTP server:\n\n  * LICENSE:\n    * license/LICENSE.webbit.txt (BSD License)\n  * HOMEPAGE:\n    * https://github.com/joewalnes/webbit\n\nThis product optionally depends on 'Protocol Buffers', Google's data\ninterchange format, which can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.protobuf.txt (New BSD License)\n  * HOMEPAGE:\n    * http://code.google.com/p/protobuf/\n\nThis product optionally depends on 'Bouncy Castle Crypto APIs' to generate\na temporary self-signed X.509 certificate when the JVM does not provide the\nequivalent functionality.  It can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.bouncycastle.txt (MIT License)\n  * HOMEPAGE:\n    * http://www.bouncycastle.org/\n\nThis product optionally depends on 'SLF4J', a simple logging facade for Java,\nwhich can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.slf4j.txt (MIT License)\n  * HOMEPAGE:\n    * http://www.slf4j.org/\n\nThis product optionally depends on 'Apache Commons Logging', a logging\nframework, which can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.commons-logging.txt (Apache License 2.0)\n  * HOMEPAGE:\n    * http://commons.apache.org/logging/\n\nThis product optionally depends on 'Apache Log4J', a logging framework,\nwhich can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.log4j.txt (Apache License 2.0)\n  * HOMEPAGE:\n    * http://logging.apache.org/log4j/\n\nThis product optionally depends on 'JBoss Logging', a logging framework,\nwhich can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.jboss-logging.txt (GNU LGPL 2.1)\n  * HOMEPAGE:\n    * http://anonsvn.jboss.org/repos/common/common-logging-spi/\n\nThis product optionally depends on 'Apache Felix', an open source OSGi\nframework implementation, which can be obtained at:\n\n  * LICENSE:\n    * license/LICENSE.felix.txt (Apache License 2.0)\n  * HOMEPAGE:\n    * http://felix.apache.org/\n"
  },
  {
    "path": "src/c/CMakeLists.txt",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ncmake_minimum_required(VERSION 3.6)\n\nproject(zookeeper VERSION 3.4.12)\nset(email user@zookeeper.apache.org)\nset(description \"zookeeper C client\")\n\n# general options\ninclude_directories(include tests generated ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})\nif(UNIX)\n  add_compile_options(-Wall -fPIC)\nelseif(WIN32)\n  add_compile_options(/W3)\nendif()\nadd_definitions(-DUSE_STATIC_LIB)\n\n# TODO: Enable /WX and /W4 on Windows. Currently there are ~1000 warnings.\n# TODO: Add Solaris support.\n# TODO: Add a shared library option.\n# TODO: Specify symbols to export.\n# TODO: Generate doxygen documentation.\n\n# Sync API option\noption(WANT_SYNCAPI \"Enables Sync API support\" ON)\nif(WANT_SYNCAPI)\n  add_definitions(-DTHREADED)\n  if(WIN32)\n    # Note that the generator expression ensures that `/MTd` is used when Debug\n    # configurations are built.\n    add_compile_options(/MT$<$<CONFIG:Debug>:d>)\n  endif()\nendif()\n\n# CppUnit option\nif(WIN32 OR APPLE)\n  # The tests do not yet compile on Windows or macOS,\n  # so we set this to off by default.\n  #\n  # Note that CMake does not have expressions except in conditionals,\n  # so we're left with this if/else/endif pattern.\n  set(DEFAULT_WANT_CPPUNIT OFF)\nelse()\n  set(DEFAULT_WANT_CPPUNIT ON)\nendif()\noption(WANT_CPPUNIT \"Enables CppUnit and tests\" ${DEFAULT_WANT_CPPUNIT})\n\n# The function `to_have(in out)` converts a header name like `arpa/inet.h`\n# into an Autotools style preprocessor definition `HAVE_ARPA_INET_H`.\n# This is then set or unset in `configure_file()` step.\n#\n# Note that CMake functions do not have return values; instead an \"out\"\n# variable must be passed, and explicitly set with parent scope.\nfunction(to_have in out)\n  string(TOUPPER ${in} str)\n  string(REGEX REPLACE \"/|\\\\.\" \"_\" str ${str})\n  set(${out} \"HAVE_${str}\" PARENT_SCOPE)\nendfunction()\n\n# include file checks\nforeach(f generated/zookeeper.jute.h generated/zookeeper.jute.c)\n  if(EXISTS \"${CMAKE_SOURCE_DIR}/${f}\")\n    to_have(${f} name)\n    set(${name} 1)\n  else()\n    message(FATAL_ERROR\n      \"jute files are missing!\\n\"\n      \"Please run 'ant compile_jute' while in the ZooKeeper top level directory.\")\n  endif()\nendforeach()\n\n# header checks\ninclude(CheckIncludeFile)\nset(check_headers\n  arpa/inet.h\n  dlfcn.h\n  fcntl.h\n  inttypes.h\n  memory.h\n  netdb.h\n  netinet/in.h\n  stdint.h\n  stdlib.h\n  string.h\n  strings.h\n  sys/socket.h\n  sys/stat.h\n  sys/time.h\n  sys/types.h\n  unistd.h\n  sys/utsname.h)\n\nforeach(f ${check_headers})\n  to_have(${f} name)\n  check_include_file(${f} ${name})\nendforeach()\n\n# function checks\ninclude(CheckFunctionExists)\nset(check_functions\n  getcwd\n  gethostbyname\n  gethostname\n  getlogin\n  getpwuid_r\n  gettimeofday\n  getuid\n  memmove\n  memset\n  poll\n  socket\n  strchr\n  strdup\n  strerror\n  strtol)\n\nforeach(fn ${check_functions})\n  to_have(${fn} name)\n  check_function_exists(${fn} ${name})\nendforeach()\n\n# library checks\nset(check_libraries rt m pthread)\nforeach(lib ${check_libraries})\n  to_have(\"lib${lib}\" name)\n  find_library(${name} ${lib})\nendforeach()\n\n# IPv6 check\ninclude(CheckStructHasMember)\ncheck_struct_has_member(\"struct sockaddr_in6\" sin6_addr \"netinet/in.h\" ZOO_IPV6_ENABLED)\n\n# configure\nconfigure_file(cmake_config.h.in ${CMAKE_SOURCE_DIR}/include/config.h)\n\n# hashtable library\nset(hashtable_sources src/hashtable/hashtable_itr.c src/hashtable/hashtable.c)\nadd_library(hashtable STATIC ${hashtable_sources})\ntarget_link_libraries(hashtable PUBLIC $<$<PLATFORM_ID:Linux>:m>)\n\n# zookeeper library\nset(zookeeper_sources\n  src/zookeeper.c\n  src/recordio.c\n  generated/zookeeper.jute.c\n  src/zk_log.c\n  src/zk_hashtable.c)\n\nif(WANT_SYNCAPI)\n  list(APPEND zookeeper_sources src/mt_adaptor.c)\nelse()\n  list(APPEND zookeeper_sources src/st_adaptor.c)\nendif()\n\nif(WIN32)\n  list(APPEND zookeeper_sources src/winport.c)\nendif()\n\nadd_library(zookeeper STATIC ${zookeeper_sources})\ntarget_link_libraries(zookeeper PUBLIC\n  hashtable\n  $<$<PLATFORM_ID:Linux>:rt> # clock_gettime\n  $<$<PLATFORM_ID:Windows>:ws2_32>) # Winsock 2.0\n\nif(WANT_SYNCAPI AND NOT WIN32)\n  find_package(Threads REQUIRED)\n  target_link_libraries(zookeeper PUBLIC Threads::Threads)\nendif()\n\n# cli executable\nadd_executable(cli src/cli.c)\ntarget_link_libraries(cli zookeeper)\n\n# load_gen executable\nif(WANT_SYNCAPI AND NOT WIN32)\n  add_executable(load_gen src/load_gen.c)\n  target_link_libraries(load_gen zookeeper)\nendif()\n\n# tests\nset(test_sources\n  tests/TestDriver.cc\n  tests/LibCMocks.cc\n  tests/LibCSymTable.cc\n  tests/MocksBase.cc\n  tests/ZKMocks.cc\n  tests/Util.cc\n  tests/ThreadingUtil.cc\n  tests/TestZookeeperInit.cc\n  tests/TestZookeeperClose.cc\n  tests/TestClientRetry.cc\n  tests/TestOperations.cc\n  tests/TestMulti.cc\n  tests/TestWatchers.cc\n  tests/TestClient.cc)\n\nif(WANT_SYNCAPI)\n  list(APPEND test_sources tests/PthreadMocks.cc)\nendif()\n\nif(WANT_CPPUNIT)\n  add_executable(zktest ${test_sources})\n  target_compile_definitions(zktest\n    PRIVATE -DZKSERVER_CMD=\"${CMAKE_SOURCE_DIR}/tests/zkServer.sh\")\n  # TODO: Use `find_library()` for `cppunit`.\n  target_link_libraries(zktest zookeeper cppunit dl)\n\n  # This reads the link flags from the file `tests/wrappers.opt` into\n  # the variable `symbol_wrappers` for use in `target_link_libraries`.\n  # It is a holdover from the original build system.\n  file(STRINGS tests/wrappers.opt symbol_wrappers)\n  if(WANT_SYNCAPI)\n    file(STRINGS tests/wrappers-mt.opt symbol_wrappers_mt)\n  endif()\n\n  target_link_libraries(zktest ${symbol_wrappers} ${symbol_wrappers_mt})\n\n  enable_testing()\n  add_test(NAME zktest_runner COMMAND zktest)\n  set_property(TEST zktest_runner PROPERTY ENVIRONMENT\n    \"ZKROOT=${CMAKE_SOURCE_DIR}/../..\"\n    \"CLASSPATH=$CLASSPATH:$CLOVER_HOME/lib/clover.jar\")\nendif()\n"
  },
  {
    "path": "src/c/ChangeLog",
    "content": "Release 2.1.1\n2008-04-30 Andrew Kornev <akornev@users.sourceforge.net>\n\n    * changed the distributino package name to \"c-client-src\"\n    \nRelease 2.1.0\n2008-04-30 Andrew Kornev <akornev@users.sourceforge.net>\n\n    * added the client latency diagnostics; the client prints a warning when the\n      reponse latency exceeds 20ms\n\n    * modified logging format to report the znode path for which the zookeeper \n      operation is called\n\n    * fixed a minor bug where error messages were missing for some of the newer \n      zookeeper error codes (ZCLOSING and ZNOTHING).\n\n    * improved logging by adding the XID to the message to make it easy to match\n      requests to responses\n\n    * fixed the bug causing sporadic session termination and timeouts\n\n    * added a new return code to zookeeper_process() -- ZNOTHING -- \n      that indicates that the socket has no more data to read\n\n    * more unit tests added    \n\nRelease 1.1.3\n2008-02-07 Andrew Kornev <akornev@users.sourceforge.net>\n\n    * get_xid() is not thread-safe (xid initialization race condition \n      in the multi-threaded mode).\n    \n    * the I/O thread doesnt automatically terminate on AUTH_FAILURE and \n      SESSION_EXPIRED events.\n      \n    * all session events should be processed on the completion thread. \n    \n    * PING operation doesnt atomically enqueue the completion and \n      send buffers like other operations do.\n      \n    * corrected zookeeper_init() doxygen docs.\n    \n    * new unit tests added.\n      \n\nRelease 1.1.2\n2008-01-24 Andrew Kornev <akornev@users.sourceforge.net>\n\n    * fixed a race condition caused by the code in zookeeper_process()\n      and free_completions() setting sc->complete to 1 without proper\n      synchronization;\n\n    * fixed zoo_get() not updating buffer_len value with the actual\n      buffer length on return; added missing enter_critical/leave_critical\n      calls to the async ZK operations.\n\n    * Replaced select() with poll() to fix the problem with the FD_SET\n      macro causing stack corruption for FDs higher than 1024\n\n    * Added zoo_set_log_stream() to the public API. The function allows\n      applications to specify a different log file.\n\n    * Removed unused declarations from zookeeper.h (ACL related)\n\n    * changed zoo_get() signature to take a pointer to buffer length.\n      The function sets the parameter to the actual data length upon return.\n\n    * the watcher callback now takes the zhandle as its first parameter. This\n      is to avoid a race condition in the multi-threaded client when a watcher\n      is called before zookeeper_init() has returned.\n\n    * fixed zookeeper_close() resource leaks and race conditions,\n      fixed the race condition causing xid mismatch.\n\n    * added support for cppunit, added new targets: \"check\" and \"run-check\"\n      to build and run unit tests.\n\n    * Changed the signature of zookeeper_init(): it now takes a context pointer\n      as a parameter. This is to avoid a race condition in the multi-threaded client.\n\n    * Using a self-pipe rather than SIGUSR1 to wake up select() in the I/O thread\n\n    * Added the doxygen target to the autoconf scripts\n\n    * Pulled out the logging functionality from zookeeper.c to zk_log.c/.h.\n      Fixed a minor issue with PING responses being unnecessarily put on\n      the completion queue rather than simply dropped. Make use of DLL_EXPORT\n      symbol for building shared lib on cygwin.\n\n    * Implemented new Zookeeper operation sync() to flush the leader channel\n      to ensure that all updates have reached the followers.\n\n    * Synchronous methods not being handled properly on disconnect\n\n    * breed: fixed an incorrect parameter passed to zookeeper API by\n      the Sync API wrapper functions\n\n    * breed: the set and delete commands now support both Sync and Async API.\n      Prefix the command name with an 'a' to call the Async API: aset, adelete\n\n    * Make sure mutexes and condition variables are properly initialized\n      and destroyed\n\n    * Fixed zookeeper_close() causing core dumps with mt_adaptor\n\n\nRelease 1.0.0\n2007-11-27 Andrew Kornev <akornev@users.sourceforge.net>\n\n    * configure.ac and Makefile.am added support for GNU autotools\n\n    * recordio.c/.h updated jute IO routines to use bit-explicit integer types\n      (int32_t vs. int, and int64_t vs. long long)\n\n    * README rough draft"
  },
  {
    "path": "src/c/INSTALL",
    "content": "Installation Instructions\n*************************\n\nCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,\n2006 Free Software Foundation, Inc.\n\nThis file is free documentation; the Free Software Foundation gives\nunlimited permission to copy, distribute and modify it.\n\nBasic Installation\n==================\n\nBriefly, the shell commands `./configure; make; make install' should\nconfigure, build, and install this package.  The following\nmore-detailed instructions are generic; see the `README' file for\ninstructions specific to this package.\n\n   The `configure' shell script attempts to guess correct values for\nvarious system-dependent variables used during compilation.  It uses\nthose values to create a `Makefile' in each directory of the package.\nIt may also create one or more `.h' files containing system-dependent\ndefinitions.  Finally, it creates a shell script `config.status' that\nyou can run in the future to recreate the current configuration, and a\nfile `config.log' containing compiler output (useful mainly for\ndebugging `configure').\n\n   It can also use an optional file (typically called `config.cache'\nand enabled with `--cache-file=config.cache' or simply `-C') that saves\nthe results of its tests to speed up reconfiguring.  Caching is\ndisabled by default to prevent problems with accidental use of stale\ncache files.\n\n   If you need to do unusual things to compile the package, please try\nto figure out how `configure' could check whether to do them, and mail\ndiffs or instructions to the address given in the `README' so they can\nbe considered for the next release.  If you are using the cache, and at\nsome point `config.cache' contains results you don't want to keep, you\nmay remove or edit it.\n\n   The file `configure.ac' (or `configure.in') is used to create\n`configure' by a program called `autoconf'.  You need `configure.ac' if\nyou want to change it or regenerate `configure' using a newer version\nof `autoconf'.\n\nThe simplest way to compile this package is:\n\n  1. `cd' to the directory containing the package's source code and type\n     `./configure' to configure the package for your system.\n\n     Running `configure' might take a while.  While running, it prints\n     some messages telling which features it is checking for.\n\n  2. Type `make' to compile the package.\n\n  3. Optionally, type `make check' to run any self-tests that come with\n     the package.\n\n  4. Type `make install' to install the programs and any data files and\n     documentation.\n\n  5. You can remove the program binaries and object files from the\n     source code directory by typing `make clean'.  To also remove the\n     files that `configure' created (so you can compile the package for\n     a different kind of computer), type `make distclean'.  There is\n     also a `make maintainer-clean' target, but that is intended mainly\n     for the package's developers.  If you use it, you may have to get\n     all sorts of other programs in order to regenerate files that came\n     with the distribution.\n\nCompilers and Options\n=====================\n\nSome systems require unusual options for compilation or linking that the\n`configure' script does not know about.  Run `./configure --help' for\ndetails on some of the pertinent environment variables.\n\n   You can give `configure' initial values for configuration parameters\nby setting variables in the command line or in the environment.  Here\nis an example:\n\n     ./configure CC=c99 CFLAGS=-g LIBS=-lposix\n\n   *Note Defining Variables::, for more details.\n\nCompiling For Multiple Architectures\n====================================\n\nYou can compile the package for more than one kind of computer at the\nsame time, by placing the object files for each architecture in their\nown directory.  To do this, you can use GNU `make'.  `cd' to the\ndirectory where you want the object files and executables to go and run\nthe `configure' script.  `configure' automatically checks for the\nsource code in the directory that `configure' is in and in `..'.\n\n   With a non-GNU `make', it is safer to compile the package for one\narchitecture at a time in the source code directory.  After you have\ninstalled the package for one architecture, use `make distclean' before\nreconfiguring for another architecture.\n\nInstallation Names\n==================\n\nBy default, `make install' installs the package's commands under\n`/usr/local/bin', include files under `/usr/local/include', etc.  You\ncan specify an installation prefix other than `/usr/local' by giving\n`configure' the option `--prefix=PREFIX'.\n\n   You can specify separate installation prefixes for\narchitecture-specific files and architecture-independent files.  If you\npass the option `--exec-prefix=PREFIX' to `configure', the package uses\nPREFIX as the prefix for installing programs and libraries.\nDocumentation and other data files still use the regular prefix.\n\n   In addition, if you use an unusual directory layout you can give\noptions like `--bindir=DIR' to specify different values for particular\nkinds of files.  Run `configure --help' for a list of the directories\nyou can set and what kinds of files go in them.\n\n   If the package supports it, you can cause programs to be installed\nwith an extra prefix or suffix on their names by giving `configure' the\noption `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.\n\nOptional Features\n=================\n\nSome packages pay attention to `--enable-FEATURE' options to\n`configure', where FEATURE indicates an optional part of the package.\nThey may also pay attention to `--with-PACKAGE' options, where PACKAGE\nis something like `gnu-as' or `x' (for the X Window System).  The\n`README' should mention any `--enable-' and `--with-' options that the\npackage recognizes.\n\n   For packages that use the X Window System, `configure' can usually\nfind the X include and library files automatically, but if it doesn't,\nyou can use the `configure' options `--x-includes=DIR' and\n`--x-libraries=DIR' to specify their locations.\n\nSpecifying the System Type\n==========================\n\nThere may be some features `configure' cannot figure out automatically,\nbut needs to determine by the type of machine the package will run on.\nUsually, assuming the package is built to be run on the _same_\narchitectures, `configure' can figure that out, but if it prints a\nmessage saying it cannot guess the machine type, give it the\n`--build=TYPE' option.  TYPE can either be a short name for the system\ntype, such as `sun4', or a canonical name which has the form:\n\n     CPU-COMPANY-SYSTEM\n\nwhere SYSTEM can have one of these forms:\n\n     OS KERNEL-OS\n\n   See the file `config.sub' for the possible values of each field.  If\n`config.sub' isn't included in this package, then this package doesn't\nneed to know the machine type.\n\n   If you are _building_ compiler tools for cross-compiling, you should\nuse the option `--target=TYPE' to select the type of system they will\nproduce code for.\n\n   If you want to _use_ a cross compiler, that generates code for a\nplatform different from the build platform, you should specify the\n\"host\" platform (i.e., that on which the generated programs will\neventually be run) with `--host=TYPE'.\n\nSharing Defaults\n================\n\nIf you want to set default values for `configure' scripts to share, you\ncan create a site shell script called `config.site' that gives default\nvalues for variables like `CC', `cache_file', and `prefix'.\n`configure' looks for `PREFIX/share/config.site' if it exists, then\n`PREFIX/etc/config.site' if it exists.  Or, you can set the\n`CONFIG_SITE' environment variable to the location of the site script.\nA warning: not all `configure' scripts look for a site script.\n\nDefining Variables\n==================\n\nVariables not defined in a site shell script can be set in the\nenvironment passed to `configure'.  However, some packages may run\nconfigure again during the build, and the customized values of these\nvariables may be lost.  In order to avoid this problem, you should set\nthem in the `configure' command line, using `VAR=value'.  For example:\n\n     ./configure CC=/usr/local2/bin/gcc\n\ncauses the specified `gcc' to be used as the C compiler (unless it is\noverridden in the site shell script).\n\nUnfortunately, this technique does not work for `CONFIG_SHELL' due to\nan Autoconf bug.  Until the bug is fixed you can use this workaround:\n\n     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash\n\n`configure' Invocation\n======================\n\n`configure' recognizes the following options to control how it operates.\n\n`--help'\n`-h'\n     Print a summary of the options to `configure', and exit.\n\n`--version'\n`-V'\n     Print the version of Autoconf used to generate the `configure'\n     script, and exit.\n\n`--cache-file=FILE'\n     Enable the cache: use and save the results of the tests in FILE,\n     traditionally `config.cache'.  FILE defaults to `/dev/null' to\n     disable caching.\n\n`--config-cache'\n`-C'\n     Alias for `--cache-file=config.cache'.\n\n`--quiet'\n`--silent'\n`-q'\n     Do not print messages saying which checks are being made.  To\n     suppress all normal output, redirect it to `/dev/null' (any error\n     messages will still be shown).\n\n`--srcdir=DIR'\n     Look for the package's source code in directory DIR.  Usually\n     `configure' can determine that directory automatically.\n\n`configure' also accepts some other, not widely useful, options.  Run\n`configure --help' for more details.\n\n"
  },
  {
    "path": "src/c/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/c/Makefile.am",
    "content": "# need this for Doxygen integration\ninclude $(top_srcdir)/aminclude.am\n\nif SOLARIS\n  SOLARIS_CPPFLAGS = -D_POSIX_PTHREAD_SEMANTICS\n  SOLARIS_LIB_LDFLAGS = -lnsl -lsocket\nendif\nAM_CPPFLAGS = -I${srcdir}/include -I${srcdir}/tests -I${srcdir}/generated $(SOLARIS_CPPFLAGS)\nAM_CFLAGS = -Wall -Werror \nAM_CXXFLAGS = -Wall $(USEIPV6)\n\nLIB_LDFLAGS = -no-undefined -version-info 2 $(SOLARIS_LIB_LDFLAGS)\n\npkginclude_HEADERS = include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h include/proto.h include/recordio.h generated/zookeeper.jute.h\nEXTRA_DIST=LICENSE\n\nHASHTABLE_SRC = src/hashtable/hashtable_itr.h src/hashtable/hashtable_itr.c \\\n    src/hashtable/hashtable_private.h src/hashtable/hashtable.h src/hashtable/hashtable.c\n\nnoinst_LTLIBRARIES = libhashtable.la\nlibhashtable_la_SOURCES = $(HASHTABLE_SRC)\n\nCOMMON_SRC = src/zookeeper.c include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h\\\n    src/recordio.c include/recordio.h include/proto.h \\\n    src/zk_adaptor.h generated/zookeeper.jute.c \\\n    src/zookeeper_log.h src/zk_log.c src/zk_hashtable.h src/zk_hashtable.c\n\n# These are the symbols (classes, mostly) we want to export from our library.\nEXPORT_SYMBOLS = '(zoo_|zookeeper_|zhandle|Z|format_log_message|log_message|logLevel|deallocate_|allocate_|zerror|is_unrecoverable)'\nnoinst_LTLIBRARIES += libzkst.la\nlibzkst_la_SOURCES =$(COMMON_SRC) src/st_adaptor.c\nlibzkst_la_LIBADD = -lm\n\nlib_LTLIBRARIES = libzookeeper_st.la\nlibzookeeper_st_la_SOURCES =\nlibzookeeper_st_la_LIBADD=libzkst.la libhashtable.la\nlibzookeeper_st_la_DEPENDENCIES=libzkst.la libhashtable.la\nlibzookeeper_st_la_LDFLAGS = $(LIB_LDFLAGS) -export-symbols-regex $(EXPORT_SYMBOLS)\n\nif WANT_SYNCAPI\nnoinst_LTLIBRARIES += libzkmt.la\nlibzkmt_la_SOURCES =$(COMMON_SRC) src/mt_adaptor.c\nlibzkmt_la_CFLAGS = -DTHREADED\nlibzkmt_la_LIBADD = -lm\n\nlib_LTLIBRARIES += libzookeeper_mt.la\nlibzookeeper_mt_la_SOURCES =\nlibzookeeper_mt_la_LIBADD=libzkmt.la libhashtable.la -lpthread\nlibzookeeper_mt_la_DEPENDENCIES=libzkmt.la libhashtable.la\nlibzookeeper_mt_la_LDFLAGS = $(LIB_LDFLAGS) -export-symbols-regex $(EXPORT_SYMBOLS)\nendif\n\nbin_PROGRAMS = cli_st\n\ncli_st_SOURCES = src/cli.c\ncli_st_LDADD = libzookeeper_st.la\n\nif WANT_SYNCAPI\nbin_PROGRAMS += cli_mt load_gen\n\ncli_mt_SOURCES = src/cli.c\ncli_mt_LDADD = libzookeeper_mt.la\ncli_mt_CFLAGS = -DTHREADED\n\nload_gen_SOURCES = src/load_gen.c\nload_gen_LDADD = libzookeeper_mt.la\nload_gen_CFLAGS = -DTHREADED\n\nendif\n\n#########################################################################\n# build and run unit tests\n\nEXTRA_DIST+=$(wildcard ${srcdir}/tests/*.cc) $(wildcard ${srcdir}/tests/*.h) \\\n    ${srcdir}/tests/wrappers.opt ${srcdir}/tests/wrappers-mt.opt\n\nTEST_SOURCES = tests/TestDriver.cc tests/LibCMocks.cc tests/LibCSymTable.cc \\\n    tests/MocksBase.cc  tests/ZKMocks.cc tests/Util.cc tests/ThreadingUtil.cc \\\n    tests/TestClientRetry.cc \\\n    tests/TestOperations.cc tests/TestZookeeperInit.cc \\\n    tests/TestZookeeperClose.cc tests/TestClient.cc \\\n    tests/TestMulti.cc tests/TestWatchers.cc\n\n\nif SOLARIS\n  SHELL_SYMBOL_WRAPPERS = cat ${srcdir}/tests/wrappers.opt\n  SYMBOL_WRAPPERS=$(SHELL_SYMBOL_WRAPPERS:sh)\nelse\n  SYMBOL_WRAPPERS=$(shell cat ${srcdir}/tests/wrappers.opt)\nendif\n\ncheck_PROGRAMS = zktest-st\nnodist_zktest_st_SOURCES = $(TEST_SOURCES)\nzktest_st_LDADD = libzkst.la libhashtable.la $(CPPUNIT_LIBS)\nzktest_st_CXXFLAGS = -DUSE_STATIC_LIB $(CPPUNIT_CFLAGS) $(USEIPV6) $(SOLARIS_CPPFLAGS)\nzktest_st_LDFLAGS = -static-libtool-libs $(SYMBOL_WRAPPERS) $(SOLARIS_LIB_LDFLAGS)\n\nif WANT_SYNCAPI\n  check_PROGRAMS += zktest-mt\n  nodist_zktest_mt_SOURCES = $(TEST_SOURCES) tests/PthreadMocks.cc\n  zktest_mt_LDADD = libzkmt.la libhashtable.la -lpthread $(CPPUNIT_LIBS)\n  zktest_mt_CXXFLAGS = -DUSE_STATIC_LIB -DTHREADED $(CPPUNIT_CFLAGS) $(USEIPV6)\nif SOLARIS\n  SHELL_SYMBOL_WRAPPERS_MT = cat ${srcdir}/tests/wrappers-mt.opt\n  SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(SHELL_SYMBOL_WRAPPERS_MT:sh)\nelse\n  SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(shell cat ${srcdir}/tests/wrappers-mt.opt)\nendif\n  zktest_mt_LDFLAGS = -static-libtool-libs $(SYMBOL_WRAPPERS_MT) $(SOLARIS_LIB_LDFLAGS)\nendif\n\nrun-check: check\n\t./zktest-st $(TEST_OPTIONS)\nif WANT_SYNCAPI\n\t./zktest-mt $(TEST_OPTIONS)\nendif\n\nclean-local: clean-check\n\t$(RM) $(DX_CLEANFILES)\n\nclean-check:\n\t$(RM) $(nodist_zktest_st_OBJECTS) $(nodist_zktest_mt_OBJECTS)\n"
  },
  {
    "path": "src/c/NOTICE.txt",
    "content": "Apache ZooKeeper\nCopyright 2009-2018 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n\n----------\ninclude/winstdint.h is included only for Windows Client support, as follows:\n\n// ISO C9x  compliant stdint.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2008 Alexander Chemeris\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// \n//   1. Redistributions of source code must retain the above copyright notice,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. The name of the author may be used to endorse or promote products\n//      derived from this software without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n----------\n"
  },
  {
    "path": "src/c/README",
    "content": "                     Zookeeper C client library \n\n\nThis package provides a C client interface to Zookeeper server.\n\nFor the latest information about ZooKeeper, please visit our website at:\n   http://zookeeper.apache.org/\nand our wiki, at:\n   https://cwiki.apache.org/confluence/display/ZOOKEEPER\n\nFull documentation for this release can also be found in ../../docs/index.html\n\n\nOVERVIEW\n\nThe client supports two types of APIs -- synchronous and asynchronous.\n\nAsynchronous API provides non-blocking operations with completion callbacks and \nrelies on the application to implement event multiplexing on its behalf.\n\nOn the other hand, Synchronous API provides a blocking flavor of\nzookeeper operations and runs its own event loop in a separate thread.\n\nSync and Async APIs can be mixed and matched within the same application.\n\nThe package includes two shared libraries: zookeeper_st and\nzookeeper_mt. The former only provides the Async API and is not\nthread-safe. The only reason this library exists is to support the\nplatforms were pthread library is not available or unstable\n(i.e. FreeBSD 4.x). In all other cases the application developers are\nadvised to link against zookeeper_mt as it includes support for both\nSync and Async API.\n\n\nINSTALLATION\n\nIf you're building the client from a source checkout you need to\nfollow the steps outlined below. If you're building from a release\ntar downloaded from Apache please skip to step 2.\n\n1) do a \"ant compile_jute\" from the zookeeper top level directory (.../trunk).\n   This will create a directory named \"generated\" under src/c.  Skip to step 3.\n2) unzip/untar the source tarball and cd to the zookeeper-x.x.x/src/c directory\n3) change directory to src/c and do a \"autoreconf -if\" to bootstrap\n   autoconf, automake and libtool. Please make sure you have autoconf\n   version 2.59 or greater installed. If cppunit is installed in a non-standard\n   directory, you need to specify where to find cppunit.m4. For example, if\n   cppunit is installed under /usr/local, run:\n   \n       ACLOCAL=\"aclocal -I /usr/local/share/aclocal\" autoreconf -if\n\n4) do a \"./configure [OPTIONS]\" to generate the makefile. See INSTALL\n   for general information about running configure. Additionally, the\n   configure supports the following options:\n   --enable-debug     enables optimization and enables debug info compiler\n                      options, disabled by default\n   --without-syncapi  disables Sync API support; zookeeper_mt library won't\n                      be built, enabled by default\n   --disable-static   do not build static libraries, enabled by default\n   --disable-shared   do not build shared libraries, enabled by default\n   --without-cppunit  do not build the test library, enabled by default.\n\n5) do a \"make\" or \"make install\" to build the libraries and install them. \n   Alternatively, you can also build and run a unit test suite (and\n   you probably should).  Please make sure you have cppunit-1.10.x or\n   higher installed before you execute step 4.  Once ./configure has\n   finished, do a \"make run-check\". It will build the libraries, build\n   the tests and run them.\n6) to generate doxygen documentation do a \"make doxygen-doc\". All\n   documentations will be placed to a new subfolder named docs. By\n   default only HTML documentation is generated.  For information on\n   other document formats please use \"./configure --help\"\n\nAlternatively you can use the CMake build system. On Windows, this is required.\nFollow steps 1 and 2 above, and then continue here.\n\n1) do a \"cmake [OPTIONS]\" to generate the makefile or msbuild files (the correct\n   build system will be generated based on your platform). Some options from above\n   are supported:\n   -DCMAKE_BUILD_TYPE  Debug by default, Release enables optimzation etc.\n   -DWANT_SYNCAPI      ON by default, OFF disables the Sync API support\n   -DWANT_CPPUNIT      ON except on Windows, OFF disables the tests\n   -DBUILD_SHARED_LIBS not yet supported, only static libraries are built\n   other CMake options see \"cmake --help\" for generic options, such as generator\n\n2) do a \"cmake --build .\" to build the default targets. Alternatively you can\n   invoke \"make\" or \"msbuild\" manually. If the tests were enabled, use \"ctest -V\"\n   to run them.\n\nCurrent limitations of the CMake build system include lack of Solaris support,\nno shared library option, no explicitly exported symbols (all are exported by\ndefault), no versions on the libraries, and no documentation generation.\nFeatures of CMake include a single, easily consumed cross-platform build system\nto generate the ZooKeeper C Client libraries for any project, with little to no\nconfiguration.\n\nEXAMPLE/SAMPLE C CLIENT SHELL\n\nNOTE: the ZooKeeper C client shell (cli_st and cli_mt) is meant as a\nexample/sample of ZooKeeper C client API usage. It is not a full\nfledged client and not meant for production usage - see the Java\nclient shell for a fully featured shell.\n\nYou can test your client by running a zookeeper server (see\ninstructions on the project wiki page on how to run it) and connecting\nto it using the zookeeper shell application cli that is built as part\nof the installation procedure.\n\ncli_mt (multithreaded, built against zookeeper_mt library) is shown in\nthis example, but you could also use cli_st (singlethreaded, built\nagainst zookeeper_st library):\n\n$ cli_mt zookeeper_host:9876\n\nThis is a client application that gives you a shell for executing\nsimple zookeeper commands. Once successfully started and connected to\nthe server it displays a shell prompt.\n\nYou can now enter zookeeper commands. For example, to create a node:\n\n> create /my_new_node\n\nTo verify that the node's been created:\n\n> ls /\n\nYou should see a list of nodes who are the children of the root node \"/\".\n\nHere's a list of command supported by the cli shell:\n\nls <path>             -- list children of a znode identified by <path>. The\n                         command set a children watch on the znode.\nget <path>            -- get the value of a znode at <path>\nset <path> <value>    -- set the value of a znode at <path> to <value>\ncreate [+e|+s] <path> -- create a znode as a child of znode <path>; \n                         use +e option to create an ephemeral znode,\n                         use +s option to create a znode with a sequence number \n                         appended to the name. The operation will fail if \n                         the parent znode (the one identified by <path>) doesn't\n                         exist.\ndelete <path>         -- delete the znode at <path>. The command will fail if the znode\n                         has children.\nsync <path>           -- make sure all pending updates have been applied to znode at <path>\nexists <path>         -- returns a result code indicating whether the znode at <path>\n                         exists. The command also sets a znode watch.\nmyid                  -- prints out the current zookeeper session id.\nquit                  -- exit the shell.\n\nIn order to be able to use the zookeeper API in your application you have to\n1) remember to include the zookeeper header \n   #include <zookeeper/zookeeper.h>\n2) use -DTHREADED compiler option to enable Sync API; in this case you should\n   be linking your code against zookeeper_mt library\n\nPlease take a look at cli.c to understand how to use the two API types. \n(TODO: some kind of short tutorial would be helpful, I guess)\n"
  },
  {
    "path": "src/c/acinclude.m4",
    "content": "# This file is part of Autoconf.                       -*- Autoconf -*-\n\n# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Autoconf macro files.\n\n# Generate automatic documentation using Doxygen. Works in concert with the\n# aminclude.m4 file and a compatible doxygen configuration file. Defines the\n# following public macros:\n#\n# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.\n# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,\n# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'\n# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',\n# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment\n# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'\n# paper size.\n#\n# By default, HTML, PDF and PS documentation is generated as this seems to be\n# the most popular and portable combination. MAN pages created by Doxygen are\n# usually problematic, though by picking an appropriate subset and doing some\n# massaging they might be better than nothing. CHM and RTF are specific for MS\n# (note that you can't generate both HTML and CHM at the same time). The XML is\n# rather useless unless you apply specialized post-processing to it.\n#\n# The macro mainly controls the default state of the feature. The use can\n# override the default by specifying --enable or --disable. The macros ensure\n# that contradictory flags are not given (e.g., --enable-doxygen-html and\n# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)\n# Finally, each feature will be automatically disabled (with a warning) if the\n# required programs are missing.\n#\n# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with\n# the following parameters: a one-word name for the project for use as a\n# filename base etc., an optional configuration file name (the default is\n# 'Doxyfile', the same as Doxygen's default), and an optional output directory\n# name (the default is 'doxygen-doc').\n\n## ----------##\n## Defaults. ##\n## ----------##\n\nDX_ENV=\"\"\nAC_DEFUN([DX_FEATURE_doc],  ON)\nAC_DEFUN([DX_FEATURE_dot],  ON)\nAC_DEFUN([DX_FEATURE_man],  OFF)\nAC_DEFUN([DX_FEATURE_html], ON)\nAC_DEFUN([DX_FEATURE_chm],  OFF)\nAC_DEFUN([DX_FEATURE_chi],  OFF)\nAC_DEFUN([DX_FEATURE_rtf],  OFF)\nAC_DEFUN([DX_FEATURE_xml],  OFF)\nAC_DEFUN([DX_FEATURE_pdf],  ON)\nAC_DEFUN([DX_FEATURE_ps],   ON)\n\n## --------------- ##\n## Private macros. ##\n## --------------- ##\n\n# DX_ENV_APPEND(VARIABLE, VALUE)\n# ------------------------------\n# Append VARIABLE=\"VALUE\" to DX_ENV for invoking doxygen.\nAC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], [\"$DX_ENV $1='$2'\"])])\n\n# DX_DIRNAME_EXPR\n# ---------------\n# Expand into a shell expression prints the directory part of a path.\nAC_DEFUN([DX_DIRNAME_EXPR],\n         [[expr \".$1\" : '\\(\\.\\)[^/]*$' \\| \"x$1\" : 'x\\(.*\\)/[^/]*$']])\n\n# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)\n# -------------------------------------\n# Expands according to the M4 (static) status of the feature.\nAC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])\n\n# DX_REQUIRE_PROG(VARIABLE, PROGRAM)\n# ----------------------------------\n# Require the specified program to be found for the DX_CURRENT_FEATURE to work.\nAC_DEFUN([DX_REQUIRE_PROG], [\nAC_PATH_TOOL([$1], [$2])\nif test \"$DX_FLAG_$[DX_CURRENT_FEATURE$$1]\" = 1; then\n    AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])\n    AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\nfi\n])\n\n# DX_TEST_FEATURE(FEATURE)\n# ------------------------\n# Expand to a shell expression testing whether the feature is active.\nAC_DEFUN([DX_TEST_FEATURE], [test \"$DX_FLAG_$1\" = 1])\n\n# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)\n# -------------------------------------------------\n# Verify that a required features has the right state before trying to turn on\n# the DX_CURRENT_FEATURE.\nAC_DEFUN([DX_CHECK_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" \\\n|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,\n                            requires, contradicts) doxygen-DX_CURRENT_FEATURE])\n])\n\n# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)\n# ----------------------------------------------------------\n# Turn off the DX_CURRENT_FEATURE if the required feature is off.\nAC_DEFUN([DX_CLEAR_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" || AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\n])\n\n# DX_FEATURE_ARG(FEATURE, DESCRIPTION,\n#                CHECK_DEPEND, CLEAR_DEPEND,\n#                REQUIRE, DO-IF-ON, DO-IF-OFF)\n# --------------------------------------------\n# Parse the command-line option controlling a feature. CHECK_DEPEND is called\n# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),\n# otherwise CLEAR_DEPEND is called to turn off the default state if a required\n# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional\n# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and\n# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.\nAC_DEFUN([DX_ARG_ABLE], [\n    AC_DEFUN([DX_CURRENT_FEATURE], [$1])\n    AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])\n    AC_ARG_ENABLE(doxygen-$1,\n                  [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],\n                                                      [--enable-doxygen-$1]),\n                                  DX_IF_FEATURE([$1], [don't $2], [$2]))],\n                  [\ncase \"$enableval\" in\n#(\ny|Y|yes|Yes|YES)\n    AC_SUBST([DX_FLAG_$1], 1)\n    $3\n;; #(\nn|N|no|No|NO)\n    AC_SUBST([DX_FLAG_$1], 0)\n;; #(\n*)\n    AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])\n;;\nesac\n], [\nAC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])\n$4\n])\nif DX_TEST_FEATURE([$1]); then\n    $5\n    :\nfi\nif DX_TEST_FEATURE([$1]); then\n    AM_CONDITIONAL(DX_COND_$1, :)\n    $6\n    :\nelse\n    AM_CONDITIONAL(DX_COND_$1, false)\n    $7\n    :\nfi\n])\n\n## -------------- ##\n## Public macros. ##\n## -------------- ##\n\n# DX_XXX_FEATURE(DEFAULT_STATE)\n# -----------------------------\nAC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc],  [$1])])\nAC_DEFUN([DX_MAN_FEATURE],     [AC_DEFUN([DX_FEATURE_man],  [$1])])\nAC_DEFUN([DX_HTML_FEATURE],    [AC_DEFUN([DX_FEATURE_html], [$1])])\nAC_DEFUN([DX_CHM_FEATURE],     [AC_DEFUN([DX_FEATURE_chm],  [$1])])\nAC_DEFUN([DX_CHI_FEATURE],     [AC_DEFUN([DX_FEATURE_chi],  [$1])])\nAC_DEFUN([DX_RTF_FEATURE],     [AC_DEFUN([DX_FEATURE_rtf],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])\nAC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])\n\n# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])\n# ---------------------------------------------------------\n# PROJECT also serves as the base name for the documentation files.\n# The default CONFIG-FILE is \"Doxyfile\" and OUTPUT-DOC-DIR is \"doxygen-doc\".\nAC_DEFUN([DX_INIT_DOXYGEN], [\n\n# Files:\nAC_SUBST([DX_PROJECT], [$1])\nAC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])\nAC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])\n\n# Environment variables used inside doxygen.cfg:\nDX_ENV_APPEND(SRCDIR, $srcdir)\nDX_ENV_APPEND(PROJECT, $DX_PROJECT)\nDX_ENV_APPEND(DOCDIR, $DX_DOCDIR)\nDX_ENV_APPEND(VERSION, $PACKAGE_VERSION)\n\n# Doxygen itself:\nDX_ARG_ABLE(doc, [generate any doxygen documentation],\n            [],\n            [],\n            [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)\n             DX_REQUIRE_PROG([DX_PERL], perl)],\n            [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])\n\n# Dot for graphics:\nDX_ARG_ABLE(dot, [generate graphics for doxygen documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_DOT], dot)],\n            [DX_ENV_APPEND(HAVE_DOT, YES)\n             DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],\n            [DX_ENV_APPEND(HAVE_DOT, NO)])\n\n# Man pages generation:\nDX_ARG_ABLE(man, [generate doxygen manual pages],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_MAN, YES)],\n            [DX_ENV_APPEND(GENERATE_MAN, NO)])\n\n# RTF file generation:\nDX_ARG_ABLE(rtf, [generate doxygen RTF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_RTF, YES)],\n            [DX_ENV_APPEND(GENERATE_RTF, NO)])\n\n# XML file generation:\nDX_ARG_ABLE(xml, [generate doxygen XML documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_XML, YES)],\n            [DX_ENV_APPEND(GENERATE_XML, NO)])\n\n# (Compressed) HTML help generation:\nDX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_HHC], hhc)],\n            [DX_ENV_APPEND(HHC_PATH, $DX_HHC)\n             DX_ENV_APPEND(GENERATE_HTML, YES)\n             DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],\n            [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])\n\n# Seperate CHI file generation.\nDX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],\n            [DX_CHECK_DEPEND(chm, 1)],\n            [DX_CLEAR_DEPEND(chm, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_CHI, YES)],\n            [DX_ENV_APPEND(GENERATE_CHI, NO)])\n\n# Plain HTML pages generation:\nDX_ARG_ABLE(html, [generate doxygen plain HTML documentation],\n            [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],\n            [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],\n            [],\n            [DX_ENV_APPEND(GENERATE_HTML, YES)],\n            [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])\n\n# PostScript file generation:\nDX_ARG_ABLE(ps, [generate doxygen PostScript documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_LATEX], latex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_DVIPS], dvips)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# PDF file generation:\nDX_ARG_ABLE(pdf, [generate doxygen PDF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# LaTeX generation for PS and/or PDF:\nif DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then\n    AM_CONDITIONAL(DX_COND_latex, :)\n    DX_ENV_APPEND(GENERATE_LATEX, YES)\nelse\n    AM_CONDITIONAL(DX_COND_latex, false)\n    DX_ENV_APPEND(GENERATE_LATEX, NO)\nfi\n\n# Paper size for PS and/or PDF:\nAC_ARG_VAR(DOXYGEN_PAPER_SIZE,\n           [a4wide (default), a4, letter, legal or executive])\ncase \"$DOXYGEN_PAPER_SIZE\" in\n#(\n\"\")\n    AC_SUBST(DOXYGEN_PAPER_SIZE, \"\")\n;; #(\na4wide|a4|letter|legal|executive)\n    DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)\n;; #(\n*)\n    AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])\n;;\nesac\n\n#For debugging:\n#echo DX_FLAG_doc=$DX_FLAG_doc\n#echo DX_FLAG_dot=$DX_FLAG_dot\n#echo DX_FLAG_man=$DX_FLAG_man\n#echo DX_FLAG_html=$DX_FLAG_html\n#echo DX_FLAG_chm=$DX_FLAG_chm\n#echo DX_FLAG_chi=$DX_FLAG_chi\n#echo DX_FLAG_rtf=$DX_FLAG_rtf\n#echo DX_FLAG_xml=$DX_FLAG_xml\n#echo DX_FLAG_pdf=$DX_FLAG_pdf\n#echo DX_FLAG_ps=$DX_FLAG_ps\n#echo DX_ENV=$DX_ENV\n])\n"
  },
  {
    "path": "src/c/aminclude.am",
    "content": "# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Automake macro files.\n\n# Generate automatic documentation using Doxygen. Goals and variables values\n# are controlled by the various DX_COND_??? conditionals set by autoconf.\n#\n# The provided goals are:\n# doxygen-doc: Generate all doxygen documentation.\n# doxygen-run: Run doxygen, which will generate some of the documentation\n#              (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post\n#              processing required for the rest of it (PS, PDF, and some MAN).\n# doxygen-man: Rename some doxygen generated man pages.\n# doxygen-ps: Generate doxygen PostScript documentation.\n# doxygen-pdf: Generate doxygen PDF documentation.\n#\n# Note that by default these are not integrated into the automake goals. If\n# doxygen is used to generate man pages, you can achieve this integration by\n# setting man3_MANS to the list of man pages generated and then adding the\n# dependency:\n#\n#   $(man3_MANS): doxygen-doc\n#\n# This will cause make to run doxygen and generate all the documentation.\n#\n# The following variable is intended for use in Makefile.am:\n#\n# DX_CLEANFILES = everything to clean.\n#\n# This is usually added to MOSTLYCLEANFILES.\n\n## --------------------------------- ##\n## Format-independent Doxygen rules. ##\n## --------------------------------- ##\n\nif DX_COND_doc\n\n## ------------------------------- ##\n## Rules specific for HTML output. ##\n## ------------------------------- ##\n\nif DX_COND_html\n\nDX_CLEAN_HTML = @DX_DOCDIR@/html\n\nendif DX_COND_html\n\n## ------------------------------ ##\n## Rules specific for CHM output. ##\n## ------------------------------ ##\n\nif DX_COND_chm\n\nDX_CLEAN_CHM = @DX_DOCDIR@/chm\n\nif DX_COND_chi\n\nDX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi\n\nendif DX_COND_chi\n\nendif DX_COND_chm\n\n## ------------------------------ ##\n## Rules specific for MAN output. ##\n## ------------------------------ ##\n\nif DX_COND_man\n\nDX_CLEAN_MAN = @DX_DOCDIR@/man\n\nendif DX_COND_man\n\n## ------------------------------ ##\n## Rules specific for RTF output. ##\n## ------------------------------ ##\n\nif DX_COND_rtf\n\nDX_CLEAN_RTF = @DX_DOCDIR@/rtf\n\nendif DX_COND_rtf\n\n## ------------------------------ ##\n## Rules specific for XML output. ##\n## ------------------------------ ##\n\nif DX_COND_xml\n\nDX_CLEAN_XML = @DX_DOCDIR@/xml\n\nendif DX_COND_xml\n\n## ----------------------------- ##\n## Rules specific for PS output. ##\n## ----------------------------- ##\n\nif DX_COND_ps\n\nDX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps\n\nDX_PS_GOAL = doxygen-ps\n\ndoxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps\n\n@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_LATEX) refman.tex; \\\n\t$(MAKEINDEX_PATH) refman.idx; \\\n\t$(DX_LATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_LATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\t$(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi\n\nendif DX_COND_ps\n\n## ------------------------------ ##\n## Rules specific for PDF output. ##\n## ------------------------------ ##\n\nif DX_COND_pdf\n\nDX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf\n\nDX_PDF_GOAL = doxygen-pdf\n\ndoxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf\n\n@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\t$(DX_MAKEINDEX) refman.idx; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_PDFLATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\tmv refman.pdf ../@PACKAGE@.pdf\n\nendif DX_COND_pdf\n\n## ------------------------------------------------- ##\n## Rules specific for LaTeX (shared for PS and PDF). ##\n## ------------------------------------------------- ##\n\nif DX_COND_latex\n\nDX_CLEAN_LATEX = @DX_DOCDIR@/latex\n\nendif DX_COND_latex\n\n.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\ndoxygen-run: @DX_DOCDIR@/@PACKAGE@.tag\n\ndoxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)\n\trm -rf @DX_DOCDIR@\n\t$(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)\n\nDX_CLEANFILES = \\\n    @DX_DOCDIR@/@PACKAGE@.tag \\\n    -r \\\n    $(DX_CLEAN_HTML) \\\n    $(DX_CLEAN_CHM) \\\n    $(DX_CLEAN_CHI) \\\n    $(DX_CLEAN_MAN) \\\n    $(DX_CLEAN_RTF) \\\n    $(DX_CLEAN_XML) \\\n    $(DX_CLEAN_PS) \\\n    $(DX_CLEAN_PDF) \\\n    $(DX_CLEAN_LATEX)\n\nendif DX_COND_doc\n"
  },
  {
    "path": "src/c/c-doc.Doxyfile",
    "content": "# Doxyfile 1.4.7\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project\n#\n# All text after a hash (#) is considered a comment and will be ignored\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \")\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \n# by quotes) that should identify the project.\n\nPROJECT_NAME = $(PROJECT)-$(VERSION)\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. \n# This could be handy for archiving the generated documentation or \n# if some version control system is used.\n\nPROJECT_NUMBER = \n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \n# base path where the generated documentation will be put. \n# If a relative path is entered, it will be relative to the location \n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY = $(DOCDIR)\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \n# 4096 sub-directories (in 2 levels) under the output directory of each output \n# format and will distribute the generated files over these directories. \n# Enabling this option can be useful when feeding doxygen a huge amount of \n# source files, where putting all generated files in the same directory would \n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all \n# documentation generated by doxygen is written. Doxygen will use this \n# information to generate all constant output in the proper language. \n# The default language is English, other supported languages are: \n# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \n# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \n# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \n# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \n# Swedish, and Ukrainian.\n\nOUTPUT_LANGUAGE = English\n\n# This tag can be used to specify the encoding used in the generated output. \n# The encoding is not always determined by the language that is chosen, \n# but also whether or not the output is meant for Windows or non-Windows users. \n# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \n# forces the Windows encoding (this is the default for the Windows binary), \n# whereas setting the tag to NO uses a Unix-style encoding (the default for \n# all platforms other than Windows).\n\nUSE_WINDOWS_ENCODING = NO\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n# include brief member descriptions after the members that are listed in \n# the file and class documentation (similar to JavaDoc). \n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n# the brief description of a member or function before the detailed description. \n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator \n# that is used to form the text in various listings. Each string \n# in this list, if found as the leading text of the brief description, will be \n# stripped from the text and the result after processing the whole list, is \n# used as the annotated text. Otherwise, the brief description is used as-is. \n# If left blank, the following values are used (\"$name\" is automatically \n# replaced with the name of the entity): \"The $name class\" \"The $name widget\" \n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\" \n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF = \n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n# Doxygen will generate a detailed section even if there is only a brief \n# description.\n\nALWAYS_DETAILED_SEC = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all \n# inherited members of a class in the documentation of that class as if those \n# members were ordinary class members. Constructors, destructors and assignment \n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n# path before files name in the file list and in the header files. If set \n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES = YES\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n# can be used to strip a user-defined part of the path. Stripping is \n# only done if one of the specified strings matches the left-hand part of \n# the path. The tag can be used to show relative paths in the file list. \n# If left blank the directory from which doxygen is run is used as the \n# path to strip.\n\nSTRIP_FROM_PATH = \n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \n# the path mentioned in the documentation of a class, which tells \n# the reader which header file to include in order to use a class. \n# If left blank only the name of the header file containing the class \n# definition is used. Otherwise one should specify the include paths that \n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH = \n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n# (but less readable) file names. This can be useful is your file systems \n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n# will interpret the first line (until the first dot) of a JavaDoc-style \n# comment as the brief description. If set to NO, the JavaDoc \n# comments will behave just like the Qt-style comments (thus requiring an \n# explicit @brief command for a brief description.\n\nJAVADOC_AUTOBRIEF = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n# treat a multi-line C++ special comment block (i.e. a block of //! or /// \n# comments) as a brief description. This used to be the default behaviour. \n# The new default is to treat a multi-line C++ comment block as a detailed \n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the DETAILS_AT_TOP tag is set to YES then Doxygen \n# will output the detailed description near the top, like JavaDoc.\n# If set to NO, the detailed description appears after the member \n# documentation.\n\nDETAILS_AT_TOP = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n# member inherits the documentation from any documented member that it \n# re-implements.\n\nINHERIT_DOCS = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce \n# a new page for each member. If set to NO, the documentation of a member will \n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. \n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE = 8\n\n# This tag can be used to specify a number of aliases that acts \n# as commands in the documentation. An alias has the form \"name=value\". \n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n# put the command \\sideeffect (or @sideeffect) in the documentation, which \n# will result in a user-defined paragraph with heading \"Side Effects:\". \n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES = \n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C \n# sources only. Doxygen will then generate output that is more tailored for C. \n# For instance, some of the names that are used will be different. The list \n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java \n# sources only. Doxygen will then generate output that is more tailored for Java. \n# For instance, namespaces will be presented as packages, qualified scopes \n# will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA = NO\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to \n# include (a tag file for) the STL sources as input, then you should \n# set this tag to YES in order to let doxygen match functions declarations and \n# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. \n# func(std::string) {}). This also make the inheritance and collaboration \n# diagrams that involve STL classes more complete and accurate.\n\nBUILTIN_STL_SUPPORT = NO\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n# tag is set to YES, then doxygen will reuse the documentation of the first \n# member in the group (if any) for the other members of the group. By default \n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n# the same type (for instance a group of public functions) to be put as a \n# subgroup of that type (e.g. under the Public Functions section). Set it to \n# NO to prevent subgrouping. Alternatively, this can be done per class using \n# the \\nosubgrouping command.\n\nSUBGROUPING = YES\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \n# documentation are documented, even if no documentation was available. \n# Private class members and static file members will be hidden unless \n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \n# will be included in the documentation.\n\nEXTRACT_PRIVATE = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file \n# will be included in the documentation.\n\nEXTRACT_STATIC = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \n# defined locally in source files will be included in the documentation. \n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES = YES\n\n# This flag is only useful for Objective-C code. When set to YES local \n# methods, which are defined in the implementation section but not in \n# the interface are included in the documentation. \n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \n# undocumented members of documented classes, files or namespaces. \n# If set to NO (the default) these members will be included in the \n# various overviews, but no documentation section is generated. \n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \n# undocumented classes that are normally visible in the class hierarchy. \n# If set to NO (the default) these classes will be included in the various \n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \n# friend (class|struct|union) declarations. \n# If set to NO (the default) these declarations will be included in the \n# documentation.\n\nHIDE_FRIEND_COMPOUNDS = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \n# documentation blocks found inside the body of a function. \n# If set to NO (the default) these blocks will be appended to the \n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS = NO\n\n# The INTERNAL_DOCS tag determines if documentation \n# that is typed after a \\internal command is included. If the tag is set \n# to NO (the default) then the documentation will be excluded. \n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \n# file names in lower-case letters. If set to YES upper-case letters are also \n# allowed. This is useful if you have classes or files whose names only differ \n# in case and if your file system supports case sensitive file names. Windows \n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \n# will show members with their full class and namespace scopes in the \n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \n# will put a list of the files that are included by a file in the documentation \n# of that file.\n\nSHOW_INCLUDE_FILES = NO\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \n# is inserted in the documentation for inline members.\n\nINLINE_INFO = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \n# will sort the (detailed) documentation of file and class members \n# alphabetically by member name. If set to NO the members will appear in \n# declaration order.\n\nSORT_MEMBER_DOCS = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \n# brief documentation of file, namespace and class members alphabetically \n# by member name. If set to NO (the default) the members will appear in \n# declaration order.\n\nSORT_BRIEF_DOCS = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \n# sorted by fully-qualified names, including namespaces. If set to \n# NO (the default), the class list will be sorted only by class name, \n# not including the namespace part. \n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the \n# alphabetical list.\n\nSORT_BY_SCOPE_NAME = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or \n# disable (NO) the todo list. This list is created by putting \\todo \n# commands in the documentation.\n\nGENERATE_TODOLIST = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or \n# disable (NO) the test list. This list is created by putting \\test \n# commands in the documentation.\n\nGENERATE_TESTLIST = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or \n# disable (NO) the bug list. This list is created by putting \\bug \n# commands in the documentation.\n\nGENERATE_BUGLIST = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \n# disable (NO) the deprecated list. This list is created by putting \n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST = YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional \n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS = \n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \n# the initial value of a variable or define consists of for it to appear in \n# the documentation. If the initializer consists of more lines than specified \n# here it will be hidden. Use a value of 0 to hide initializers completely. \n# The appearance of the initializer of individual variables and defines in the \n# documentation can be controlled using \\showinitializer or \\hideinitializer \n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \n# at the bottom of the documentation of classes and structs. If set to YES the \n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES = YES\n\n# If the sources in your project are distributed over multiple directories \n# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \n# in the documentation. The default is NO.\n\nSHOW_DIRECTORIES = NO\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that \n# doxygen should invoke to get the current version for each file (typically from the \n# version control system). Doxygen will invoke the program by executing (via \n# popen()) the command <command> <input-file>, where <command> is the value of \n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file \n# provided by doxygen. Whatever the program writes to standard output \n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER = \n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated \n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are \n# generated by doxygen. Possible values are YES and NO. If left blank \n# NO is used.\n\nWARNINGS = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \n# potential errors in the documentation, such as not documenting some \n# parameters in a documented function, or documenting parameters that \n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR = YES\n\n# This WARN_NO_PARAMDOC option can be abled to get warnings for \n# functions that are documented, but have no documentation for their parameters \n# or return value. If set to NO (the default) doxygen will only warn about \n# wrong or incomplete parameter documentation, but not about the absence of \n# documentation.\n\nWARN_NO_PARAMDOC = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that \n# doxygen can produce. The string should contain the $file, $line, and $text \n# tags, which will be replaced by the file and line number from which the \n# warning originated and the warning text. Optionally the format may contain \n# $version, which will be replaced by the version of the file (if it could \n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning \n# and error messages should be written. If left blank the output is written \n# to stderr.\n\nWARN_LOGFILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain \n# documented source files. You may enter file names like \"myfile.cpp\" or \n# directories like \"/usr/src/myproject\". Separate the files or directories \n# with spaces.\n\nINPUT = include/zookeeper.h\n\n# If the value of the INPUT tag contains directories, you can use the \n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank the following patterns are tested: \n# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx \n# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py\n\nFILE_PATTERNS = \n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories \n# should be searched for input files as well. Possible values are YES and NO. \n# If left blank NO is used.\n\nRECURSIVE = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should \n# excluded from the INPUT source files. This way you can easily exclude a \n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n\nEXCLUDE = \n\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or \n# directories that are symbolic links (a Unix filesystem feature) are excluded \n# from the input.\n\nEXCLUDE_SYMLINKS = NO\n\n# If the value of the INPUT tag contains directories, you can use the \n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \n# certain files from those directories. Note that the wildcards are matched \n# against the file with absolute path, so to exclude all test directories \n# for example use the pattern */test/*\n\nEXCLUDE_PATTERNS = \n\n# The EXAMPLE_PATH tag can be used to specify one or more files or \n# directories that contain example code fragments that are included (see \n# the \\include command).\n\nEXAMPLE_PATH = \n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the \n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank all files are included.\n\nEXAMPLE_PATTERNS = \n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \n# searched for input files to be used with the \\include or \\dontinclude \n# commands irrespective of the value of the RECURSIVE tag. \n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or \n# directories that contain image that are included in the documentation (see \n# the \\image command).\n\nIMAGE_PATH = \n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should \n# invoke to filter for each input file. Doxygen will invoke the filter program \n# by executing (via popen()) the command <filter> <input-file>, where <filter> \n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \n# input file. Doxygen will then use the output that the filter program writes \n# to standard output.  If FILTER_PATTERNS is specified, this tag will be \n# ignored.\n\nINPUT_FILTER = \n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \n# basis.  Doxygen will compare the file name with each pattern and apply the \n# filter if there is a match.  The filters are a list of the form: \n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \n# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \n# is applied to all files.\n\nFILTER_PATTERNS = \n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \n# INPUT_FILTER) will be used to filter the input files when producing source \n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will \n# be generated. Documented entities will be cross-referenced with these sources. \n# Note: To get rid of all source code in the generated output, make sure also \n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body \n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \n# doxygen to hide any special comment blocks from generated source code \n# fragments. Normal C and C++ comments will always remain visible.\n\nSTRIP_CODE_COMMENTS = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES (the default) \n# then for each documented function all documented \n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES (the default) \n# then for each documented function all documented entities \n# called/used by that function will be listed.\n\nREFERENCES_RELATION = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n# link to the source code.  Otherwise they will link to the documentstion.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code \n# will point to the HTML generated by the htags(1) tool instead of doxygen \n# built-in source browser. The htags tool is part of GNU's global source \n# tagging system (see http://www.gnu.org/software/global/global.html). You \n# will need version 4.8.6 or higher.\n\nUSE_HTAGS = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \n# will generate a verbatim copy of the header file for each class for \n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \n# of all compounds will be generated. Enable this if the project \n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX = 5\n\n# In case all classes in a project start with a common prefix, all \n# classes will be put under the same header in the alphabetical index. \n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX = \n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \n# generate HTML output.\n\nGENERATE_HTML = $(GENERATE_HTML)\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard header.\n\nHTML_HEADER = \n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard footer.\n\nHTML_FOOTER = \n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \n# style sheet that is used by each HTML page. It can be used to \n# fine-tune the look of the HTML output. If the tag is left blank doxygen \n# will generate a default style sheet. Note that doxygen will try to copy \n# the style sheet file to the HTML output directory, so don't put your own \n# stylesheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET = \n\n# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \n# files or namespaces will be aligned in HTML using tables. If set to \n# NO a bullet list will be used.\n\nHTML_ALIGN_MEMBERS = YES\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files \n# will be generated that can be used as input for tools like the \n# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP = $(GENERATE_HTMLHELP)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \n# be used to specify the file name of the resulting .chm file. You \n# can add a path in front of the file if the result should not be \n# written to the html output directory.\n\nCHM_FILE = ../$(PROJECT).chm\n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \n# be used to specify the location (absolute path including file name) of \n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION = $(HHC_PATH)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \n# controls if a separate .chi index file is generated (YES) or that \n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI = $(GENERATE_CHI)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \n# controls whether a binary table of contents is generated (YES) or a \n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members \n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND = NO\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \n# top of each HTML page. The value NO (the default) enables the index and \n# the value YES disables it.\n\nDISABLE_INDEX = NO\n\n# This tag can be used to set the number of enum values (range [1..20]) \n# that doxygen will group on one line in the generated HTML documentation.\n\nENUM_VALUES_PER_LINE = 4\n\n# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\n# generated containing a tree-like index structure (just like the one that \n# is generated for HTML Help). For this to work a browser that supports \n# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \n# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \n# probably better off using the HTML help feature.\n\nGENERATE_TREEVIEW = NO\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \n# used to set the initial width (in pixels) of the frame in which the tree \n# is shown.\n\nTREEVIEW_WIDTH = 250\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \n# generate Latex output.\n\nGENERATE_LATEX = $(GENERATE_LATEX)\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \n# invoked. If left blank `latex' will be used as the default command name.\n\nLATEX_CMD_NAME = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \n# generate index for LaTeX. If left blank `makeindex' will be used as the \n# default command name.\n\nMAKEINDEX_CMD_NAME = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \n# LaTeX documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_LATEX = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used \n# by the printer. Possible values are: a4, a4wide, letter, legal and \n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE = $(PAPER_SIZE)\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES = \n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \n# the generated latex document. The header should contain everything until \n# the first chapter. If it is left blank doxygen will generate a \n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER = \n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \n# is prepared for conversion to pdf (using ps2pdf). The pdf file will \n# contain links (just like the HTML output) instead of page references \n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS = NO\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \n# plain latex in the generated Makefile. Set this option to YES to get a \n# higher quality PDF documentation.\n\nUSE_PDFLATEX = $(GENERATE_PDF)\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode. \n# command to the generated LaTeX files. This will instruct LaTeX to keep \n# running if errors occur, instead of asking the user for help. \n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not \n# include the index chapters (such as File Index, Compound Index, etc.) \n# in the output.\n\nLATEX_HIDE_INDICES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \n# The RTF output is optimized for Word 97 and may not look very pretty with \n# other RTF readers or editors.\n\nGENERATE_RTF = $(GENERATE_RTF)\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \n# RTF documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_RTF = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \n# will contain hyperlink fields. The RTF file will \n# contain links (just like the HTML output) instead of page references. \n# This makes the output suitable for online browsing using WORD or other \n# programs which support those fields. \n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's \n# config file, i.e. a series of assignments. You only have to provide \n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE = \n\n# Set optional variables used in the generation of an rtf document. \n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \n# generate man pages\n\nGENERATE_MAN = $(GENERATE_MAN)\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT = man\n\n# The MAN_EXTENSION tag determines the extension that is added to \n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \n# then it will generate one additional man file for each entity \n# documented in the real man page(s). These additional files \n# only source the real man page, but without them the man command \n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will \n# generate an XML file that captures the structure of \n# the code including all documentation.\n\nGENERATE_XML = $(GENERATE_XML)\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_SCHEMA = \n\n# The XML_DTD tag can be used to specify an XML DTD, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_DTD = \n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \n# dump the program listings (including syntax highlighting \n# and cross-referencing information) to the XML output. Note that \n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \n# generate an AutoGen Definitions (see autogen.sf.net) file \n# that captures the structure of the code including all \n# documentation. Note that this feature is still experimental \n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will \n# generate a Perl module file that captures the structure of \n# the code including all documentation. Note that this \n# feature is still experimental and incomplete at the \n# moment.\n\nGENERATE_PERLMOD = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \n# the necessary Makefile rules, Perl scripts and LaTeX code to be able \n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \n# nicely formatted so it can be parsed by a human reader.  This is useful \n# if you want to understand what is going on.  On the other hand, if this \n# tag is set to NO the size of the Perl module output will be much smaller \n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY = YES\n\n# The names of the make variables in the generated doxyrules.make file \n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \n# This is useful so different doxyrules.make files included by the same \n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor   \n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \n# evaluate all C-preprocessor directives found in the sources and include \n# files.\n\nENABLE_PREPROCESSING = YES\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \n# names in the source code. If set to NO (the default) only conditional \n# compilation will be performed. Macro expansion can be done in a controlled \n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \n# then the macro expansion is limited to the macros specified with the \n# PREDEFINED and EXPAND_AS_DEFINED tags.\n\nEXPAND_ONLY_PREDEF = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \n# in the INCLUDE_PATH (see below) will be search if a #include is found.\n\nSEARCH_INCLUDES = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that \n# contain include files that are not input files but should be processed by \n# the preprocessor.\n\nINCLUDE_PATH = \n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \n# patterns (like *.h and *.hpp) to filter out the header-files in the \n# directories. If left blank, the patterns specified with FILE_PATTERNS will \n# be used.\n\nINCLUDE_FILE_PATTERNS = \n\n# The PREDEFINED tag can be used to specify one or more macro names that \n# are defined before the preprocessor is started (similar to the -D option of \n# gcc). The argument of the tag is a list of macros of the form: name \n# or name=definition (no spaces). If the definition and the = are \n# omitted =1 is assumed. To prevent a macro definition from being \n# undefined via #undef or recursively expanded use the := operator \n# instead of the = operator.\n\nPREDEFINED = \n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \n# this tag can be used to specify a list of macro names that should be expanded. \n# The macro definition that is found in the sources will be used. \n# Use the PREDEFINED tag if you want to use a different macro definition.\n\nEXPAND_AS_DEFINED = \n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \n# doxygen's preprocessor will remove all function-like macros that are alone \n# on a line, have an all uppercase name, and do not end with a semicolon. Such \n# function macros are typically used for boiler-plate code, and will confuse \n# the parser if not removed.\n\nSKIP_FUNCTION_MACROS = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references   \n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles. \n# Optionally an initial location of the external documentation \n# can be added for each tagfile. The format of a tag file without \n# this location is as follows: \n#   TAGFILES = file1 file2 ... \n# Adding location for the tag files is done as follows: \n#   TAGFILES = file1=loc1 \"file2 = loc2\" ... \n# where \"loc1\" and \"loc2\" can be relative or absolute paths or \n# URLs. If a location is present for each tag, the installdox tool \n# does not have to be run to correct the links.\n# Note that each tag file must have a unique name\n# (where the name does NOT include the path)\n# If a tag file is not located in the directory in which doxygen \n# is run, you must also specify the path to the tagfile here.\n\nTAGFILES = \n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create \n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag\n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed \n# in the class index. If set to NO only the inherited external classes \n# will be listed.\n\nALLEXTERNALS = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \n# in the modules index. If set to NO, only the current project's groups will \n# be listed.\n\nEXTERNAL_GROUPS = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script \n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool   \n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base \n# or super classes. Setting the tag to NO turns the diagrams off. Note that \n# this option is superseded by the HAVE_DOT option below. This is only a \n# fallback. It is recommended to install and use dot, since it yields more \n# powerful graphs.\n\nCLASS_DIAGRAMS = YES\n\n# If set to YES, the inheritance and collaboration graphs will hide \n# inheritance and usage relations if the target is undocumented \n# or is not a class.\n\nHIDE_UNDOC_RELATIONS = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \n# available from the path. This tool is part of Graphviz, a graph visualization \n# toolkit from AT&T and Lucent Bell Labs. The other options in this section \n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT = $(HAVE_DOT)\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect inheritance relations. Setting this tag to YES will force the \n# the CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect implementation dependencies (inheritance, containment, and \n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \n# collaboration diagrams in a style similar to the OMG's Unified Modeling \n# Language.\n\nUML_LOOK = NO\n\n# If set to YES, the inheritance and collaboration graphs will show the \n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \n# tags are set to YES then doxygen will generate a graph for each documented \n# file showing the direct and indirect include dependencies of the file with \n# other documented files.\n\nINCLUDE_GRAPH = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \n# documented header file showing the documented files that directly or \n# indirectly include this file.\n\nINCLUDED_BY_GRAPH = YES\n\n# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a call dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable call graphs for selected \n# functions only using the \\callgraph command.\n\nCALL_GRAPH = NO\n\n# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a caller dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable caller graphs for selected \n# functions only using the \\callergraph command.\n\nCALLER_GRAPH = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \n# will graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY = YES\n\n# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \n# then doxygen will show the dependencies a directory has on other directories \n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \n# generated by dot. Possible values are png, jpg, or gif\n# If left blank png will be used.\n\nDOT_IMAGE_FORMAT = png\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be \n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH = $(DOT_PATH)\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that \n# contain dot files that are included in the documentation (see the \n# \\dotfile command).\n\nDOTFILE_DIRS = \n\n# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_WIDTH = 1024\n\n# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_HEIGHT = 1024\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \n# graphs generated by dot. A depth value of 3 means that only nodes reachable \n# from the root by following a path via at most 3 edges will be shown. Nodes \n# that lay further from the root node will be omitted. Note that setting this \n# option to 1 or 2 may greatly reduce the computation time needed for large \n# code bases. Also note that a graph may be further truncated if the graph's \n# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH \n# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), \n# the graph is not depth-constrained.\n\nMAX_DOT_GRAPH_DEPTH = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent \n# background. This is disabled by default, which results in a white background. \n# Warning: Depending on the platform used, enabling this option may lead to \n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to \n# read).\n\nDOT_TRANSPARENT = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output \n# files in one run (i.e. multiple -o and -T options on the command line). This \n# makes dot run faster, but since only newer versions of dot (>1.8.10) \n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \n# generate a legend page explaining the meaning of the various boxes and \n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \n# remove the intermediate dot files that are used to generate \n# the various graphs.\n\nDOT_CLEANUP = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to the search engine   \n#---------------------------------------------------------------------------\n\n# The SEARCHENGINE tag specifies whether or not a search engine should be \n# used. If set to NO the values of all tags below this one will be ignored.\n\nSEARCHENGINE = NO\n"
  },
  {
    "path": "src/c/cmake_config.h.in",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef CONFIG_H_\n#define CONFIG_H_\n\n/* Define to 1 if you have the <arpa/inet.h> header file. */\n#cmakedefine HAVE_ARPA_INET_H 1\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#cmakedefine HAVE_DLFCN_H 1\n\n/* Define to 1 if you have the <fcntl.h> header file. */\n#cmakedefine HAVE_FCNTL_H 1\n\n/* Define to 1 if you have the file `generated/zookeeper.jute.c'. */\n#cmakedefine HAVE_GENERATED_ZOOKEEPER_JUTE_C 1\n\n/* Define to 1 if you have the file `generated/zookeeper.jute.h'. */\n#cmakedefine HAVE_GENERATED_ZOOKEEPER_JUTE_H 1\n\n/* Define to 1 if you have the `getcwd' function. */\n#cmakedefine HAVE_GETCWD 1\n\n/* Define to 1 if you have the `gethostbyname' function. */\n#cmakedefine HAVE_GETHOSTBYNAME 1\n\n/* Define to 1 if you have the `gethostname' function. */\n#cmakedefine HAVE_GETHOSTNAME 1\n\n/* Define to 1 if you have the `getlogin' function. */\n#cmakedefine HAVE_GETLOGIN 1\n\n/* Define to 1 if you have the `getpwuid_r' function. */\n#cmakedefine HAVE_GETPWUID_R 1\n\n/* Define to 1 if you have the `gettimeofday' function. */\n#cmakedefine HAVE_GETTIMEOFDAY 1\n\n/* Define to 1 if you have the `getuid' function. */\n#cmakedefine HAVE_GETUID 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#cmakedefine HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `rt' library (-lrt). */\n#cmakedefine HAVE_LIBRT 1\n\n/* Define to 1 if you have the `memmove' function. */\n#cmakedefine HAVE_MEMMOVE 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#cmakedefine HAVE_MEMORY_H 1\n\n/* Define to 1 if you have the `memset' function. */\n#cmakedefine HAVE_MEMSET 1\n\n/* Define to 1 if you have the <netdb.h> header file. */\n#cmakedefine HAVE_NETDB_H 1\n\n/* Define to 1 if you have the <netinet/in.h> header file. */\n#cmakedefine HAVE_NETINET_IN_H 1\n\n/* Define to 1 if you have the `poll' function. */\n#cmakedefine HAVE_POLL 1\n\n/* Define to 1 if you have the `socket' function. */\n#cmakedefine HAVE_SOCKET 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#cmakedefine HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#cmakedefine HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the `strchr' function. */\n#cmakedefine HAVE_STRCHR 1\n\n/* Define to 1 if you have the `strdup' function. */\n#cmakedefine HAVE_STRDUP 1\n\n/* Define to 1 if you have the `strerror' function. */\n#cmakedefine HAVE_STRERROR 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#cmakedefine HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#cmakedefine HAVE_STRING_H 1\n\n/* Define to 1 if you have the `strtol' function. */\n#cmakedefine HAVE_STRTOL 1\n\n/* Define to 1 if you have the <sys/socket.h> header file. */\n#cmakedefine HAVE_SYS_SOCKET_H 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#cmakedefine HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#cmakedefine HAVE_SYS_TIME_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#cmakedefine HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <sys/utsname.h> header file. */\n#cmakedefine HAVE_SYS_UTSNAME_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#cmakedefine HAVE_UNISTD_H 1\n\n/* Define to 1 if IPv6 support is available. */\n#cmakedefine ZOO_IPV6_ENABLED 1\n\n/* poll() second argument type */\n#define POLL_NFDS_TYPE nfds_t\n\n/* Name of package */\n#define PACKAGE \"${PROJECT_NAME}\"\n\n/* Define to the address where bug reports for this package should be sent. */\n#define PACKAGE_BUGREPORT \"${email}\"\n\n/* Define to the full name of this package. */\n#define PACKAGE_NAME \"${description}\"\n\n/* Define to the full name and version of this package. */\n#define PACKAGE_STRING \"${description} ${PROJECT_VERSION}\"\n\n/* Define to the one symbol short name of this package. */\n#define PACKAGE_TARNAME \"${PROJECT_NAME}\"\n\n/* Define to the version of this package. */\n#define PACKAGE_VERSION \"${PROJECT_VERSION}\"\n\n/* Version number of package */\n#define VERSION \"${PROJECT_VERSION}\"\n\n#endif\n"
  },
  {
    "path": "src/c/configure.ac",
    "content": "#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ(2.59)\n\nAC_INIT([zookeeper C client],3.4.12,[user@zookeeper.apache.org],[zookeeper])\nAC_CONFIG_SRCDIR([src/zookeeper.c])\n\n# Save initial CFLAGS and CXXFLAGS values before AC_PROG_CC and AC_PROG_CXX\ninit_cflags=\"$CFLAGS\"\ninit_cxxflags=\"$CXXFLAGS\"\n\n# initialize Doxygen support\nDX_HTML_FEATURE(ON)\nDX_CHM_FEATURE(OFF)\nDX_CHI_FEATURE(OFF)\nDX_MAN_FEATURE(OFF)\nDX_RTF_FEATURE(OFF)\nDX_XML_FEATURE(OFF)\nDX_PDF_FEATURE(OFF)\nDX_PS_FEATURE(OFF)\nDX_INIT_DOXYGEN([zookeeper],[c-doc.Doxyfile],[docs])\n\n# initialize automake\nAM_INIT_AUTOMAKE([-Wall foreign])\nAC_CONFIG_HEADER([config.h])\n\n# Checks for programs.\nAC_ARG_WITH(cppunit,\n        [  --without-cppunit       do not use CPPUNIT])\n\nif test \"$with_cppunit\" = \"no\" ; then\n   CPPUNIT_PATH=\"No_CPPUNIT\"\n   CPPUNIT_INCLUDE=\n   CPPUNIT_LIBS=\nelse\n   AM_PATH_CPPUNIT(1.10.2)\nfi\n\nif test \"$CALLER\" = \"ANT\" ; then\nCPPUNIT_CFLAGS=\"$CPPUNIT_CFLAGS -DZKSERVER_CMD=\\\"\\\\\\\"${base_dir}/src/c/tests/zkServer.sh\\\\\\\"\\\"\"\nelse\nCPPUNIT_CFLAGS=\"$CPPUNIT_CFLAGS -DZKSERVER_CMD=\\\"\\\\\\\"./tests/zkServer.sh\\\\\\\"\\\"\"\nAC_CHECK_FILES([generated/zookeeper.jute.c generated/zookeeper.jute.h],[],\n    [AC_MSG_ERROR([jute files are missing! Please run \"ant compile_jute\" while in the zookeeper top level directory.])\n])\nfi\nAC_SUBST(CPPUNIT_CFLAGS)\n\nAC_PROG_CC\nAM_PROG_CC_C_O\nAC_PROG_CXX\nAC_PROG_INSTALL\nAC_PROG_LN_S\n\n# AC_DISABLE_SHARED\nAC_PROG_LIBTOOL\n\n#enable -D_GNU_SOURCE since the return code value of getaddrinfo\n#ifdefed with __USE_GNU\n#features.h header undef's __USE_GNU and defines it only if _GNU_SOURCE is defined\n#hence this define for gcc\nAC_ARG_ENABLE([debug],\n [AS_HELP_STRING([--enable-debug],[enable debug build [default=no]])],\n [],[enable_debug=no])\n\nif test \"x$enable_debug\" = xyes; then\n    if test \"x$init_cflags\" = x; then\n        CFLAGS=\"\"\n    fi\n    CFLAGS=\"$CFLAGS -g -O0 -D_GNU_SOURCE\"\nelse\n    if test \"x$init_cflags\" = x; then\n        CFLAGS=\"-g -O2 -D_GNU_SOURCE\"\n    fi\nfi\n\nif test \"x$enable_debug\" = xyes; then\n    if test \"x$init_cxxflags\" = x; then\n        CXXFLAGS=\"\"\n    fi\n    CXXFLAGS=\"$CXXFLAGS -g -O0\"\nelse\n    if test \"x$init_cxxflags\" = x; then\n        CXXFLAGS=\"-g -O2\"\n    fi\nfi\n\nAC_ARG_WITH([syncapi],\n [AS_HELP_STRING([--with-syncapi],[build with support for SyncAPI [default=yes]])],\n [],[with_syncapi=yes])\n\n# Checks for libraries.\nAC_CHECK_LIB([pthread], [pthread_mutex_lock],[have_pthread=yes],[have_pthread=no])\n\nif test \"x$with_syncapi\" != xno && test \"x$have_pthread\" = xno; then\n    AC_MSG_WARN([cannot build SyncAPI -- pthread not found])\n    with_syncapi=no\nfi\nif test \"x$with_syncapi\" != xno; then\n    AC_MSG_NOTICE([building with SyncAPI support])\nelse\n    AC_MSG_NOTICE([building without SyncAPI support])\nfi\n\nAM_CONDITIONAL([WANT_SYNCAPI],[test \"x$with_syncapi\" != xno])\n\n# Checks for header files.\nAC_HEADER_STDC\nAC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h sys/utsname.h])\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_C_CONST\nAC_C_INLINE\nAC_HEADER_TIME\nAC_CHECK_TYPE([nfds_t],\n    [AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[poll() second argument type])],\n    [AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[poll() second argument type])],\n    [#include <poll.h>])\n\nAC_MSG_CHECKING([whether to enable ipv6])\n\nAC_TRY_RUN([ /* is AF_INET6 available? */\n#include <sys/types.h>\n#include <sys/socket.h>\nmain()\n{\n if (socket(AF_INET6, SOCK_STREAM, 0) < 0)\n   exit(1);\n else\n   exit(0);\n}\n], AC_MSG_RESULT(yes) \n   ipv6=yes, \n   AC_MSG_RESULT(no) \n   ipv6=no, \n   AC_MSG_RESULT(no) \n   ipv6=no)\n\nif test x\"$ipv6\" = xyes; then\n  USEIPV6=\"-DZOO_IPV6_ENABLED\"\n  AC_SUBST(USEIPV6)\nfi\n\n# Checks for library functions.\nAC_CHECK_FUNCS([getcwd gethostbyname gethostname getlogin getpwuid_r gettimeofday getuid memmove memset poll socket strchr strdup strerror strtol])\n\nAC_CONFIG_FILES([Makefile])\nAC_CANONICAL_HOST\nAM_CONDITIONAL([SOLARIS],[\n  case \"$host_os\" in\n  *solaris*)\n    true\n    ;;\n  *)\n    false\n    ;;\n  esac ])\nAC_OUTPUT\n"
  },
  {
    "path": "src/c/include/proto.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef PROTO_H_\n#define PROTO_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZOO_NOTIFY_OP 0\n#define ZOO_CREATE_OP 1\n#define ZOO_DELETE_OP 2\n#define ZOO_EXISTS_OP 3\n#define ZOO_GETDATA_OP 4\n#define ZOO_SETDATA_OP 5\n#define ZOO_GETACL_OP 6\n#define ZOO_SETACL_OP 7\n#define ZOO_GETCHILDREN_OP 8\n#define ZOO_SYNC_OP 9\n#define ZOO_PING_OP 11\n#define ZOO_GETCHILDREN2_OP 12\n#define ZOO_CHECK_OP 13\n#define ZOO_MULTI_OP 14\n#define ZOO_CLOSE_OP -11\n#define ZOO_SETAUTH_OP 100\n#define ZOO_SETWATCHES_OP 101\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*PROTO_H_*/\n"
  },
  {
    "path": "src/c/include/recordio.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef __RECORDIO_H__\n#define __RECORDIO_H__\n\n#include <sys/types.h>\n#include <stdint.h> /* for int64_t */\n#ifdef WIN32\n#include \"winconfig.h\"\n#define STRUCT_INITIALIZER(l,r)  r\n#else\n#define STRUCT_INITIALIZER(l,r) .l = r\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct buffer {\n    int32_t len;\n    char *buff;\n};\n\nvoid deallocate_String(char **s);\nvoid deallocate_Buffer(struct buffer *b);\nvoid deallocate_vector(void *d);\nstruct iarchive {\n    int (*start_record)(struct iarchive *ia, const char *tag);\n    int (*end_record)(struct iarchive *ia, const char *tag);\n    int (*start_vector)(struct iarchive *ia, const char *tag, int32_t *count);\n    int (*end_vector)(struct iarchive *ia, const char *tag);\n    int (*deserialize_Bool)(struct iarchive *ia, const char *name, int32_t *);\n    int (*deserialize_Int)(struct iarchive *ia, const char *name, int32_t *);\n    int (*deserialize_Long)(struct iarchive *ia, const char *name, int64_t *);\n    int (*deserialize_Buffer)(struct iarchive *ia, const char *name,\n            struct buffer *);\n    int (*deserialize_String)(struct iarchive *ia, const char *name, char **);\n    void *priv;\n};\nstruct oarchive {\n    int (*start_record)(struct oarchive *oa, const char *tag);\n    int (*end_record)(struct oarchive *oa, const char *tag);\n    int (*start_vector)(struct oarchive *oa, const char *tag, const int32_t *count);\n    int (*end_vector)(struct oarchive *oa, const char *tag);\n    int (*serialize_Bool)(struct oarchive *oa, const char *name, const int32_t *);\n    int (*serialize_Int)(struct oarchive *oa, const char *name, const int32_t *);\n    int (*serialize_Long)(struct oarchive *oa, const char *name,\n            const int64_t *);\n    int (*serialize_Buffer)(struct oarchive *oa, const char *name,\n            const struct buffer *);\n    int (*serialize_String)(struct oarchive *oa, const char *name, char **);\n    void *priv;\n};\n\nstruct oarchive *create_buffer_oarchive(void);\nvoid close_buffer_oarchive(struct oarchive **oa, int free_buffer);\nstruct iarchive *create_buffer_iarchive(char *buffer, int len);\nvoid close_buffer_iarchive(struct iarchive **ia);\nchar *get_buffer(struct oarchive *);\nint get_buffer_len(struct oarchive *);\n\nint64_t zoo_htonll(int64_t v);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/c/include/winconfig.h",
    "content": "#ifndef WINCONFIG_H_\n#define WINCONFIG_H_\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n#define inline __inline\n#endif\n\n#define __attribute__(x)\n#define __func__ __FUNCTION__\n\n#define ACL ZKACL /* Conflict with windows API */\n\n#endif\n"
  },
  {
    "path": "src/c/include/zookeeper.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZOOKEEPER_H_\n#define ZOOKEEPER_H_\n\n#include <stdlib.h>\n\n/* we must not include config.h as a public header */\n#ifndef WIN32\n#include <sys/socket.h>\n#include <sys/time.h>\n#endif\n\n#ifdef WIN32\n#include <winsock2.h> /* must always be included before ws2tcpip.h */\n#include <ws2tcpip.h> /* for struct sock_addr and socklen_t */\n#endif\n\n#include <stdio.h>\n#include <ctype.h>\n\n#include \"proto.h\"\n#include \"zookeeper_version.h\"\n#include \"recordio.h\"\n#include \"zookeeper.jute.h\"\n\n/**\n * \\file zookeeper.h \n * \\brief ZooKeeper functions and definitions.\n * \n * ZooKeeper is a network service that may be backed by a cluster of\n * synchronized servers. The data in the service is represented as a tree\n * of data nodes. Each node has data, children, an ACL, and status information.\n * The data for a node is read and write in its entirety.\n * \n * ZooKeeper clients can leave watches when they queries the data or children\n * of a node. If a watch is left, that client will be notified of the change.\n * The notification is a one time trigger. Subsequent chances to the node will\n * not trigger a notification unless the client issues a query with the watch\n * flag set. If the client is ever disconnected from the service, the watches do \n * not need to be reset. The client automatically resets the watches.\n * \n * When a node is created, it may be flagged as an ephemeral node. Ephemeral\n * nodes are automatically removed when a client session is closed or when\n * a session times out due to inactivity (the ZooKeeper runtime fills in\n * periods of inactivity with pings). Ephemeral nodes cannot have children.\n * \n * ZooKeeper clients are identified by a server assigned session id. For\n * security reasons The server\n * also generates a corresponding password for a session. A client may save its\n * id and corresponding password to persistent storage in order to use the\n * session across program invocation boundaries.\n */\n\n/* Support for building on various platforms */\n\n// on cygwin we should take care of exporting/importing symbols properly \n#ifdef DLL_EXPORT\n#    define ZOOAPI __declspec(dllexport)\n#else\n#  if (defined(__CYGWIN__) || defined(WIN32)) && !defined(USE_STATIC_LIB)\n#    define ZOOAPI __declspec(dllimport)\n#  else\n#    define ZOOAPI\n#  endif\n#endif\n\n/** zookeeper return constants **/\n\nenum ZOO_ERRORS {\n  ZOK = 0, /*!< Everything is OK */\n\n  /** System and server-side errors.\n   * This is never thrown by the server, it shouldn't be used other than\n   * to indicate a range. Specifically error codes greater than this\n   * value, but lesser than {@link #ZAPIERROR}, are system errors. */\n  ZSYSTEMERROR = -1,\n  ZRUNTIMEINCONSISTENCY = -2, /*!< A runtime inconsistency was found */\n  ZDATAINCONSISTENCY = -3, /*!< A data inconsistency was found */\n  ZCONNECTIONLOSS = -4, /*!< Connection to the server has been lost */\n  ZMARSHALLINGERROR = -5, /*!< Error while marshalling or unmarshalling data */\n  ZUNIMPLEMENTED = -6, /*!< Operation is unimplemented */\n  ZOPERATIONTIMEOUT = -7, /*!< Operation timeout */\n  ZBADARGUMENTS = -8, /*!< Invalid arguments */\n  ZINVALIDSTATE = -9, /*!< Invliad zhandle state */\n\n  /** API errors.\n   * This is never thrown by the server, it shouldn't be used other than\n   * to indicate a range. Specifically error codes greater than this\n   * value are API errors (while values less than this indicate a \n   * {@link #ZSYSTEMERROR}).\n   */\n  ZAPIERROR = -100,\n  ZNONODE = -101, /*!< Node does not exist */\n  ZNOAUTH = -102, /*!< Not authenticated */\n  ZBADVERSION = -103, /*!< Version conflict */\n  ZNOCHILDRENFOREPHEMERALS = -108, /*!< Ephemeral nodes may not have children */\n  ZNODEEXISTS = -110, /*!< The node already exists */\n  ZNOTEMPTY = -111, /*!< The node has children */\n  ZSESSIONEXPIRED = -112, /*!< The session has been expired by the server */\n  ZINVALIDCALLBACK = -113, /*!< Invalid callback specified */\n  ZINVALIDACL = -114, /*!< Invalid ACL specified */\n  ZAUTHFAILED = -115, /*!< Client authentication failed */\n  ZCLOSING = -116, /*!< ZooKeeper is closing */\n  ZNOTHING = -117, /*!< (not error) no server responses to process */\n  ZSESSIONMOVED = -118 /*!<session moved to another server, so operation is ignored */ \n};\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n*  @name Debug levels\n*/\ntypedef enum {ZOO_LOG_LEVEL_ERROR=1,ZOO_LOG_LEVEL_WARN=2,ZOO_LOG_LEVEL_INFO=3,ZOO_LOG_LEVEL_DEBUG=4} ZooLogLevel;\n\n/**\n * @name ACL Consts\n */\nextern ZOOAPI const int ZOO_PERM_READ;\nextern ZOOAPI const int ZOO_PERM_WRITE;\nextern ZOOAPI const int ZOO_PERM_CREATE;\nextern ZOOAPI const int ZOO_PERM_DELETE;\nextern ZOOAPI const int ZOO_PERM_ADMIN;\nextern ZOOAPI const int ZOO_PERM_ALL;\n\n/** This Id represents anyone. */\nextern ZOOAPI struct Id ZOO_ANYONE_ID_UNSAFE;\n/** This Id is only usable to set ACLs. It will get substituted with the\n * Id's the client authenticated with.\n */\nextern ZOOAPI struct Id ZOO_AUTH_IDS;\n\n/** This is a completely open ACL*/\nextern ZOOAPI struct ACL_vector ZOO_OPEN_ACL_UNSAFE;\n/** This ACL gives the world the ability to read. */\nextern ZOOAPI struct ACL_vector ZOO_READ_ACL_UNSAFE;\n/** This ACL gives the creators authentication id's all permissions. */\nextern ZOOAPI struct ACL_vector ZOO_CREATOR_ALL_ACL;\n\n/**\n * @name Interest Consts\n * These constants are used to express interest in an event and to\n * indicate to zookeeper which events have occurred. They can\n * be ORed together to express multiple interests. These flags are\n * used in the interest and event parameters of \n * \\ref zookeeper_interest and \\ref zookeeper_process.\n */\n// @{\nextern ZOOAPI const int ZOOKEEPER_WRITE;\nextern ZOOAPI const int ZOOKEEPER_READ;\n// @}\n\n/**\n * @name Create Flags\n * \n * These flags are used by zoo_create to affect node create. They may\n * be ORed together to combine effects.\n */\n// @{\nextern ZOOAPI const int ZOO_EPHEMERAL;\nextern ZOOAPI const int ZOO_SEQUENCE;\n// @}\n\n/**\n * @name State Consts\n * These constants represent the states of a zookeeper connection. They are\n * possible parameters of the watcher callback.\n */\n// @{\nextern ZOOAPI const int ZOO_EXPIRED_SESSION_STATE;\nextern ZOOAPI const int ZOO_AUTH_FAILED_STATE;\nextern ZOOAPI const int ZOO_CONNECTING_STATE;\nextern ZOOAPI const int ZOO_ASSOCIATING_STATE;\nextern ZOOAPI const int ZOO_CONNECTED_STATE;\n// @}\n\n/**\n * @name Watch Types\n * These constants indicate the event that caused the watch event. They are\n * possible values of the first parameter of the watcher callback.\n */\n// @{\n/**\n * \\brief a node has been created.\n * \n * This is only generated by watches on non-existent nodes. These watches\n * are set using \\ref zoo_exists.\n */\nextern ZOOAPI const int ZOO_CREATED_EVENT;\n/**\n * \\brief a node has been deleted.\n * \n * This is only generated by watches on nodes. These watches\n * are set using \\ref zoo_exists and \\ref zoo_get.\n */\nextern ZOOAPI const int ZOO_DELETED_EVENT;\n/**\n * \\brief a node has changed.\n * \n * This is only generated by watches on nodes. These watches\n * are set using \\ref zoo_exists and \\ref zoo_get.\n */\nextern ZOOAPI const int ZOO_CHANGED_EVENT;\n/**\n * \\brief a change as occurred in the list of children.\n * \n * This is only generated by watches on the child list of a node. These watches\n * are set using \\ref zoo_get_children or \\ref zoo_get_children2.\n */\nextern ZOOAPI const int ZOO_CHILD_EVENT;\n/**\n * \\brief a session has been lost.\n * \n * This is generated when a client loses contact or reconnects with a server.\n */\nextern ZOOAPI const int ZOO_SESSION_EVENT;\n\n/**\n * \\brief a watch has been removed.\n * \n * This is generated when the server for some reason, probably a resource\n * constraint, will no longer watch a node for a client.\n */\nextern ZOOAPI const int ZOO_NOTWATCHING_EVENT;\n// @}\n\n/**\n * \\brief ZooKeeper handle.\n * \n * This is the handle that represents a connection to the ZooKeeper service.\n * It is needed to invoke any ZooKeeper function. A handle is obtained using\n * \\ref zookeeper_init.\n */\ntypedef struct _zhandle zhandle_t;\n\n/**\n * \\brief client id structure.\n * \n * This structure holds the id and password for the session. This structure\n * should be treated as opaque. It is received from the server when a session\n * is established and needs to be sent back as-is when reconnecting a session.\n */\ntypedef struct {\n    int64_t client_id;\n    char passwd[16];\n} clientid_t;\n\n/**\n * \\brief zoo_op structure.\n *\n * This structure holds all the arguments necessary for one op as part\n * of a containing multi_op via \\ref zoo_multi or \\ref zoo_amulti.\n * This structure should be treated as opaque and initialized via \n * \\ref zoo_create_op_init, \\ref zoo_delete_op_init, \\ref zoo_set_op_init\n * and \\ref zoo_check_op_init.\n */\ntypedef struct zoo_op {\n    int type;\n    union {\n        // CREATE\n        struct {\n            const char *path;\n            const char *data;\n            int datalen;\n\t        char *buf;\n            int buflen;\n            const struct ACL_vector *acl;\n            int flags;\n        } create_op;\n\n        // DELETE \n        struct {\n            const char *path;\n            int version;\n        } delete_op;\n        \n        // SET\n        struct {\n            const char *path;\n            const char *data;\n            int datalen;\n            int version;\n            struct Stat *stat;\n        } set_op;\n        \n        // CHECK\n        struct {\n            const char *path;\n            int version;\n        } check_op;\n    };\n} zoo_op_t;\n\n/**\n * \\brief zoo_create_op_init.\n *\n * This function initializes a zoo_op_t with the arguments for a ZOO_CREATE_OP.\n *\n * \\param op A pointer to the zoo_op_t to be initialized.\n * \\param path The name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param value The data to be stored in the node.\n * \\param valuelen The number of bytes in data. To set the data to be NULL use\n * value as NULL and valuelen as -1.\n * \\param acl The initial ACL of the node. The ACL must not be null or empty.\n * \\param flags this parameter can be set to 0 for normal create or an OR\n *    of the Create Flags\n * \\param path_buffer Buffer which will be filled with the path of the\n *    new node (this might be different than the supplied path\n *    because of the ZOO_SEQUENCE flag).  The path string will always be\n *    null-terminated. This parameter may be NULL if path_buffer_len = 0.\n * \\param path_buffer_len Size of path buffer; if the path of the new\n *    node (including space for the null terminator) exceeds the buffer size,\n *    the path string will be truncated to fit.  The actual path of the\n *    new node in the server will not be affected by the truncation.\n *    The path string will always be null-terminated.\n */\nvoid zoo_create_op_init(zoo_op_t *op, const char *path, const char *value,\n        int valuelen,  const struct ACL_vector *acl, int flags, \n        char *path_buffer, int path_buffer_len);\n\n/**\n * \\brief zoo_delete_op_init.\n *\n * This function initializes a zoo_op_t with the arguments for a ZOO_DELETE_OP.\n *\n * \\param op A pointer to the zoo_op_t to be initialized.\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param version the expected version of the node. The function will fail if the\n *    actual version of the node does not match the expected version.\n *  If -1 is used the version check will not take place. \n */\nvoid zoo_delete_op_init(zoo_op_t *op, const char *path, int version);\n\n/**\n * \\brief zoo_set_op_init.\n *\n * This function initializes an zoo_op_t with the arguments for a ZOO_SETDATA_OP.\n *\n * \\param op A pointer to the zoo_op_t to be initialized.\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param buffer the buffer holding data to be written to the node.\n * \\param buflen the number of bytes from buffer to write. To set NULL as data \n * use buffer as NULL and buflen as -1.\n * \\param version the expected version of the node. The function will fail if \n * the actual version of the node does not match the expected version. If -1 is \n * used the version check will not take place. \n */\nvoid zoo_set_op_init(zoo_op_t *op, const char *path, const char *buffer, \n        int buflen, int version, struct Stat *stat);\n\n/**\n * \\brief zoo_check_op_init.\n *\n * This function initializes an zoo_op_t with the arguments for a ZOO_CHECK_OP.\n *\n * \\param op A pointer to the zoo_op_t to be initialized.\n * \\param path The name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param version the expected version of the node. The function will fail if the\n *    actual version of the node does not match the expected version.\n */\nvoid zoo_check_op_init(zoo_op_t *op, const char *path, int version);\n\n/**\n * \\brief zoo_op_result structure.\n *\n * This structure holds the result for an op submitted as part of a multi_op\n * via \\ref zoo_multi or \\ref zoo_amulti.\n */\ntypedef struct zoo_op_result {\n    int err;\n    char *value;\n\tint valuelen;\n    struct Stat *stat;\n} zoo_op_result_t; \n\n/**\n * \\brief signature of a watch function.\n * \n * There are two ways to receive watch notifications: legacy and watcher object.\n * <p>\n * The legacy style, an application wishing to receive events from ZooKeeper must \n * first implement a function with this signature and pass a pointer to the function \n * to \\ref zookeeper_init. Next, the application sets a watch by calling one of \n * the getter API that accept the watch integer flag (for example, \\ref zoo_aexists, \n * \\ref zoo_get, etc).\n * <p>\n * The watcher object style uses an instance of a \"watcher object\" which in \n * the C world is represented by a pair: a pointer to a function implementing this\n * signature and a pointer to watcher context -- handback user-specific data. \n * When a watch is triggered this function will be called along with \n * the watcher context. An application wishing to use this style must use\n * the getter API functions with the \"w\" prefix in their names (for example, \\ref\n * zoo_awexists, \\ref zoo_wget, etc).\n * \n * \\param zh zookeeper handle\n * \\param type event type. This is one of the *_EVENT constants. \n * \\param state connection state. The state value will be one of the *_STATE constants.\n * \\param path znode path for which the watcher is triggered. NULL if the event \n * type is ZOO_SESSION_EVENT\n * \\param watcherCtx watcher context.\n */\ntypedef void (*watcher_fn)(zhandle_t *zh, int type, \n        int state, const char *path,void *watcherCtx);\n\n/**\n * \\brief create a handle to used communicate with zookeeper.\n * \n * This method creates a new handle and a zookeeper session that corresponds\n * to that handle. Session establishment is asynchronous, meaning that the\n * session should not be considered established until (and unless) an\n * event of state ZOO_CONNECTED_STATE is received.\n * \\param host comma separated host:port pairs, each corresponding to a zk\n *   server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"\n * \\param fn the global watcher callback function. When notifications are\n *   triggered this function will be invoked.\n * \\param clientid the id of a previously established session that this\n *   client will be reconnecting to. Pass 0 if not reconnecting to a previous\n *   session. Clients can access the session id of an established, valid,\n *   connection by calling \\ref zoo_client_id. If the session corresponding to\n *   the specified clientid has expired, or if the clientid is invalid for \n *   any reason, the returned zhandle_t will be invalid -- the zhandle_t \n *   state will indicate the reason for failure (typically\n *   ZOO_EXPIRED_SESSION_STATE).\n * \\param context the handback object that will be associated with this instance \n *   of zhandle_t. Application can access it (for example, in the watcher \n *   callback) using \\ref zoo_get_context. The object is not used by zookeeper \n *   internally and can be null.\n * \\param flags reserved for future use. Should be set to zero.\n * \\return a pointer to the opaque zhandle structure. If it fails to create \n * a new zhandle the function returns NULL and the errno variable \n * indicates the reason.\n */\nZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,\n  int recv_timeout, const clientid_t *clientid, void *context, int flags);\n\n/**\n * \\brief close the zookeeper handle and free up any resources.\n * \n * After this call, the client session will no longer be valid. The function\n * will flush any outstanding send requests before return. As a result it may \n * block.\n *\n * This method should only be called only once on a zookeeper handle. Calling\n * twice will cause undefined (and probably undesirable behavior). Calling any other\n * zookeeper method after calling close is undefined behaviour and should be avoided.\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\return a result code. Regardless of the error code returned, the zhandle \n * will be destroyed and all resources freed. \n *\n * ZOK - success\n * ZBADARGUMENTS - invalid input parameters\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n * ZOPERATIONTIMEOUT - failed to flush the buffers within the specified timeout.\n * ZCONNECTIONLOSS - a network error occurred while attempting to send request to server\n * ZSYSTEMERROR -- a system (OS) error occurred; it's worth checking errno to get details\n */\nZOOAPI int zookeeper_close(zhandle_t *zh);\n\n/**\n * \\brief return the client session id, only valid if the connections\n * is currently connected (ie. last watcher state is ZOO_CONNECTED_STATE)\n */\nZOOAPI const clientid_t *zoo_client_id(zhandle_t *zh);\n\n/**\n * \\brief return the timeout for this session, only valid if the connections\n * is currently connected (ie. last watcher state is ZOO_CONNECTED_STATE). This\n * value may change after a server re-connect.\n */\nZOOAPI int zoo_recv_timeout(zhandle_t *zh);\n\n/**\n * \\brief return the context for this handle.\n */\nZOOAPI const void *zoo_get_context(zhandle_t *zh);\n\n/**\n * \\brief set the context for this handle.\n */\nZOOAPI void zoo_set_context(zhandle_t *zh, void *context);\n\n/**\n * \\brief set a watcher function\n * \\return previous watcher function\n */\nZOOAPI watcher_fn zoo_set_watcher(zhandle_t *zh,watcher_fn newFn);\n\n/**\n * \\brief returns the socket address for the current connection\n * \\return socket address of the connected host or NULL on failure, only valid if the\n * connection is current connected\n */\nZOOAPI struct sockaddr* zookeeper_get_connected_host(zhandle_t *zh,\n        struct sockaddr *addr, socklen_t *addr_len);\n\n#ifndef THREADED\n/**\n * \\brief Returns the events that zookeeper is interested in.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param fd is the file descriptor of interest\n * \\param interest is an or of the ZOOKEEPER_WRITE and ZOOKEEPER_READ flags to\n *    indicate the I/O of interest on fd.\n * \\param tv a timeout value to be used with select/poll system call\n * \\return a result code.\n * ZOK - success\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZCONNECTIONLOSS - a network error occurred while attempting to establish \n * a connection to the server\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n * ZOPERATIONTIMEOUT - hasn't received anything from the server for 2/3 of the\n * timeout value specified in zookeeper_init()\n * ZSYSTEMERROR -- a system (OS) error occurred; it's worth checking errno to get details\n */\n#ifdef WIN32\nZOOAPI int zookeeper_interest(zhandle_t *zh, SOCKET *fd, int *interest, \n\tstruct timeval *tv);\n#else\nZOOAPI int zookeeper_interest(zhandle_t *zh, int *fd, int *interest, \n\tstruct timeval *tv);\n#endif\n\n/**\n * \\brief Notifies zookeeper that an event of interest has happened.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param events will be an OR of the ZOOKEEPER_WRITE and ZOOKEEPER_READ flags.\n * \\return a result code. \n * ZOK - success\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZCONNECTIONLOSS - a network error occurred while attempting to send request to server\n * ZSESSIONEXPIRED - connection attempt failed -- the session's expired\n * ZAUTHFAILED - authentication request failed, e.i. invalid credentials\n * ZRUNTIMEINCONSISTENCY - a server response came out of order\n * ZSYSTEMERROR -- a system (OS) error occurred; it's worth checking errno to get details\n * ZNOTHING -- not an error; simply indicates that there no more data from the server \n *              to be processed (when called with ZOOKEEPER_READ flag).\n */\nZOOAPI int zookeeper_process(zhandle_t *zh, int events);\n#endif\n\n/**\n * \\brief signature of a completion function for a call that returns void.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*void_completion_t)(int rc, const void *data);\n\n/**\n * \\brief signature of a completion function that returns a Stat structure.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param stat a pointer to the stat information for the node involved in\n *   this function. If a non zero error code is returned, the content of\n *   stat is undefined. The programmer is NOT responsible for freeing stat.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*stat_completion_t)(int rc, const struct Stat *stat,\n        const void *data);\n\n/**\n * \\brief signature of a completion function that returns data.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param value the value of the information returned by the asynchronous call.\n *   If a non zero error code is returned, the content of value is undefined.\n *   The programmer is NOT responsible for freeing value.\n * \\param value_len the number of bytes in value.\n * \\param stat a pointer to the stat information for the node involved in\n *   this function. If a non zero error code is returned, the content of\n *   stat is undefined. The programmer is NOT responsible for freeing stat.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*data_completion_t)(int rc, const char *value, int value_len,\n        const struct Stat *stat, const void *data);\n\n/**\n * \\brief signature of a completion function that returns a list of strings.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param strings a pointer to the structure containng the list of strings of the\n *   names of the children of a node. If a non zero error code is returned,\n *   the content of strings is undefined. The programmer is NOT responsible\n *   for freeing strings.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*strings_completion_t)(int rc,\n        const struct String_vector *strings, const void *data);\n\n/**\n * \\brief signature of a completion function that returns a list of strings and stat.\n * .\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param strings a pointer to the structure containng the list of strings of the\n *   names of the children of a node. If a non zero error code is returned,\n *   the content of strings is undefined. The programmer is NOT responsible\n *   for freeing strings.\n * \\param stat a pointer to the stat information for the node involved in\n *   this function. If a non zero error code is returned, the content of\n *   stat is undefined. The programmer is NOT responsible for freeing stat.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*strings_stat_completion_t)(int rc,\n        const struct String_vector *strings, const struct Stat *stat,\n        const void *data);\n\n/**\n * \\brief signature of a completion function that returns a list of strings.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param value the value of the string returned.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void\n        (*string_completion_t)(int rc, const char *value, const void *data);\n\n/**\n * \\brief signature of a completion function that returns an ACL.\n * \n * This method will be invoked at the end of a asynchronous call and also as \n * a result of connection loss or timeout.\n * \\param rc the error code of the call. Connection loss/timeout triggers \n * the completion with one of the following error codes:\n * ZCONNECTIONLOSS -- lost connection to the server\n * ZOPERATIONTIMEOUT -- connection timed out\n * Data related events trigger the completion with error codes listed the \n * Exceptions section of the documentation of the function that initiated the\n * call. (Zero indicates call was successful.)\n * \\param acl a pointer to the structure containng the ACL of a node. If a non \n *   zero error code is returned, the content of strings is undefined. The\n *   programmer is NOT responsible for freeing acl.\n * \\param stat a pointer to the stat information for the node involved in\n *   this function. If a non zero error code is returned, the content of\n *   stat is undefined. The programmer is NOT responsible for freeing stat.\n * \\param data the pointer that was passed by the caller when the function\n *   that this completion corresponds to was invoked. The programmer\n *   is responsible for any memory freeing associated with the data\n *   pointer.\n */\ntypedef void (*acl_completion_t)(int rc, struct ACL_vector *acl,\n        struct Stat *stat, const void *data);\n\n/**\n * \\brief get the state of the zookeeper connection.\n * \n * The return value will be one of the \\ref State Consts.\n */\nZOOAPI int zoo_state(zhandle_t *zh);\n\n/**\n * \\brief create a node.\n * \n * This method will create a node in ZooKeeper. A node can only be created if\n * it does not already exists. The Create Flags affect the creation of nodes.\n * If ZOO_EPHEMERAL flag is set, the node will automatically get removed if the\n * client session goes away. If the ZOO_SEQUENCE flag is set, a unique\n * monotonically increasing sequence number is appended to the path name. The\n * sequence number is always fixed length of 10 digits, 0 padded.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path The name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param value The data to be stored in the node.\n * \\param valuelen The number of bytes in data.\n * \\param acl The initial ACL of the node. The ACL must not be null or empty.\n * \\param flags this parameter can be set to 0 for normal create or an OR\n *    of the Create Flags\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the parent node does not exist.\n * ZNODEEXISTS the node already exists\n * ZNOAUTH the client does not have permission.\n * ZNOCHILDRENFOREPHEMERALS cannot create children of ephemeral nodes.\n * \\param data The data that will be passed to the completion routine when the \n * function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_acreate(zhandle_t *zh, const char *path, const char *value, \n        int valuelen, const struct ACL_vector *acl, int flags,\n        string_completion_t completion, const void *data);\n\n/**\n * \\brief delete a node in zookeeper.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param version the expected version of the node. The function will fail if the\n *    actual version of the node does not match the expected version.\n *  If -1 is used the version check will not take place. \n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADVERSION expected version does not match actual version.\n * ZNOTEMPTY children are present; node cannot be deleted.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_adelete(zhandle_t *zh, const char *path, int version, \n        void_completion_t completion, const void *data);\n\n/**\n * \\brief checks the existence of a node in zookeeper.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify the \n * client if the node changes. The watch will be set even if the node does not \n * exist. This allows clients to watch for nodes to appear.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when the \n * function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aexists(zhandle_t *zh, const char *path, int watch, \n        stat_completion_t completion, const void *data);\n\n/**\n * \\brief checks the existence of a node in zookeeper.\n * \n * This function is similar to \\ref zoo_axists except it allows one specify \n * a watcher object - a function pointer and associated context. The function\n * will be called once the watch has fired. The associated context data will be \n * passed to the function as the watcher context parameter. \n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null a watch will set on the specified znode on the server.\n * The watch will be set even if the node does not exist. This allows clients \n * to watch for nodes to appear.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when the \n * function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_awexists(zhandle_t *zh, const char *path, \n        watcher_fn watcher, void* watcherCtx, \n        stat_completion_t completion, const void *data);\n\n/**\n * \\brief gets the data associated with a node.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either in ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aget(zhandle_t *zh, const char *path, int watch, \n        data_completion_t completion, const void *data);\n\n/**\n * \\brief gets the data associated with a node.\n * \n * This function is similar to \\ref zoo_aget except it allows one specify \n * a watcher object rather than a boolean watch flag. \n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either in ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_awget(zhandle_t *zh, const char *path, \n        watcher_fn watcher, void* watcherCtx, \n        data_completion_t completion, const void *data);\n\n/**\n * \\brief sets the data associated with a node.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param buffer the buffer holding data to be written to the node.\n * \\param buflen the number of bytes from buffer to write.\n * \\param version the expected version of the node. The function will fail if \n * the actual version of the node does not match the expected version. If -1 is \n * used the version check will not take place. * completion: If null, \n * the function will execute synchronously. Otherwise, the function will return \n * immediately and invoke the completion routine when the request completes.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADVERSION expected version does not match actual version.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aset(zhandle_t *zh, const char *path, const char *buffer, int buflen, \n        int version, stat_completion_t completion, const void *data);\n\n/**\n * \\brief lists the children of a node.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aget_children(zhandle_t *zh, const char *path, int watch, \n        strings_completion_t completion, const void *data);\n\n/**\n * \\brief lists the children of a node.\n * \n * This function is similar to \\ref zoo_aget_children except it allows one specify \n * a watcher object rather than a boolean watch flag.\n *  \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_awget_children(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx, \n        strings_completion_t completion, const void *data);\n\n/**\n * \\brief lists the children of a node, and get the parent stat.\n * \n * This function is new in version 3.3.0\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aget_children2(zhandle_t *zh, const char *path, int watch, \n        strings_stat_completion_t completion, const void *data);\n\n/**\n * \\brief lists the children of a node, and get the parent stat.\n * \n * This function is similar to \\ref zoo_aget_children2 except it allows one specify \n * a watcher object rather than a boolean watch flag.\n *  \n * This function is new in version 3.3.0\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_awget_children2(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx, \n        strings_stat_completion_t completion, const void *data);\n\n/**\n * \\brief Flush leader channel.\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes\n * separating ancestors of the node.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when\n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\n\nZOOAPI int zoo_async(zhandle_t *zh, const char *path, \n        string_completion_t completion, const void *data);\n\n\n/**\n * \\brief gets the acl associated with a node.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aget_acl(zhandle_t *zh, const char *path, acl_completion_t completion, \n        const void *data);\n\n/**\n * \\brief sets the acl associated with a node.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param buffer the buffer holding the acls to be written to the node.\n * \\param buflen the number of bytes from buffer to write.\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with one of the following codes passed in as the rc argument:\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZINVALIDACL invalid ACL specified\n * ZBADVERSION expected version does not match actual version.\n * \\param data the data that will be passed to the completion routine when \n * the function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_aset_acl(zhandle_t *zh, const char *path, int version, \n        struct ACL_vector *acl, void_completion_t, const void *data);\n\n/**\n * \\brief atomically commits multiple zookeeper operations.\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param count the number of operations\n * \\param ops an array of operations to commit\n * \\param results an array to hold the results of the operations\n * \\param completion the routine to invoke when the request completes. The completion\n * will be triggered with any of the error codes that can that can be returned by the \n * ops supported by a multi op (see \\ref zoo_acreate, \\ref zoo_adelete, \\ref zoo_aset).\n * \\param data the data that will be passed to the completion routine when\n * the function completes.\n * \\return the return code for the function call. This can be any of the\n * values that can be returned by the ops supported by a multi op (see\n * \\ref zoo_acreate, \\ref zoo_adelete, \\ref zoo_aset).\n */\nZOOAPI int zoo_amulti(zhandle_t *zh, int count, const zoo_op_t *ops, \n        zoo_op_result_t *results, void_completion_t, const void *data);\n\n/**\n * \\brief return an error string.\n * \n * \\param return code\n * \\return string corresponding to the return code\n */\nZOOAPI const char* zerror(int c);\n\n/**\n * \\brief specify application credentials.\n * \n * The application calls this function to specify its credentials for purposes\n * of authentication. The server will use the security provider specified by \n * the scheme parameter to authenticate the client connection. If the \n * authentication request has failed:\n * - the server connection is dropped\n * - the watcher is called with the ZOO_AUTH_FAILED_STATE value as the state \n * parameter.\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param scheme the id of authentication scheme. Natively supported:\n * \"digest\" password-based authentication\n * \\param cert application credentials. The actual value depends on the scheme.\n * \\param certLen the length of the data parameter\n * \\param completion the routine to invoke when the request completes. One of \n * the following result codes may be passed into the completion callback:\n * ZOK operation completed successfully\n * ZAUTHFAILED authentication failed \n * \\param data the data that will be passed to the completion routine when the \n * function completes.\n * \\return ZOK on success or one of the following errcodes on failure:\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n * ZSYSTEMERROR - a system error occurred\n */\nZOOAPI int zoo_add_auth(zhandle_t *zh,const char* scheme,const char* cert, \n\tint certLen, void_completion_t completion, const void *data);\n\n/**\n * \\brief checks if the current zookeeper connection state can't be recovered.\n * \n *  The application must close the zhandle and try to reconnect.\n * \n * \\param zh the zookeeper handle (see \\ref zookeeper_init)\n * \\return ZINVALIDSTATE if connection is unrecoverable\n */\nZOOAPI int is_unrecoverable(zhandle_t *zh);\n\n/**\n * \\brief sets the debugging level for the library \n */\nZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);\n\n/**\n * \\brief sets the stream to be used by the library for logging \n * \n * The zookeeper library uses stderr as its default log stream. Application\n * must make sure the stream is writable. Passing in NULL resets the stream \n * to its default value (stderr).\n */\nZOOAPI void zoo_set_log_stream(FILE* logStream);\n\n/**\n * \\brief enable/disable quorum endpoint order randomization\n * \n * Note: typically this method should NOT be used outside of testing.\n *\n * If passed a non-zero value, will make the client connect to quorum peers\n * in the order as specified in the zookeeper_init() call.\n * A zero value causes zookeeper_init() to permute the peer endpoints\n * which is good for more even client connection distribution among the \n * quorum peers.\n */\nZOOAPI void zoo_deterministic_conn_order(int yesOrNo);\n\n/**\n * \\brief create a node synchronously.\n * \n * This method will create a node in ZooKeeper. A node can only be created if\n * it does not already exists. The Create Flags affect the creation of nodes.\n * If ZOO_EPHEMERAL flag is set, the node will automatically get removed if the\n * client session goes away. If the ZOO_SEQUENCE flag is set, a unique\n * monotonically increasing sequence number is appended to the path name.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path The name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param value The data to be stored in the node.\n * \\param valuelen The number of bytes in data. To set the data to be NULL use\n * value as NULL and valuelen as -1.\n * \\param acl The initial ACL of the node. The ACL must not be null or empty.\n * \\param flags this parameter can be set to 0 for normal create or an OR\n *    of the Create Flags\n * \\param path_buffer Buffer which will be filled with the path of the\n *    new node (this might be different than the supplied path\n *    because of the ZOO_SEQUENCE flag).  The path string will always be\n *    null-terminated. This parameter may be NULL if path_buffer_len = 0.\n * \\param path_buffer_len Size of path buffer; if the path of the new\n *    node (including space for the null terminator) exceeds the buffer size,\n *    the path string will be truncated to fit.  The actual path of the\n *    new node in the server will not be affected by the truncation.\n *    The path string will always be null-terminated.\n * \\return  one of the following codes are returned:\n * ZOK operation completed successfully\n * ZNONODE the parent node does not exist.\n * ZNODEEXISTS the node already exists\n * ZNOAUTH the client does not have permission.\n * ZNOCHILDRENFOREPHEMERALS cannot create children of ephemeral nodes.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_create(zhandle_t *zh, const char *path, const char *value,\n        int valuelen, const struct ACL_vector *acl, int flags,\n        char *path_buffer, int path_buffer_len);\n\n/**\n * \\brief delete a node in zookeeper synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param version the expected version of the node. The function will fail if the\n *    actual version of the node does not match the expected version.\n *  If -1 is used the version check will not take place. \n * \\return one of the following values is returned.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADVERSION expected version does not match actual version.\n * ZNOTEMPTY children are present; node cannot be deleted.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_delete(zhandle_t *zh, const char *path, int version);\n\n\n/**\n * \\brief checks the existence of a node in zookeeper synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify the \n * client if the node changes. The watch will be set even if the node does not \n * exist. This allows clients to watch for nodes to appear.\n * \\param the return stat value of the node.\n * \\return  return code of the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat);\n\n/**\n * \\brief checks the existence of a node in zookeeper synchronously.\n * \n * This function is similar to \\ref zoo_exists except it allows one specify \n * a watcher object rather than a boolean watch flag.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null a watch will set on the specified znode on the server.\n * The watch will be set even if the node does not exist. This allows clients \n * to watch for nodes to appear.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param the return stat value of the node.\n * \\return  return code of the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_wexists(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx, struct Stat *stat);\n\n/**\n * \\brief gets the data associated with a node synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param buffer the buffer holding the node data returned by the server\n * \\param buffer_len is the size of the buffer pointed to by the buffer parameter.\n * It'll be set to the actual data length upon return. If the data is NULL, length is -1.\n * \\param stat if not NULL, will hold the value of stat for the path on return.\n * \\return return value of the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either in ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer,   \n                   int* buffer_len, struct Stat *stat);\n\n/**\n * \\brief gets the data associated with a node synchronously.\n * \n * This function is similar to \\ref zoo_get except it allows one specify \n * a watcher object rather than a boolean watch flag.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param buffer the buffer holding the node data returned by the server\n * \\param buffer_len is the size of the buffer pointed to by the buffer parameter.\n * It'll be set to the actual data length upon return. If the data is NULL, length is -1.\n * \\param stat if not NULL, will hold the value of stat for the path on return.\n * \\return return value of the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either in ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_wget(zhandle_t *zh, const char *path, \n        watcher_fn watcher, void* watcherCtx, \n        char *buffer, int* buffer_len, struct Stat *stat);\n\n/**\n * \\brief sets the data associated with a node. See zoo_set2 function if\n * you require access to the stat information associated with the znode.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param buffer the buffer holding data to be written to the node.\n * \\param buflen the number of bytes from buffer to write. To set NULL as data \n * use buffer as NULL and buflen as -1.\n * \\param version the expected version of the node. The function will fail if \n * the actual version of the node does not match the expected version. If -1 is \n * used the version check will not take place. \n * \\return the return code for the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADVERSION expected version does not match actual version.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_set(zhandle_t *zh, const char *path, const char *buffer,\n                   int buflen, int version);\n\n/**\n * \\brief sets the data associated with a node. This function is the same\n * as zoo_set except that it also provides access to stat information\n * associated with the znode.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param buffer the buffer holding data to be written to the node.\n * \\param buflen the number of bytes from buffer to write. To set NULL as data\n * use buffer as NULL and buflen as -1.\n * \\param version the expected version of the node. The function will fail if \n * the actual version of the node does not match the expected version. If -1 is \n * used the version check will not take place. \n * \\param stat if not NULL, will hold the value of stat for the path on return.\n * \\return the return code for the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADVERSION expected version does not match actual version.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_set2(zhandle_t *zh, const char *path, const char *buffer,\n                   int buflen, int version, struct Stat *stat);\n\n/**\n * \\brief lists the children of a node synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param strings return value of children paths.\n * \\return the return code of the function.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,\n                            struct String_vector *strings);\n\n/**\n * \\brief lists the children of a node synchronously.\n * \n * This function is similar to \\ref zoo_get_children except it allows one specify \n * a watcher object rather than a boolean watch flag.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param strings return value of children paths.\n * \\return the return code of the function.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_wget_children(zhandle_t *zh, const char *path, \n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings);\n\n/**\n * \\brief lists the children of a node and get its stat synchronously.\n * \n * This function is new in version 3.3.0\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watch if nonzero, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param strings return value of children paths.\n * \\param stat return value of node stat.\n * \\return the return code of the function.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_get_children2(zhandle_t *zh, const char *path, int watch,\n                            struct String_vector *strings, struct Stat *stat);\n\n/**\n * \\brief lists the children of a node and get its stat synchronously.\n * \n * This function is similar to \\ref zoo_get_children except it allows one specify \n * a watcher object rather than a boolean watch flag.\n * \n * This function is new in version 3.3.0\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param watcher if non-null, a watch will be set at the server to notify \n * the client if the node changes.\n * \\param watcherCtx user specific data, will be passed to the watcher callback.\n * Unlike the global context set by \\ref zookeeper_init, this watcher context\n * is associated with the given instance of the watcher only.\n * \\param strings return value of children paths.\n * \\param stat return value of node stat.\n * \\return the return code of the function.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_wget_children2(zhandle_t *zh, const char *path, \n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings, struct Stat *stat);\n\n/**\n * \\brief gets the acl associated with a node synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param acl the return value of acls on the path.\n * \\param stat returns the stat of the path specified.\n * \\return the return code for the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl,\n                       struct Stat *stat);\n\n/**\n * \\brief sets the acl associated with a node synchronously.\n * \n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param path the name of the node. Expressed as a file name with slashes \n * separating ancestors of the node.\n * \\param version the expected version of the path.\n * \\param acl the acl to be set on the path. \n * \\return the return code for the function call.\n * ZOK operation completed successfully\n * ZNONODE the node does not exist.\n * ZNOAUTH the client does not have permission.\n * ZINVALIDACL invalid ACL specified\n * ZBADVERSION expected version does not match actual version.\n * ZBADARGUMENTS - invalid input parameters\n * ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE\n * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory\n */\nZOOAPI int zoo_set_acl(zhandle_t *zh, const char *path, int version,\n                           const struct ACL_vector *acl);\n\n/**\n * \\brief atomically commits multiple zookeeper operations synchronously.\n *\n * \\param zh the zookeeper handle obtained by a call to \\ref zookeeper_init\n * \\param count the number of operations\n * \\param ops an array of operations to commit\n * \\param results an array to hold the results of the operations\n * \\return the return code for the function call. This can be any of the\n * values that can be returned by the ops supported by a multi op (see\n * \\ref zoo_acreate, \\ref zoo_adelete, \\ref zoo_aset).\n */ \nZOOAPI int zoo_multi(zhandle_t *zh, int count, const zoo_op_t *ops, zoo_op_result_t *results);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*ZOOKEEPER_H_*/\n"
  },
  {
    "path": "src/c/include/zookeeper_log.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZK_LOG_H_\n#define ZK_LOG_H_\n\n#include <zookeeper.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern ZOOAPI ZooLogLevel logLevel;\n#define LOGSTREAM getLogStream()\n\n#define LOG_ERROR(x) if(logLevel>=ZOO_LOG_LEVEL_ERROR) \\\n    log_message(ZOO_LOG_LEVEL_ERROR,__LINE__,__func__,format_log_message x)\n#define LOG_WARN(x) if(logLevel>=ZOO_LOG_LEVEL_WARN) \\\n    log_message(ZOO_LOG_LEVEL_WARN,__LINE__,__func__,format_log_message x)\n#define LOG_INFO(x) if(logLevel>=ZOO_LOG_LEVEL_INFO) \\\n    log_message(ZOO_LOG_LEVEL_INFO,__LINE__,__func__,format_log_message x)\n#define LOG_DEBUG(x) if(logLevel==ZOO_LOG_LEVEL_DEBUG) \\\n    log_message(ZOO_LOG_LEVEL_DEBUG,__LINE__,__func__,format_log_message x)\n\nZOOAPI void log_message(ZooLogLevel curLevel, int line,const char* funcName,\n    const char* message);\n\nZOOAPI const char* format_log_message(const char* format,...);\n\nFILE* getLogStream();\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*ZK_LOG_H_*/\n"
  },
  {
    "path": "src/c/include/zookeeper_version.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef ZOOKEEPER_VERSION_H_\n#define ZOOKEEPER_VERSION_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZOO_MAJOR_VERSION 3\n#define ZOO_MINOR_VERSION 4\n#define ZOO_PATCH_VERSION 12\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZOOKEEPER_VERSION_H_ */\n"
  },
  {
    "path": "src/c/src/cli.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * cli.c is a example/sample C client shell for ZooKeeper. It contains\n * basic shell functionality which exercises some of the features of\n * the ZooKeeper C client API. It is not a full fledged client and is\n * not meant for production usage - see the Java client shell for a\n * fully featured shell.\n */\n\n#include <zookeeper.h>\n#include <proto.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#ifndef WIN32\n#include <sys/time.h>\n#include <unistd.h>\n#include <sys/select.h>\n#else\n#include \"winport.h\"\n//#include <io.h> <-- can't include, conflicting definitions of close()\nint read(int _FileHandle, void * _DstBuf, unsigned int _MaxCharCount);\nint write(int _Filehandle, const void * _Buf, unsigned int _MaxCharCount);\n#define ctime_r(tctime, buffer) ctime_s (buffer, 40, tctime)\n#endif\n\n#include <time.h>\n#include <errno.h>\n#include <assert.h>\n\n#ifdef YCA\n#include <yca/yca.h>\n#endif\n\n#define _LL_CAST_ (long long)\n\nstatic zhandle_t *zh;\nstatic clientid_t myid;\nstatic const char *clientIdFile = 0;\nstruct timeval startTime;\nstatic char cmd[1024];\nstatic int batchMode=0;\n\nstatic int to_send=0;\nstatic int sent=0;\nstatic int recvd=0;\n\nstatic int shutdownThisThing=0;\n\nstatic __attribute__ ((unused)) void \nprintProfileInfo(struct timeval start, struct timeval end, int thres,\n                 const char* msg)\n{\n  int delay=(end.tv_sec*1000+end.tv_usec/1000)-\n    (start.tv_sec*1000+start.tv_usec/1000);\n  if(delay>thres)\n    fprintf(stderr,\"%s: execution time=%dms\\n\",msg,delay);\n}\n\nstatic const char* state2String(int state){\n  if (state == 0)\n    return \"CLOSED_STATE\";\n  if (state == ZOO_CONNECTING_STATE)\n    return \"CONNECTING_STATE\";\n  if (state == ZOO_ASSOCIATING_STATE)\n    return \"ASSOCIATING_STATE\";\n  if (state == ZOO_CONNECTED_STATE)\n    return \"CONNECTED_STATE\";\n  if (state == ZOO_EXPIRED_SESSION_STATE)\n    return \"EXPIRED_SESSION_STATE\";\n  if (state == ZOO_AUTH_FAILED_STATE)\n    return \"AUTH_FAILED_STATE\";\n\n  return \"INVALID_STATE\";\n}\n\nstatic const char* type2String(int state){\n  if (state == ZOO_CREATED_EVENT)\n    return \"CREATED_EVENT\";\n  if (state == ZOO_DELETED_EVENT)\n    return \"DELETED_EVENT\";\n  if (state == ZOO_CHANGED_EVENT)\n    return \"CHANGED_EVENT\";\n  if (state == ZOO_CHILD_EVENT)\n    return \"CHILD_EVENT\";\n  if (state == ZOO_SESSION_EVENT)\n    return \"SESSION_EVENT\";\n  if (state == ZOO_NOTWATCHING_EVENT)\n    return \"NOTWATCHING_EVENT\";\n\n  return \"UNKNOWN_EVENT_TYPE\";\n}\n\nvoid watcher(zhandle_t *zzh, int type, int state, const char *path,\n             void* context)\n{\n    /* Be careful using zh here rather than zzh - as this may be mt code\n     * the client lib may call the watcher before zookeeper_init returns */\n\n    fprintf(stderr, \"Watcher %s state = %s\", type2String(type), state2String(state));\n    if (path && strlen(path) > 0) {\n      fprintf(stderr, \" for path %s\", path);\n    }\n    fprintf(stderr, \"\\n\");\n\n    if (type == ZOO_SESSION_EVENT) {\n        if (state == ZOO_CONNECTED_STATE) {\n            const clientid_t *id = zoo_client_id(zzh);\n            if (myid.client_id == 0 || myid.client_id != id->client_id) {\n                myid = *id;\n                fprintf(stderr, \"Got a new session id: 0x%llx\\n\",\n                        _LL_CAST_ myid.client_id);\n                if (clientIdFile) {\n                    FILE *fh = fopen(clientIdFile, \"w\");\n                    if (!fh) {\n                        perror(clientIdFile);\n                    } else {\n                        int rc = fwrite(&myid, sizeof(myid), 1, fh);\n                        if (rc != sizeof(myid)) {\n                            perror(\"writing client id\");\n                        }\n                        fclose(fh);\n                    }\n                }\n            }\n        } else if (state == ZOO_AUTH_FAILED_STATE) {\n            fprintf(stderr, \"Authentication failure. Shutting down...\\n\");\n            zookeeper_close(zzh);\n            shutdownThisThing=1;\n            zh=0;\n        } else if (state == ZOO_EXPIRED_SESSION_STATE) {\n            fprintf(stderr, \"Session expired. Shutting down...\\n\");\n            zookeeper_close(zzh);\n            shutdownThisThing=1;\n            zh=0;\n        }\n    }\n}\n\nvoid dumpStat(const struct Stat *stat) {\n    char tctimes[40];\n    char tmtimes[40];\n    time_t tctime;\n    time_t tmtime;\n\n    if (!stat) {\n        fprintf(stderr,\"null\\n\");\n        return;\n    }\n    tctime = stat->ctime/1000;\n    tmtime = stat->mtime/1000;\n       \n    ctime_r(&tmtime, tmtimes);\n    ctime_r(&tctime, tctimes);\n       \n    fprintf(stderr, \"\\tctime = %s\\tczxid=%llx\\n\"\n    \"\\tmtime=%s\\tmzxid=%llx\\n\"\n    \"\\tversion=%x\\taversion=%x\\n\"\n    \"\\tephemeralOwner = %llx\\n\",\n     tctimes, _LL_CAST_ stat->czxid, tmtimes,\n    _LL_CAST_ stat->mzxid,\n    (unsigned int)stat->version, (unsigned int)stat->aversion,\n    _LL_CAST_ stat->ephemeralOwner);\n}\n\nvoid my_string_completion(int rc, const char *name, const void *data) {\n    fprintf(stderr, \"[%s]: rc = %d\\n\", (char*)(data==0?\"null\":data), rc);\n    if (!rc) {\n        fprintf(stderr, \"\\tname = %s\\n\", name);\n    }\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_string_completion_free_data(int rc, const char *name, const void *data) {\n    my_string_completion(rc, name, data);\n    free((void*)data);\n}\n\nvoid my_data_completion(int rc, const char *value, int value_len,\n        const struct Stat *stat, const void *data) {\n    struct timeval tv;\n    int sec;\n    int usec;\n    gettimeofday(&tv, 0);\n    sec = tv.tv_sec - startTime.tv_sec;\n    usec = tv.tv_usec - startTime.tv_usec;\n    fprintf(stderr, \"time = %d msec\\n\", sec*1000 + usec/1000);\n    fprintf(stderr, \"%s: rc = %d\\n\", (char*)data, rc);\n    if (value) {\n        fprintf(stderr, \" value_len = %d\\n\", value_len);\n        assert(write(2, value, value_len) == value_len);\n    }\n    fprintf(stderr, \"\\nStat:\\n\");\n    dumpStat(stat);\n    free((void*)data);\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_silent_data_completion(int rc, const char *value, int value_len,\n        const struct Stat *stat, const void *data) {\n    recvd++;\n    fprintf(stderr, \"Data completion %s rc = %d\\n\",(char*)data,rc);\n    free((void*)data);\n    if (recvd==to_send) {\n        fprintf(stderr,\"Recvd %d responses for %d requests sent\\n\",recvd,to_send);\n        if(batchMode)\n          shutdownThisThing=1;\n    }\n}\n\nvoid my_strings_completion(int rc, const struct String_vector *strings,\n        const void *data) {\n    struct timeval tv;\n    int sec;\n    int usec;\n    int i;\n\n    gettimeofday(&tv, 0);\n    sec = tv.tv_sec - startTime.tv_sec;\n    usec = tv.tv_usec - startTime.tv_usec;\n    fprintf(stderr, \"time = %d msec\\n\", sec*1000 + usec/1000);\n    fprintf(stderr, \"%s: rc = %d\\n\", (char*)data, rc);\n    if (strings)\n        for (i=0; i < strings->count; i++) {\n            fprintf(stderr, \"\\t%s\\n\", strings->data[i]);\n        }\n    free((void*)data);\n    gettimeofday(&tv, 0);\n    sec = tv.tv_sec - startTime.tv_sec;\n    usec = tv.tv_usec - startTime.tv_usec;\n    fprintf(stderr, \"time = %d msec\\n\", sec*1000 + usec/1000);\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_strings_stat_completion(int rc, const struct String_vector *strings,\n        const struct Stat *stat, const void *data) {\n    my_strings_completion(rc, strings, data);\n    dumpStat(stat);\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_void_completion(int rc, const void *data) {\n    fprintf(stderr, \"%s: rc = %d\\n\", (char*)data, rc);\n    free((void*)data);\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_stat_completion(int rc, const struct Stat *stat, const void *data) {\n    fprintf(stderr, \"%s: rc = %d Stat:\\n\", (char*)data, rc);\n    dumpStat(stat);\n    free((void*)data);\n    if(batchMode)\n      shutdownThisThing=1;\n}\n\nvoid my_silent_stat_completion(int rc, const struct Stat *stat,\n        const void *data) {\n    //    fprintf(stderr, \"State completion: [%s] rc = %d\\n\", (char*)data, rc);\n    sent++;\n    free((void*)data);\n}\n\nstatic void sendRequest(const char* data) {\n    zoo_aset(zh, \"/od\", data, strlen(data), -1, my_silent_stat_completion,\n            strdup(\"/od\"));\n    zoo_aget(zh, \"/od\", 1, my_silent_data_completion, strdup(\"/od\"));\n}\n\nvoid od_completion(int rc, const struct Stat *stat, const void *data) {\n    int i;\n    fprintf(stderr, \"od command response: rc = %d Stat:\\n\", rc);\n    dumpStat(stat);\n    // send a whole bunch of requests\n    recvd=0;\n    sent=0;\n    to_send=200;\n    for (i=0; i<to_send; i++) {\n        char buf[4096*16];\n        memset(buf, -1, sizeof(buf)-1);\n        buf[sizeof(buf)-1]=0;\n        sendRequest(buf);\n    }\n}\n\nint startsWith(const char *line, const char *prefix) {\n    int len = strlen(prefix);\n    return strncmp(line, prefix, len) == 0;\n}\n\nstatic const char *hostPort;\nstatic int verbose = 0;\n\nvoid processline(char *line) {\n    int rc;\n    int async = ((line[0] == 'a') && !(startsWith(line, \"addauth \")));\n    if (async) {\n        line++;\n    }\n    if (startsWith(line, \"help\")) {\n      fprintf(stderr, \"    create [+[e|s]] <path>\\n\");\n      fprintf(stderr, \"    delete <path>\\n\");\n      fprintf(stderr, \"    set <path> <data>\\n\");\n      fprintf(stderr, \"    get <path>\\n\");\n      fprintf(stderr, \"    ls <path>\\n\");\n      fprintf(stderr, \"    ls2 <path>\\n\");\n      fprintf(stderr, \"    sync <path>\\n\");\n      fprintf(stderr, \"    exists <path>\\n\");\n      fprintf(stderr, \"    wexists <path>\\n\");\n      fprintf(stderr, \"    myid\\n\");\n      fprintf(stderr, \"    verbose\\n\");\n      fprintf(stderr, \"    addauth <id> <scheme>\\n\");\n      fprintf(stderr, \"    quit\\n\");\n      fprintf(stderr, \"\\n\");\n      fprintf(stderr, \"    prefix the command with the character 'a' to run the command asynchronously.\\n\");\n      fprintf(stderr, \"    run the 'verbose' command to toggle verbose logging.\\n\");\n      fprintf(stderr, \"    i.e. 'aget /foo' to get /foo asynchronously\\n\");\n    } else if (startsWith(line, \"verbose\")) {\n      if (verbose) {\n        verbose = 0;\n        zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);\n        fprintf(stderr, \"logging level set to WARN\\n\");\n      } else {\n        verbose = 1;\n        zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);\n        fprintf(stderr, \"logging level set to DEBUG\\n\");\n      }\n    } else if (startsWith(line, \"get \")) {\n        line += 4;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n               \n        rc = zoo_aget(zh, line, 1, my_data_completion, strdup(line));\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"set \")) {\n        char *ptr;\n        line += 4;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        ptr = strchr(line, ' ');\n        if (!ptr) {\n            fprintf(stderr, \"No data found after path\\n\");\n            return;\n        }\n        *ptr = '\\0';\n        ptr++;\n        if (async) {\n            rc = zoo_aset(zh, line, ptr, strlen(ptr), -1, my_stat_completion,\n                    strdup(line));\n        } else {\n            struct Stat stat;\n            rc = zoo_set2(zh, line, ptr, strlen(ptr), -1, &stat);\n        }\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"ls \")) {\n        line += 3;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        gettimeofday(&startTime, 0);\n        rc= zoo_aget_children(zh, line, 1, my_strings_completion, strdup(line));\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"ls2 \")) {\n        line += 4;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        gettimeofday(&startTime, 0);\n        rc= zoo_aget_children2(zh, line, 1, my_strings_stat_completion, strdup(line));\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"create \")) {\n        int flags = 0;\n        line += 7;\n        if (line[0] == '+') {\n            line++;\n            if (line[0] == 'e') {\n                flags |= ZOO_EPHEMERAL;\n                line++;\n            }\n            if (line[0] == 's') {\n                flags |= ZOO_SEQUENCE;\n                line++;\n            }\n            line++;\n        }\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        fprintf(stderr, \"Creating [%s] node\\n\", line);\n//        {\n//            struct ACL _CREATE_ONLY_ACL_ACL[] = {{ZOO_PERM_CREATE, ZOO_ANYONE_ID_UNSAFE}};\n//            struct ACL_vector CREATE_ONLY_ACL = {1,_CREATE_ONLY_ACL_ACL};\n//            rc = zoo_acreate(zh, line, \"new\", 3, &CREATE_ONLY_ACL, flags,\n//                    my_string_completion, strdup(line));\n//        }\n        rc = zoo_acreate(zh, line, \"new\", 3, &ZOO_OPEN_ACL_UNSAFE, flags,\n                my_string_completion_free_data, strdup(line));\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"delete \")) {\n        line += 7;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        if (async) {\n            rc = zoo_adelete(zh, line, -1, my_void_completion, strdup(line));\n        } else {\n            rc = zoo_delete(zh, line, -1);\n        }\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"sync \")) {\n        line += 5;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n        rc = zoo_async(zh, line, my_string_completion_free_data, strdup(line));\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"wexists \")) {\n#ifdef THREADED\n        struct Stat stat;\n#endif\n        line += 8;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n#ifndef THREADED\n        rc = zoo_awexists(zh, line, watcher, (void*) 0, my_stat_completion, strdup(line));\n#else\n        rc = zoo_wexists(zh, line, watcher, (void*) 0, &stat);\n#endif\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (startsWith(line, \"exists \")) {\n#ifdef THREADED\n        struct Stat stat;\n#endif\n        line += 7;\n        if (line[0] != '/') {\n            fprintf(stderr, \"Path must start with /, found: %s\\n\", line);\n            return;\n        }\n#ifndef THREADED\n        rc = zoo_aexists(zh, line, 1, my_stat_completion, strdup(line));\n#else\n        rc = zoo_exists(zh, line, 1, &stat);\n#endif\n        if (rc) {\n            fprintf(stderr, \"Error %d for %s\\n\", rc, line);\n        }\n    } else if (strcmp(line, \"myid\") == 0) {\n        printf(\"session Id = %llx\\n\", _LL_CAST_ zoo_client_id(zh)->client_id);\n    } else if (strcmp(line, \"reinit\") == 0) {\n        zookeeper_close(zh);\n        // we can't send myid to the server here -- zookeeper_close() removes \n        // the session on the server. We must start anew.\n        zh = zookeeper_init(hostPort, watcher, 30000, 0, 0, 0);\n    } else if (startsWith(line, \"quit\")) {\n        fprintf(stderr, \"Quitting...\\n\");\n        shutdownThisThing=1;\n    } else if (startsWith(line, \"od\")) {\n        const char val[]=\"fire off\";\n        fprintf(stderr, \"Overdosing...\\n\");\n        rc = zoo_aset(zh, \"/od\", val, sizeof(val)-1, -1, od_completion, 0);\n        if (rc)\n            fprintf(stderr, \"od command failed: %d\\n\", rc);\n    } else if (startsWith(line, \"addauth \")) {\n      char *ptr;\n      line += 8;\n      ptr = strchr(line, ' ');\n      if (ptr) {\n        *ptr = '\\0';\n        ptr++;\n      }\n      zoo_add_auth(zh, line, ptr, ptr ? strlen(ptr) : 0, NULL, NULL);\n    }\n}\n\nint main(int argc, char **argv) {\n#ifndef THREADED\n    fd_set rfds, wfds, efds;\n    int processed=0;\n#endif\n    char buffer[4096];\n    char p[2048];\n#ifdef YCA  \n    char *cert=0;\n    char appId[64];\n#endif\n    int bufoff = 0;\n    FILE *fh;\n\n    if (argc < 2) {\n        fprintf(stderr,\n                \"USAGE %s zookeeper_host_list [clientid_file|cmd:(ls|ls2|create|od|...)]\\n\", \n                argv[0]);\n        fprintf(stderr,\n                \"Version: ZooKeeper cli (c client) version %d.%d.%d\\n\", \n                ZOO_MAJOR_VERSION,\n                ZOO_MINOR_VERSION,\n                ZOO_PATCH_VERSION);\n        return 2;\n    }\n    if (argc > 2) {\n      if(strncmp(\"cmd:\",argv[2],4)==0){\n        size_t cmdlen = strlen(argv[2]);\n        if (cmdlen > sizeof(cmd)) {\n          fprintf(stderr,\n                  \"Command length %zu exceeds max length of %zu\\n\",\n                  cmdlen,\n                  sizeof(cmd));\n          return 2;\n        }\n        strncpy(cmd, argv[2]+4, sizeof(cmd));\n        batchMode=1;\n        fprintf(stderr,\"Batch mode: %s\\n\",cmd);\n      }else{\n        clientIdFile = argv[2];\n        fh = fopen(clientIdFile, \"r\");\n        if (fh) {\n            if (fread(&myid, sizeof(myid), 1, fh) != sizeof(myid)) {\n                memset(&myid, 0, sizeof(myid));\n            }\n            fclose(fh);\n        }\n      }\n    }\n#ifdef YCA\n    strcpy(appId,\"yahoo.example.yca_test\");\n    cert = yca_get_cert_once(appId);\n    if(cert!=0) {\n        fprintf(stderr,\"Certificate for appid [%s] is [%s]\\n\",appId,cert);\n        strncpy(p,cert,sizeof(p)-1);\n        free(cert);\n    } else {\n      fprintf(stderr,\"Certificate for appid [%s] not found\\n\",appId);\n      strcpy(p,\"dummy\");\n    }\n#else\n    strcpy(p, \"dummy\");\n#endif\n    verbose = 0;\n    zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);\n    zoo_deterministic_conn_order(1); // enable deterministic order\n    hostPort = argv[1];\n    zh = zookeeper_init(hostPort, watcher, 30000, &myid, 0, 0);\n    if (!zh) {\n        return errno;\n    }\n\n#ifdef YCA\n    if(zoo_add_auth(zh,\"yca\",p,strlen(p),0,0)!=ZOK)\n    return 2;\n#endif\n\n#ifdef THREADED\n    while(!shutdownThisThing) {\n        int rc;\n        int len = sizeof(buffer) - bufoff -1;\n        if (len <= 0) {\n            fprintf(stderr, \"Can't handle lines that long!\\n\");\n            exit(2);\n        }\n        rc = read(0, buffer+bufoff, len);\n        if (rc <= 0) {\n            fprintf(stderr, \"bye\\n\");\n            shutdownThisThing=1;\n            break;\n        }\n        bufoff += rc;\n        buffer[bufoff] = '\\0';\n        while (strchr(buffer, '\\n')) {\n            char *ptr = strchr(buffer, '\\n');\n            *ptr = '\\0';\n            processline(buffer);\n            ptr++;\n            memmove(buffer, ptr, strlen(ptr)+1);\n            bufoff = 0;\n        }\n    }\n#else\n    FD_ZERO(&rfds);\n    FD_ZERO(&wfds);\n    FD_ZERO(&efds);\n    while (!shutdownThisThing) {\n        int fd;\n        int interest;\n        int events;\n        struct timeval tv;\n        int rc;\n        zookeeper_interest(zh, &fd, &interest, &tv);\n        if (fd != -1) {\n            if (interest&ZOOKEEPER_READ) {\n                FD_SET(fd, &rfds);\n            } else {\n                FD_CLR(fd, &rfds);\n            }\n            if (interest&ZOOKEEPER_WRITE) {\n                FD_SET(fd, &wfds);\n            } else {\n                FD_CLR(fd, &wfds);\n            }\n        } else {\n            fd = 0;\n        }\n        FD_SET(0, &rfds);\n        rc = select(fd+1, &rfds, &wfds, &efds, &tv);\n        events = 0;\n        if (rc > 0) {\n            if (FD_ISSET(fd, &rfds)) {\n                events |= ZOOKEEPER_READ;\n            }\n            if (FD_ISSET(fd, &wfds)) {\n                events |= ZOOKEEPER_WRITE;\n            }\n        }\n        if(batchMode && processed==0){\n          //batch mode\n          processline(cmd);\n          processed=1;\n        }\n        if (FD_ISSET(0, &rfds)) {\n            int rc;\n            int len = sizeof(buffer) - bufoff -1;\n            if (len <= 0) {\n                fprintf(stderr, \"Can't handle lines that long!\\n\");\n                exit(2);\n            }\n            rc = read(0, buffer+bufoff, len);\n            if (rc <= 0) {\n                fprintf(stderr, \"bye\\n\");\n                break;\n            }\n            bufoff += rc;\n            buffer[bufoff] = '\\0';\n            while (strchr(buffer, '\\n')) {\n                char *ptr = strchr(buffer, '\\n');\n                *ptr = '\\0';\n                processline(buffer);\n                ptr++;\n                memmove(buffer, ptr, strlen(ptr)+1);\n                bufoff = 0;\n            }\n        }\n        zookeeper_process(zh, events);\n    }\n#endif\n    if (to_send!=0)\n        fprintf(stderr,\"Recvd %d responses for %d requests sent\\n\",recvd,sent);\n    zookeeper_close(zh);\n    return 0;\n}\n"
  },
  {
    "path": "src/c/src/hashtable/LICENSE.txt",
    "content": "Copyright (c) 2002, 2004, Christopher Clark\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n\t* Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\n\t* Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\n\t* Neither the name of the original author; nor the names of any contributors\nmay be used to endorse or promote products derived from this software\nwithout specific prior written permission.\n\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "src/c/src/hashtable/hashtable.c",
    "content": "/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */\n\n#include \"hashtable.h\"\n#include \"hashtable_private.h\"\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <math.h>\n\n/*\nCredit for primes table: Aaron Krowne\n http://br.endernet.org/~akrowne/\n http://planetmath.org/encyclopedia/GoodHashTablePrimes.html\n*/\nstatic const unsigned int primes[] = {\n53, 97, 193, 389,\n769, 1543, 3079, 6151,\n12289, 24593, 49157, 98317,\n196613, 393241, 786433, 1572869,\n3145739, 6291469, 12582917, 25165843,\n50331653, 100663319, 201326611, 402653189,\n805306457, 1610612741\n};\nconst unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);\nconst float max_load_factor = 0.65;\n\n/*****************************************************************************/\nstruct hashtable *\ncreate_hashtable(unsigned int minsize,\n                 unsigned int (*hashf) (void*),\n                 int (*eqf) (void*,void*))\n{\n    struct hashtable *h;\n    unsigned int pindex, size = primes[0];\n    /* Check requested hashtable isn't too large */\n    if (minsize > (1u << 30)) return NULL;\n    /* Enforce size as prime */\n    for (pindex=0; pindex < prime_table_length; pindex++) {\n        if (primes[pindex] > minsize) { size = primes[pindex]; break; }\n    }\n    h = (struct hashtable *)malloc(sizeof(struct hashtable));\n    if (NULL == h) return NULL; /*oom*/\n    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);\n    if (NULL == h->table) { free(h); return NULL; } /*oom*/\n    memset(h->table, 0, size * sizeof(struct entry *));\n    h->tablelength  = size;\n    h->primeindex   = pindex;\n    h->entrycount   = 0;\n    h->hashfn       = hashf;\n    h->eqfn         = eqf;\n    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);\n    return h;\n}\n\n/*****************************************************************************/\nunsigned int\nhash(struct hashtable *h, void *k)\n{\n    /* Aim to protect against poor hash functions by adding logic here\n     * - logic taken from java 1.4 hashtable source */\n    unsigned int i = h->hashfn(k);\n    i += ~(i << 9);\n    i ^=  ((i >> 14) | (i << 18)); /* >>> */\n    i +=  (i << 4);\n    i ^=  ((i >> 10) | (i << 22)); /* >>> */\n    return i;\n}\n\n/*****************************************************************************/\nstatic int\nhashtable_expand(struct hashtable *h)\n{\n    /* Double the size of the table to accomodate more entries */\n    struct entry **newtable;\n    struct entry *e;\n    struct entry **pE;\n    unsigned int newsize, i, index;\n    /* Check we're not hitting max capacity */\n    if (h->primeindex == (prime_table_length - 1)) return 0;\n    newsize = primes[++(h->primeindex)];\n\n    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);\n    if (NULL != newtable)\n    {\n        memset(newtable, 0, newsize * sizeof(struct entry *));\n        /* This algorithm is not 'stable'. ie. it reverses the list\n         * when it transfers entries between the tables */\n        for (i = 0; i < h->tablelength; i++) {\n            while (NULL != (e = h->table[i])) {\n                h->table[i] = e->next;\n                index = indexFor(newsize,e->h);\n                e->next = newtable[index];\n                newtable[index] = e;\n            }\n        }\n        free(h->table);\n        h->table = newtable;\n    }\n    /* Plan B: realloc instead */\n    else \n    {\n        newtable = (struct entry **)\n                   realloc(h->table, newsize * sizeof(struct entry *));\n        if (NULL == newtable) { (h->primeindex)--; return 0; }\n        h->table = newtable;\n        memset(newtable[h->tablelength], 0, newsize - h->tablelength);\n        for (i = 0; i < h->tablelength; i++) {\n            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {\n                index = indexFor(newsize,e->h);\n                if (index == i)\n                {\n                    pE = &(e->next);\n                }\n                else\n                {\n                    *pE = e->next;\n                    e->next = newtable[index];\n                    newtable[index] = e;\n                }\n            }\n        }\n    }\n    h->tablelength = newsize;\n    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);\n    return -1;\n}\n\n/*****************************************************************************/\nunsigned int\nhashtable_count(struct hashtable *h)\n{\n    return h->entrycount;\n}\n\n/*****************************************************************************/\nint\nhashtable_insert(struct hashtable *h, void *k, void *v)\n{\n    /* This method allows duplicate keys - but they shouldn't be used */\n    unsigned int index;\n    struct entry *e;\n    if (++(h->entrycount) > h->loadlimit)\n    {\n        /* Ignore the return value. If expand fails, we should\n         * still try cramming just this value into the existing table\n         * -- we may not have memory for a larger table, but one more\n         * element may be ok. Next time we insert, we'll try expanding again.*/\n        hashtable_expand(h);\n    }\n    e = (struct entry *)malloc(sizeof(struct entry));\n    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/\n    e->h = hash(h,k);\n    index = indexFor(h->tablelength,e->h);\n    e->k = k;\n    e->v = v;\n    e->next = h->table[index];\n    h->table[index] = e;\n    return -1;\n}\n\n/*****************************************************************************/\nvoid * /* returns value associated with key */\nhashtable_search(struct hashtable *h, void *k)\n{\n    struct entry *e;\n    unsigned int hashvalue, index;\n    hashvalue = hash(h,k);\n    index = indexFor(h->tablelength,hashvalue);\n    e = h->table[index];\n    while (NULL != e)\n    {\n        /* Check hash value to short circuit heavier comparison */\n        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;\n        e = e->next;\n    }\n    return NULL;\n}\n\n/*****************************************************************************/\nvoid * /* returns value associated with key */\nhashtable_remove(struct hashtable *h, void *k)\n{\n    /* TODO: consider compacting the table when the load factor drops enough,\n     *       or provide a 'compact' method. */\n\n    struct entry *e;\n    struct entry **pE;\n    void *v;\n    unsigned int hashvalue, index;\n\n    hashvalue = hash(h,k);\n    index = indexFor(h->tablelength,hash(h,k));\n    pE = &(h->table[index]);\n    e = *pE;\n    while (NULL != e)\n    {\n        /* Check hash value to short circuit heavier comparison */\n        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))\n        {\n            *pE = e->next;\n            h->entrycount--;\n            v = e->v;\n            freekey(e->k);\n            free(e);\n            return v;\n        }\n        pE = &(e->next);\n        e = e->next;\n    }\n    return NULL;\n}\n\n/*****************************************************************************/\n/* destroy */\nvoid\nhashtable_destroy(struct hashtable *h, int free_values)\n{\n    unsigned int i;\n    struct entry *e, *f;\n    struct entry **table = h->table;\n    if (free_values)\n    {\n        for (i = 0; i < h->tablelength; i++)\n        {\n            e = table[i];\n            while (NULL != e)\n            { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }\n        }\n    }\n    else\n    {\n        for (i = 0; i < h->tablelength; i++)\n        {\n            e = table[i];\n            while (NULL != e)\n            { f = e; e = e->next; freekey(f->k); free(f); }\n        }\n    }\n    free(h->table);\n    free(h);\n}\n\n/*\n * Copyright (c) 2002, Christopher Clark\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * \n * * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * \n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * \n * * Neither the name of the original author; nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "src/c/src/hashtable/hashtable.h",
    "content": "/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */\n\n#ifndef __HASHTABLE_CWC22_H__\n#define __HASHTABLE_CWC22_H__\n#ifdef WIN32\n#include \"winconfig.h\"\n#endif\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct hashtable;\n\n/* Example of use:\n *\n *      struct hashtable  *h;\n *      struct some_key   *k;\n *      struct some_value *v;\n *\n *      static unsigned int         hash_from_key_fn( void *k );\n *      static int                  keys_equal_fn ( void *key1, void *key2 );\n *\n *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);\n *      k = (struct some_key *)     malloc(sizeof(struct some_key));\n *      v = (struct some_value *)   malloc(sizeof(struct some_value));\n *\n *      (initialise k and v to suitable values)\n * \n *      if (! hashtable_insert(h,k,v) )\n *      {     exit(-1);               }\n *\n *      if (NULL == (found = hashtable_search(h,k) ))\n *      {    printf(\"not found!\");                  }\n *\n *      if (NULL == (found = hashtable_remove(h,k) ))\n *      {    printf(\"Not found\\n\");                 }\n *\n */\n\n/* Macros may be used to define type-safe(r) hashtable access functions, with\n * methods specialized to take known key and value types as parameters.\n * \n * Example:\n *\n * Insert this at the start of your file:\n *\n * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);\n * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);\n * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);\n *\n * This defines the functions 'insert_some', 'search_some' and 'remove_some'.\n * These operate just like hashtable_insert etc., with the same parameters,\n * but their function signatures have 'struct some_key *' rather than\n * 'void *', and hence can generate compile time errors if your program is\n * supplying incorrect data as a key (and similarly for value).\n *\n * Note that the hash and key equality functions passed to create_hashtable\n * still take 'void *' parameters instead of 'some key *'. This shouldn't be\n * a difficult issue as they're only defined and passed once, and the other\n * functions will ensure that only valid keys are supplied to them.\n *\n * The cost for this checking is increased code size and runtime overhead\n * - if performance is important, it may be worth switching back to the\n * unsafe methods once your program has been debugged with the safe methods.\n * This just requires switching to some simple alternative defines - eg:\n * #define insert_some hashtable_insert\n *\n */\n\n/*****************************************************************************\n * create_hashtable\n   \n * @name                    create_hashtable\n * @param   minsize         minimum initial size of hashtable\n * @param   hashfunction    function for hashing keys\n * @param   key_eq_fn       function for determining key equality\n * @return                  newly created hashtable or NULL on failure\n */\n\nstruct hashtable *\ncreate_hashtable(unsigned int minsize,\n                 unsigned int (*hashfunction) (void*),\n                 int (*key_eq_fn) (void*,void*));\n\n/*****************************************************************************\n * hashtable_insert\n   \n * @name        hashtable_insert\n * @param   h   the hashtable to insert into\n * @param   k   the key - hashtable claims ownership and will free on removal\n * @param   v   the value - does not claim ownership\n * @return      non-zero for successful insertion\n *\n * This function will cause the table to expand if the insertion would take\n * the ratio of entries to table size over the maximum load factor.\n *\n * This function does not check for repeated insertions with a duplicate key.\n * The value returned when using a duplicate key is undefined -- when\n * the hashtable changes size, the order of retrieval of duplicate key\n * entries is reversed.\n * If in doubt, remove before insert.\n */\n\nint \nhashtable_insert(struct hashtable *h, void *k, void *v);\n\n#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \\\nint fnname (struct hashtable *h, keytype *k, valuetype *v) \\\n{ \\\n    return hashtable_insert(h,k,v); \\\n}\n\n/*****************************************************************************\n * hashtable_search\n   \n * @name        hashtable_search\n * @param   h   the hashtable to search\n * @param   k   the key to search for  - does not claim ownership\n * @return      the value associated with the key, or NULL if none found\n */\n\nvoid *\nhashtable_search(struct hashtable *h, void *k);\n\n#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \\\nvaluetype * fnname (struct hashtable *h, keytype *k) \\\n{ \\\n    return (valuetype *) (hashtable_search(h,k)); \\\n}\n\n/*****************************************************************************\n * hashtable_remove\n   \n * @name        hashtable_remove\n * @param   h   the hashtable to remove the item from\n * @param   k   the key to search for  - does not claim ownership\n * @return      the value associated with the key, or NULL if none found\n */\n\nvoid * /* returns value */\nhashtable_remove(struct hashtable *h, void *k);\n\n#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \\\nvaluetype * fnname (struct hashtable *h, keytype *k) \\\n{ \\\n    return (valuetype *) (hashtable_remove(h,k)); \\\n}\n\n\n/*****************************************************************************\n * hashtable_count\n   \n * @name        hashtable_count\n * @param   h   the hashtable\n * @return      the number of items stored in the hashtable\n */\nunsigned int\nhashtable_count(struct hashtable *h);\n\n\n/*****************************************************************************\n * hashtable_destroy\n   \n * @name        hashtable_destroy\n * @param   h   the hashtable\n * @param       free_values     whether to call 'free' on the remaining values\n */\n\nvoid\nhashtable_destroy(struct hashtable *h, int free_values);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __HASHTABLE_CWC22_H__ */\n\n/*\n * Copyright (c) 2002, Christopher Clark\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * \n * * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * \n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * \n * * Neither the name of the original author; nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "src/c/src/hashtable/hashtable_itr.c",
    "content": "/* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname@cl.cam.ac.uk> */\n\n#include \"hashtable.h\"\n#include \"hashtable_private.h\"\n#include \"hashtable_itr.h\"\n#include <stdlib.h> /* defines NULL */\n\n/*****************************************************************************/\n/* hashtable_iterator    - iterator constructor */\n\nstruct hashtable_itr *\nhashtable_iterator(struct hashtable *h)\n{\n    unsigned int i, tablelength;\n    struct hashtable_itr *itr = (struct hashtable_itr *)\n        malloc(sizeof(struct hashtable_itr));\n    if (NULL == itr) return NULL;\n    itr->h = h;\n    itr->e = NULL;\n    itr->parent = NULL;\n    tablelength = h->tablelength;\n    itr->index = tablelength;\n    if (0 == h->entrycount) return itr;\n\n    for (i = 0; i < tablelength; i++)\n    {\n        if (NULL != h->table[i])\n        {\n            itr->e = h->table[i];\n            itr->index = i;\n            break;\n        }\n    }\n    return itr;\n}\n\n/*****************************************************************************/\n/* advance - advance the iterator to the next element\n *           returns zero if advanced to end of table */\n\nint\nhashtable_iterator_advance(struct hashtable_itr *itr)\n{\n    unsigned int j,tablelength;\n    struct entry **table;\n    struct entry *next;\n    if (NULL == itr->e) return 0; /* stupidity check */\n\n    next = itr->e->next;\n    if (NULL != next)\n    {\n        itr->parent = itr->e;\n        itr->e = next;\n        return -1;\n    }\n    tablelength = itr->h->tablelength;\n    itr->parent = NULL;\n    if (tablelength <= (j = ++(itr->index)))\n    {\n        itr->e = NULL;\n        return 0;\n    }\n    table = itr->h->table;\n    while (NULL == (next = table[j]))\n    {\n        if (++j >= tablelength)\n        {\n            itr->index = tablelength;\n            itr->e = NULL;\n            return 0;\n        }\n    }\n    itr->index = j;\n    itr->e = next;\n    return -1;\n}\n\n/*****************************************************************************/\n/* remove - remove the entry at the current iterator position\n *          and advance the iterator, if there is a successive\n *          element.\n *          If you want the value, read it before you remove:\n *          beware memory leaks if you don't.\n *          Returns zero if end of iteration. */\n\nint\nhashtable_iterator_remove(struct hashtable_itr *itr)\n{\n    struct entry *remember_e, *remember_parent;\n    int ret;\n\n    /* Do the removal */\n    if (NULL == (itr->parent))\n    {\n        /* element is head of a chain */\n        itr->h->table[itr->index] = itr->e->next;\n    } else {\n        /* element is mid-chain */\n        itr->parent->next = itr->e->next;\n    }\n    /* itr->e is now outside the hashtable */\n    remember_e = itr->e;\n    itr->h->entrycount--;\n    freekey(remember_e->k);\n\n    /* Advance the iterator, correcting the parent */\n    remember_parent = itr->parent;\n    ret = hashtable_iterator_advance(itr);\n    if (itr->parent == remember_e) { itr->parent = remember_parent; }\n    free(remember_e);\n    return ret;\n}\n\n/*****************************************************************************/\nint /* returns zero if not found */\nhashtable_iterator_search(struct hashtable_itr *itr,\n                          struct hashtable *h, void *k)\n{\n    struct entry *e, *parent;\n    unsigned int hashvalue, index;\n\n    hashvalue = hash(h,k);\n    index = indexFor(h->tablelength,hashvalue);\n\n    e = h->table[index];\n    parent = NULL;\n    while (NULL != e)\n    {\n        /* Check hash value to short circuit heavier comparison */\n        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))\n        {\n            itr->index = index;\n            itr->e = e;\n            itr->parent = parent;\n            itr->h = h;\n            return -1;\n        }\n        parent = e;\n        e = e->next;\n    }\n    return 0;\n}\n\n\n/*\n * Copyright (c) 2002, 2004, Christopher Clark\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * \n * * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * \n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * \n * * Neither the name of the original author; nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "src/c/src/hashtable/hashtable_itr.h",
    "content": "/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */\n\n#ifndef __HASHTABLE_ITR_CWC22__\n#define __HASHTABLE_ITR_CWC22__\n#include \"hashtable.h\"\n#include \"hashtable_private.h\" /* needed to enable inlining */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*****************************************************************************/\n/* This struct is only concrete here to allow the inlining of two of the\n * accessor functions. */\nstruct hashtable_itr\n{\n    struct hashtable *h;\n    struct entry *e;\n    struct entry *parent;\n    unsigned int index;\n};\n\n\n/*****************************************************************************/\n/* hashtable_iterator\n */\n\nstruct hashtable_itr *\nhashtable_iterator(struct hashtable *h);\n\n/*****************************************************************************/\n/* hashtable_iterator_key\n * - return the value of the (key,value) pair at the current position */\n\nstatic inline void *\nhashtable_iterator_key(struct hashtable_itr *i)\n{\n    return i->e->k;\n}\n\n/*****************************************************************************/\n/* value - return the value of the (key,value) pair at the current position */\n\nstatic inline void *\nhashtable_iterator_value(struct hashtable_itr *i)\n{\n    return i->e->v;\n}\n\n/*****************************************************************************/\n/* advance - advance the iterator to the next element\n *           returns zero if advanced to end of table */\n\nint\nhashtable_iterator_advance(struct hashtable_itr *itr);\n\n/*****************************************************************************/\n/* remove - remove current element and advance the iterator to the next element\n *          NB: if you need the value to free it, read it before\n *          removing. ie: beware memory leaks!\n *          returns zero if advanced to end of table */\n\nint\nhashtable_iterator_remove(struct hashtable_itr *itr);\n\n/*****************************************************************************/\n/* search - overwrite the supplied iterator, to point to the entry\n *          matching the supplied key.\n            h points to the hashtable to be searched.\n *          returns zero if not found. */\nint\nhashtable_iterator_search(struct hashtable_itr *itr,\n                          struct hashtable *h, void *k);\n\n#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \\\nint fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \\\n{ \\\n    return (hashtable_iterator_search(i,h,k)); \\\n}\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __HASHTABLE_ITR_CWC22__*/\n\n/*\n * Copyright (c) 2002, 2004, Christopher Clark\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * \n * * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * \n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * \n * * Neither the name of the original author; nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "src/c/src/hashtable/hashtable_private.h",
    "content": "/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */\n\n#ifndef __HASHTABLE_PRIVATE_CWC22_H__\n#define __HASHTABLE_PRIVATE_CWC22_H__\n\n#include \"hashtable.h\"\n\n/*****************************************************************************/\nstruct entry\n{\n    void *k, *v;\n    unsigned int h;\n    struct entry *next;\n};\n\nstruct hashtable {\n    unsigned int tablelength;\n    struct entry **table;\n    unsigned int entrycount;\n    unsigned int loadlimit;\n    unsigned int primeindex;\n    unsigned int (*hashfn) (void *k);\n    int (*eqfn) (void *k1, void *k2);\n};\n\n/*****************************************************************************/\nunsigned int\nhash(struct hashtable *h, void *k);\n\n/*****************************************************************************/\n/* indexFor */\nstatic inline unsigned int\nindexFor(unsigned int tablelength, unsigned int hashvalue) {\n    return (hashvalue % tablelength);\n};\n\n/* Only works if tablelength == 2^N */\n/*static inline unsigned int\nindexFor(unsigned int tablelength, unsigned int hashvalue)\n{\n    return (hashvalue & (tablelength - 1u));\n}\n*/\n\n/*****************************************************************************/\n#define freekey(X) free(X)\n/*define freekey(X) ; */\n\n\n/*****************************************************************************/\n\n#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/\n\n/*\n * Copyright (c) 2002, Christopher Clark\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * \n * * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * \n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * \n * * Neither the name of the original author; nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "src/c/src/load_gen.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <zookeeper.h>\n#include \"zookeeper_log.h\"\n#include <errno.h>\n#ifdef THREADED \n#include <pthread.h>\n#endif\n#include <string.h>\n#include <stdlib.h>\n\nstatic zhandle_t *zh;\n\nstatic int shutdownThisThing=0;\n\n// *****************************************************************************\n//\nstatic pthread_cond_t cond=PTHREAD_COND_INITIALIZER;\nstatic pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;\n\nstatic pthread_cond_t counterCond=PTHREAD_COND_INITIALIZER;\nstatic pthread_mutex_t counterLock=PTHREAD_MUTEX_INITIALIZER;\nstatic int counter; \n\n\n\nvoid ensureConnected(){\n    pthread_mutex_lock(&lock);\n    while (zoo_state(zh)!=ZOO_CONNECTED_STATE) {\n        pthread_cond_wait(&cond,&lock);\n    }\n    pthread_mutex_unlock(&lock);\n}\n\nvoid incCounter(int delta){\n    pthread_mutex_lock(&counterLock);\n    counter+=delta;\n    pthread_cond_broadcast(&counterCond);\n    pthread_mutex_unlock(&counterLock);        \n    \n}\nvoid setCounter(int cnt){\n    pthread_mutex_lock(&counterLock);\n    counter=cnt;\n    pthread_cond_broadcast(&counterCond);\n    pthread_mutex_unlock(&counterLock);        \n    \n}\nvoid waitCounter(){\n    pthread_mutex_lock(&counterLock);\n    while (counter>0) {\n        pthread_cond_wait(&counterCond,&counterLock);\n    }\n    pthread_mutex_unlock(&counterLock);    \n}\n\nvoid listener(zhandle_t *zzh, int type, int state, const char *path,void* ctx) {\n    if(type == ZOO_SESSION_EVENT){\n        if(state == ZOO_CONNECTED_STATE){\n            pthread_mutex_lock(&lock);\n            pthread_cond_broadcast(&cond);\n            pthread_mutex_unlock(&lock);\n        }\n        setCounter(0);\n    }\n}\n\nvoid create_completion(int rc, const char *name, const void *data) {\n    incCounter(-1);\n    if(rc!=ZOK){\n        LOG_ERROR((\"Failed to create a node rc=%d\",rc));\n    }\n}\n\nint doCreateNodes(const char* root, int count){\n    char nodeName[1024];\n    int i;\n    for(i=0; i<count;i++){\n        int rc = 0;\n        snprintf(nodeName, sizeof(nodeName),\"%s/%d\",root,i);\n        incCounter(1);\n        rc=zoo_acreate(zh, nodeName, \"first\", 5, &ZOO_OPEN_ACL_UNSAFE, 0,\n                            create_completion, 0);\n        if(i%1000==0){\n            LOG_INFO((\"Created %s\",nodeName));\n        }\n        if(rc!=ZOK) return rc;        \n    }\n    return ZOK;\n}\n\nint createRoot(const char* root){\n    char realpath[1024];\n    return zoo_create(zh,root,\"root\",4,&ZOO_OPEN_ACL_UNSAFE,0,realpath,sizeof(realpath)-1);\n}\n\nvoid write_completion(int rc, const struct Stat *stat, const void *data) {\n    incCounter(-1);\n    if(rc!=ZOK){\n        LOG_ERROR((\"Failed to write a node rc=%d\",rc));\n    }\n}\n\nint doWrites(const char* root, int count){\n    char nodeName[1024];\n    int i;\n    counter=0;\n    for(i=0; i<count;i++){\n        int rc = 0;\n        snprintf(nodeName, sizeof(nodeName),\"%s/%d\",root,i);\n        incCounter(1);\n        rc=zoo_aset(zh, nodeName, \"second\", 6,-1,write_completion, 0);\n        if(rc!=ZOK) return rc;        \n    }\n    return ZOK;\n}\n\nvoid read_completion(int rc, const char *value, int value_len,\n        const struct Stat *stat, const void *data) {\n    incCounter(-1);    \n    if(rc!=ZOK){\n        LOG_ERROR((\"Failed to read a node rc=%d\",rc));\n        return;\n    }\n    if(memcmp(value,\"second\",6)!=0){\n        char buf[value_len+1];\n        memcpy(buf,value,value_len);buf[value_len]=0;\n        LOG_ERROR((\"Invalid read, expected [second], received [%s]\\n\",buf));\n        exit(1);\n    }\n}\n\nint doReads(const char* root, int count){\n    char nodeName[1024];\n    int i;\n    counter=0;\n    for(i=0; i<count;i++){\n        int rc = 0;\n        snprintf(nodeName, sizeof(nodeName),\"%s/%d\",root,i);\n        incCounter(1);\n        rc=zoo_aget(zh, nodeName,0,read_completion, 0);\n        if(rc!=ZOK) return rc;        \n    }\n    return ZOK;\n}\n\nvoid delete_completion(int rc, const void *data) {\n    incCounter(-1);    \n}\n\nint doDeletes(const char* root, int count){\n    char nodeName[1024];\n    int i;\n    counter=0;\n    for(i=0; i<count;i++){\n        int rc = 0;\n        snprintf(nodeName, sizeof(nodeName),\"%s/%d\",root,i);\n        incCounter(1);\n        rc=zoo_adelete(zh, nodeName,-1,delete_completion, 0);\n        if(rc!=ZOK) return rc;        \n    }\n    return ZOK;\n}\n\nstatic int free_String_vector(struct String_vector *v) {\n    if (v->data) {\n        int32_t i;\n        for(i=0;i<v->count; i++) {\n            free(v->data[i]);\n        }\n        free(v->data);\n        v->data = 0;\n    }\n    return 0;\n}\n\nstatic int deletedCounter;\n\nint recursiveDelete(const char* root){\n    struct String_vector children;\n    int i;\n    int rc=zoo_get_children(zh,root,0,&children);\n    if(rc!=ZNONODE){\n        if(rc!=ZOK){\n            LOG_ERROR((\"Failed to get children of %s, rc=%d\",root,rc));\n            return rc;\n        }\n        for(i=0;i<children.count; i++){\n            int rc = 0;\n            char nodeName[2048];\n            snprintf(nodeName, sizeof(nodeName),\"%s/%s\",root,children.data[i]);\n            rc=recursiveDelete(nodeName);\n            if(rc!=ZOK){\n                free_String_vector(&children);\n                return rc;\n            }\n        }\n        free_String_vector(&children);\n    }\n    if(deletedCounter%1000==0)\n        LOG_INFO((\"Deleting %s\",root));\n    rc=zoo_delete(zh,root,-1);\n    if(rc!=ZOK){\n        LOG_ERROR((\"Failed to delete znode %s, rc=%d\",root,rc));\n    }else\n        deletedCounter++;\n    return rc;\n}\n\nvoid usage(char *argv[]){\n    fprintf(stderr, \"USAGE:\\t%s zookeeper_host_list path #children\\nor\", argv[0]);\n    fprintf(stderr, \"\\t%s zookeeper_host_list path clean\\n\", argv[0]);\n    exit(0);\n}\n\nint main(int argc, char **argv) {\n    int nodeCount;\n    int cleaning=0;\n    if (argc < 4) {\n        usage(argv);\n    }\n    if(strcmp(\"clean\",argv[3])==0){\n        cleaning=1;\n    }\n    zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);\n    zoo_deterministic_conn_order(1); // enable deterministic order\n\n    zh = zookeeper_init(argv[1], listener, 10000, 0, 0, 0);\n    if (!zh)\n        return errno;\n\n    LOG_INFO((\"Checking server connection...\"));\n    ensureConnected();\n    if(cleaning==1){\n        int rc = 0;\n        deletedCounter=0;\n        rc=recursiveDelete(argv[2]);\n        if(rc==ZOK){\n            LOG_INFO((\"Successfully deleted a subtree starting at %s (%d nodes)\",\n                    argv[2],deletedCounter));\n            exit(0);\n        }\n        exit(1);\n    }\n    nodeCount=atoi(argv[3]);\n    createRoot(argv[2]);\n    while(1) {\n        ensureConnected();\n        LOG_INFO((\"Creating children for path %s\",argv[2]));\n        doCreateNodes(argv[2],nodeCount);\n        waitCounter();\n        \n        LOG_INFO((\"Starting the write cycle for path %s\",argv[2]));\n        doWrites(argv[2],nodeCount);\n        waitCounter();\n        LOG_INFO((\"Starting the read cycle for path %s\",argv[2]));\n        doReads(argv[2],nodeCount);\n        waitCounter();\n\n        LOG_INFO((\"Starting the delete cycle for path %s\",argv[2]));\n        doDeletes(argv[2],nodeCount);\n        waitCounter();\n    }\n    zookeeper_close(zh);\n    return 0;\n}\n"
  },
  {
    "path": "src/c/src/mt_adaptor.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef THREADED\n#define THREADED\n#endif\n\n#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)\n#  define USE_STATIC_LIB\n#endif\n\n#ifndef _GNU_SOURCE\n#define _GNU_SOURCE\n#endif\n\n#include \"zk_adaptor.h\"\n#include \"zookeeper_log.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <time.h>\n#include <fcntl.h>\n#include <assert.h>\n#include <errno.h>\n\n#ifndef WIN32\n#include <signal.h>\n#include <poll.h>\n#include <unistd.h>\n#include <sys/time.h>\n#endif\n\nint zoo_lock_auth(zhandle_t *zh)\n{\n    return pthread_mutex_lock(&zh->auth_h.lock);\n}\nint zoo_unlock_auth(zhandle_t *zh)\n{\n    return pthread_mutex_unlock(&zh->auth_h.lock);\n}\nint lock_buffer_list(buffer_head_t *l)\n{\n    return pthread_mutex_lock(&l->lock);\n}\nint  unlock_buffer_list(buffer_head_t *l)\n{\n    return pthread_mutex_unlock(&l->lock);\n}\nint lock_completion_list(completion_head_t *l)\n{\n    return pthread_mutex_lock(&l->lock);\n}\nint unlock_completion_list(completion_head_t *l)\n{\n    pthread_cond_broadcast(&l->cond);\n    return pthread_mutex_unlock(&l->lock);\n}\nstruct sync_completion *alloc_sync_completion(void)\n{\n    struct sync_completion *sc = (struct sync_completion*)calloc(1, sizeof(struct sync_completion));\n    if (sc) {\n       pthread_cond_init(&sc->cond, 0);\n       pthread_mutex_init(&sc->lock, 0);\n    }\n    return sc;\n}\nint wait_sync_completion(struct sync_completion *sc)\n{\n    pthread_mutex_lock(&sc->lock);\n    while (!sc->complete) {\n        pthread_cond_wait(&sc->cond, &sc->lock);\n    }\n    pthread_mutex_unlock(&sc->lock);\n    return 0;\n}\n\nvoid free_sync_completion(struct sync_completion *sc)\n{\n    if (sc) {\n        pthread_mutex_destroy(&sc->lock);\n        pthread_cond_destroy(&sc->cond);\n        free(sc);\n    }\n}\n\nvoid notify_sync_completion(struct sync_completion *sc)\n{\n    pthread_mutex_lock(&sc->lock);\n    sc->complete = 1;\n    pthread_cond_broadcast(&sc->cond);\n    pthread_mutex_unlock(&sc->lock);\n}\n\nint process_async(int outstanding_sync)\n{\n    return 0;\n}\n\n#ifdef WIN32\nunsigned __stdcall do_io( void * );\nunsigned __stdcall do_completion( void * );\n\nint handle_error(SOCKET sock, char* message)\n{\n       LOG_ERROR((\"%s. %d\",message, WSAGetLastError()));\n       closesocket (sock);\n       return -1;\n}\n\n//--create socket pair for interupting selects.\nint create_socket_pair(SOCKET fds[2]) \n{ \n    struct sockaddr_in inaddr; \n    struct sockaddr addr; \n    int yes=1; \n    int len=0;\n       \n    SOCKET lst=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); \n    if (lst ==  INVALID_SOCKET ){\n       LOG_ERROR((\"Error creating socket. %d\",WSAGetLastError()));\n       return -1;\n    }\n    memset(&inaddr, 0, sizeof(inaddr)); \n    memset(&addr, 0, sizeof(addr)); \n    inaddr.sin_family = AF_INET; \n    inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); \n    inaddr.sin_port = 0; //--system assigns the port\n\n    if ( setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)) == SOCKET_ERROR  ) {\n       return handle_error(lst,\"Error trying to set socket option.\");          \n    }  \n    if (bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)) == SOCKET_ERROR){\n       return handle_error(lst,\"Error trying to bind socket.\");                \n    }\n    if (listen(lst,1) == SOCKET_ERROR){\n       return handle_error(lst,\"Error trying to listen on socket.\");\n    }\n    len=sizeof(inaddr); \n    getsockname(lst, &addr,&len); \n    fds[0]=socket(AF_INET, SOCK_STREAM,0); \n    if (connect(fds[0],&addr,len) == SOCKET_ERROR){\n       return handle_error(lst, \"Error while connecting to socket.\");\n    }\n    if ((fds[1]=accept(lst,0,0)) == INVALID_SOCKET){\n       closesocket(fds[0]);\n       return handle_error(lst, \"Error while accepting socket connection.\");\n    }\n    closesocket(lst);  \n    return 0;\n} \n#else\nvoid *do_io(void *);\nvoid *do_completion(void *);\n#endif\n\n\nint wakeup_io_thread(zhandle_t *zh);\n\n#ifdef WIN32\nstatic int set_nonblock(SOCKET fd){\n    ULONG nonblocking_flag = 1;\n    if (ioctlsocket(fd, FIONBIO, &nonblocking_flag) == 0)\n        return 1;\n    else \n        return -1;\n}\n#else\nstatic int set_nonblock(int fd){\n    long l = fcntl(fd, F_GETFL);\n    if(l & O_NONBLOCK) return 0;\n    return fcntl(fd, F_SETFL, l | O_NONBLOCK);\n}\n#endif\n\nvoid wait_for_others(zhandle_t* zh)\n{\n    struct adaptor_threads* adaptor=zh->adaptor_priv;\n    pthread_mutex_lock(&adaptor->lock);\n    while(adaptor->threadsToWait>0) \n        pthread_cond_wait(&adaptor->cond,&adaptor->lock);\n    pthread_mutex_unlock(&adaptor->lock);    \n}\n\nvoid notify_thread_ready(zhandle_t* zh)\n{\n    struct adaptor_threads* adaptor=zh->adaptor_priv;\n    pthread_mutex_lock(&adaptor->lock);\n    adaptor->threadsToWait--;\n    pthread_cond_broadcast(&adaptor->cond);\n    while(adaptor->threadsToWait>0) \n        pthread_cond_wait(&adaptor->cond,&adaptor->lock);\n    pthread_mutex_unlock(&adaptor->lock);\n}\n\n\nvoid start_threads(zhandle_t* zh)\n{\n    int rc = 0;\n    struct adaptor_threads* adaptor=zh->adaptor_priv;\n    pthread_cond_init(&adaptor->cond,0);\n    pthread_mutex_init(&adaptor->lock,0);\n    adaptor->threadsToWait=2;  // wait for 2 threads before opening the barrier\n    \n    // use api_prolog() to make sure zhandle doesn't get destroyed\n    // while initialization is in progress\n    api_prolog(zh);\n    LOG_DEBUG((\"starting threads...\"));\n    rc=pthread_create(&adaptor->io, 0, do_io, zh);\n    assert(\"pthread_create() failed for the IO thread\"&&!rc);\n    rc=pthread_create(&adaptor->completion, 0, do_completion, zh);\n    assert(\"pthread_create() failed for the completion thread\"&&!rc);\n    wait_for_others(zh);\n    api_epilog(zh, 0);    \n}\n\nint adaptor_init(zhandle_t *zh)\n{\n    pthread_mutexattr_t recursive_mx_attr;\n    struct adaptor_threads *adaptor_threads = calloc(1, sizeof(*adaptor_threads));\n    if (!adaptor_threads) {\n        LOG_ERROR((\"Out of memory\"));\n        return -1;\n    }\n\n    /* We use a pipe for interrupting select() in unix/sol and socketpair in windows. */\n#ifdef WIN32   \n    if (create_socket_pair(adaptor_threads->self_pipe) == -1){\n       LOG_ERROR((\"Can't make a socket.\"));\n#else\n    if(pipe(adaptor_threads->self_pipe)==-1) {\n        LOG_ERROR((\"Can't make a pipe %d\",errno));\n#endif\n        free(adaptor_threads);\n        return -1;\n    }\n    set_nonblock(adaptor_threads->self_pipe[1]);\n    set_nonblock(adaptor_threads->self_pipe[0]);\n\n    pthread_mutex_init(&zh->auth_h.lock,0);\n\n    zh->adaptor_priv = adaptor_threads;\n    pthread_mutex_init(&zh->to_process.lock,0);\n    pthread_mutex_init(&adaptor_threads->zh_lock,0);\n    // to_send must be recursive mutex    \n    pthread_mutexattr_init(&recursive_mx_attr);\n    pthread_mutexattr_settype(&recursive_mx_attr, PTHREAD_MUTEX_RECURSIVE);\n    pthread_mutex_init(&zh->to_send.lock,&recursive_mx_attr);\n    pthread_mutexattr_destroy(&recursive_mx_attr);\n    \n    pthread_mutex_init(&zh->sent_requests.lock,0);\n    pthread_cond_init(&zh->sent_requests.cond,0);\n    pthread_mutex_init(&zh->completions_to_process.lock,0);\n    pthread_cond_init(&zh->completions_to_process.cond,0);\n    start_threads(zh);\n    return 0;\n}\n\nvoid adaptor_finish(zhandle_t *zh)\n{\n    struct adaptor_threads *adaptor_threads;\n    // make sure zh doesn't get destroyed until after we're done here\n    api_prolog(zh); \n    adaptor_threads = zh->adaptor_priv;\n    if(adaptor_threads==0) {\n        api_epilog(zh,0);\n        return;\n    }\n\n    if(!pthread_equal(adaptor_threads->io,pthread_self())){\n        wakeup_io_thread(zh);\n        pthread_join(adaptor_threads->io, 0);\n    }else\n        pthread_detach(adaptor_threads->io);\n    \n    if(!pthread_equal(adaptor_threads->completion,pthread_self())){\n        pthread_mutex_lock(&zh->completions_to_process.lock);\n        pthread_cond_broadcast(&zh->completions_to_process.cond);\n        pthread_mutex_unlock(&zh->completions_to_process.lock);\n        pthread_join(adaptor_threads->completion, 0);\n    }else\n        pthread_detach(adaptor_threads->completion);\n    \n    api_epilog(zh,0);\n}\n\nvoid adaptor_destroy(zhandle_t *zh)\n{\n    struct adaptor_threads *adaptor = zh->adaptor_priv;\n    if(adaptor==0) return;\n    \n    pthread_cond_destroy(&adaptor->cond);\n    pthread_mutex_destroy(&adaptor->lock);\n    pthread_mutex_destroy(&zh->to_process.lock);\n    pthread_mutex_destroy(&zh->to_send.lock);\n    pthread_mutex_destroy(&zh->sent_requests.lock);\n    pthread_cond_destroy(&zh->sent_requests.cond);\n    pthread_mutex_destroy(&zh->completions_to_process.lock);\n    pthread_cond_destroy(&zh->completions_to_process.cond);\n    pthread_mutex_destroy(&adaptor->zh_lock);\n\n    pthread_mutex_destroy(&zh->auth_h.lock);\n\n    close(adaptor->self_pipe[0]);\n    close(adaptor->self_pipe[1]);\n    free(adaptor);\n    zh->adaptor_priv=0;\n}\n\nint wakeup_io_thread(zhandle_t *zh)\n{\n    struct adaptor_threads *adaptor_threads = zh->adaptor_priv;\n    char c=0;\n#ifndef WIN32\n    return write(adaptor_threads->self_pipe[1],&c,1)==1? ZOK: ZSYSTEMERROR;    \n#else\n    return send(adaptor_threads->self_pipe[1], &c, 1, 0)==1? ZOK: ZSYSTEMERROR;    \n#endif         \n}\n\nint adaptor_send_queue(zhandle_t *zh, int timeout)\n{\n    if(!zh->close_requested)\n        return wakeup_io_thread(zh);\n    // don't rely on the IO thread to send the messages if the app has\n    // requested to close \n    return flush_send_queue(zh, timeout);\n}\n\n/* These two are declared here because we will run the event loop\n * and not the client */\n#ifdef WIN32\nint zookeeper_interest(zhandle_t *zh, SOCKET *fd, int *interest,\n        struct timeval *tv);\n#else\nint zookeeper_interest(zhandle_t *zh, int *fd, int *interest,\n        struct timeval *tv);\n#endif\nint zookeeper_process(zhandle_t *zh, int events);\n\n#ifdef WIN32\nunsigned __stdcall do_io( void * v)\n#else\nvoid *do_io(void *v)\n#endif\n{\n    zhandle_t *zh = (zhandle_t*)v;\n#ifndef WIN32\n    struct pollfd fds[2];\n    struct adaptor_threads *adaptor_threads = zh->adaptor_priv;\n\n    api_prolog(zh);\n    notify_thread_ready(zh);\n    LOG_DEBUG((\"started IO thread\"));\n    fds[0].fd=adaptor_threads->self_pipe[0];\n    fds[0].events=POLLIN;\n    while(!zh->close_requested) {\n        struct timeval tv;\n        int fd;\n        int interest;\n        int timeout;\n        int maxfd=1;\n\n        zookeeper_interest(zh, &fd, &interest, &tv);\n        if (fd != -1) {\n            fds[1].fd=fd;\n            fds[1].events=(interest&ZOOKEEPER_READ)?POLLIN:0;\n            fds[1].events|=(interest&ZOOKEEPER_WRITE)?POLLOUT:0;\n            maxfd=2;\n        }\n        timeout=tv.tv_sec * 1000 + (tv.tv_usec/1000);\n        \n        poll(fds,maxfd,timeout);\n        if (fd != -1) {\n            interest=(fds[1].revents&POLLIN)?ZOOKEEPER_READ:0;\n            interest|=((fds[1].revents&POLLOUT)||(fds[1].revents&POLLHUP))?ZOOKEEPER_WRITE:0;\n        }\n        if(fds[0].revents&POLLIN){\n            // flush the pipe\n            char b[128];\n            while(read(adaptor_threads->self_pipe[0],b,sizeof(b))==sizeof(b)){}\n        }        \n#else\n    fd_set rfds, wfds, efds;\n    struct adaptor_threads *adaptor_threads = zh->adaptor_priv;\n    api_prolog(zh);\n    notify_thread_ready(zh);\n    LOG_DEBUG((\"started IO thread\"));\n    FD_ZERO(&rfds);   FD_ZERO(&wfds);    FD_ZERO(&efds);\n    while(!zh->close_requested) {      \n        struct timeval tv;\n        SOCKET fd;\n        SOCKET maxfd=adaptor_threads->self_pipe[0];\n        int interest;        \n        int rc;\n               \n       zookeeper_interest(zh, &fd, &interest, &tv);\n       if (fd != -1) {\n           if (interest&ZOOKEEPER_READ) {\n                FD_SET(fd, &rfds);\n            } else {\n                FD_CLR(fd, &rfds);\n            }\n           if (interest&ZOOKEEPER_WRITE) {\n                FD_SET(fd, &wfds);\n            } else {\n                FD_CLR(fd, &wfds);\n            }                  \n        }\n       FD_SET( adaptor_threads->self_pipe[0] ,&rfds );        \n       rc = select((int)maxfd, &rfds, &wfds, &efds, &tv);\n       if (fd != -1) \n       {\n           interest = (FD_ISSET(fd, &rfds))? ZOOKEEPER_READ:0;\n           interest|= (FD_ISSET(fd, &wfds))? ZOOKEEPER_WRITE:0;\n        }\n               \n       if (FD_ISSET(adaptor_threads->self_pipe[0], &rfds)){\n            // flush the pipe/socket\n            char b[128];\n           while(recv(adaptor_threads->self_pipe[0],b,sizeof(b), 0)==sizeof(b)){}\n       }\n#endif\n        // dispatch zookeeper events\n        zookeeper_process(zh, interest);\n        // check the current state of the zhandle and terminate \n        // if it is_unrecoverable()\n        if(is_unrecoverable(zh))\n            break;\n    }\n    api_epilog(zh, 0);    \n    LOG_DEBUG((\"IO thread terminated\"));\n    return 0;\n}\n\n#ifdef WIN32\nunsigned __stdcall do_completion( void * v)\n#else\nvoid *do_completion(void *v)\n#endif\n{\n    zhandle_t *zh = v;\n    api_prolog(zh);\n    notify_thread_ready(zh);\n    LOG_DEBUG((\"started completion thread\"));\n    while(!zh->close_requested) {\n        pthread_mutex_lock(&zh->completions_to_process.lock);\n        while(!zh->completions_to_process.head && !zh->close_requested) {\n            pthread_cond_wait(&zh->completions_to_process.cond, &zh->completions_to_process.lock);\n        }\n        pthread_mutex_unlock(&zh->completions_to_process.lock);\n        process_completions(zh);\n    }\n    api_epilog(zh, 0);    \n    LOG_DEBUG((\"completion thread terminated\"));\n    return 0;\n}\n\nint32_t inc_ref_counter(zhandle_t* zh,int i)\n{\n    int incr=(i<0?-1:(i>0?1:0));\n    // fetch_and_add implements atomic post-increment\n    int v=fetch_and_add(&zh->ref_counter,incr);\n    // inc_ref_counter wants pre-increment\n    v+=incr;   // simulate pre-increment\n    return v;\n}\n\nint32_t fetch_and_add(volatile int32_t* operand, int incr)\n{\n#ifndef WIN32\n    return __sync_fetch_and_add(operand, incr);\n#else\n    return InterlockedExchangeAdd(operand, incr);\n#endif\n}\n\n// make sure the static xid is initialized before any threads started\n__attribute__((constructor)) int32_t get_xid()\n{\n    static int32_t xid = -1;\n    if (xid == -1) {\n        xid = time(0);\n    }\n    return fetch_and_add(&xid,1);\n}\n\nint enter_critical(zhandle_t* zh)\n{\n    struct adaptor_threads *adaptor = zh->adaptor_priv;\n    if (adaptor) {\n        return pthread_mutex_lock(&adaptor->zh_lock);\n    } else {\n        return 0;\n    }\n}\n\nint leave_critical(zhandle_t* zh)\n{\n    struct adaptor_threads *adaptor = zh->adaptor_priv;\n    if (adaptor) {\n        return pthread_mutex_unlock(&adaptor->zh_lock);\n    } else {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "src/c/src/recordio.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <recordio.h>\n#include <string.h>\n#include <stdio.h>\n#include <errno.h>\n#include <stdlib.h>\n#ifndef WIN32\n#include <netinet/in.h>\n#else\n#include <winsock2.h> /* for _htonl and _ntohl */\n#endif\n\nvoid deallocate_String(char **s)\n{\n    if (*s)\n        free(*s);\n    *s = 0;\n}\n\nvoid deallocate_Buffer(struct buffer *b)\n{\n    if (b->buff)\n        free(b->buff);\n    b->buff = 0;\n}\n\nstruct buff_struct {\n    int32_t len;\n    int32_t off;\n    char *buffer;\n};\n\nstatic int resize_buffer(struct buff_struct *s, int newlen)\n{\n    char *buffer= NULL;\n    while (s->len < newlen) {\n        s->len *= 2;\n    }\n    buffer = (char*)realloc(s->buffer, s->len);\n    if (!buffer) {\n        s->buffer = 0;\n        return -ENOMEM;\n    }\n    s->buffer = buffer;\n    return 0;\n}\n\nint oa_start_record(struct oarchive *oa, const char *tag)\n{\n    return 0;\n}\nint oa_end_record(struct oarchive *oa, const char *tag)\n{\n    return 0;\n}\nint oa_serialize_int(struct oarchive *oa, const char *tag, const int32_t *d)\n{\n    struct buff_struct *priv = oa->priv;\n    int32_t i = htonl(*d);\n    if ((priv->len - priv->off) < sizeof(i)) {\n        int rc = resize_buffer(priv, priv->len + sizeof(i));\n        if (rc < 0) return rc;\n    }\n    memcpy(priv->buffer+priv->off, &i, sizeof(i));\n    priv->off+=sizeof(i);\n    return 0;\n}\nint64_t zoo_htonll(int64_t v)\n{\n    int i = 0;\n    char *s = (char *)&v;\n    if (htonl(1) == 1) {\n        return v;\n    }\n    for (i = 0; i < 4; i++) {\n        int tmp = s[i];\n        s[i] = s[8-i-1];\n        s[8-i-1] = tmp;\n    }\n\n    return v;\n}\n\nint oa_serialize_long(struct oarchive *oa, const char *tag, const int64_t *d)\n{\n    const int64_t i = zoo_htonll(*d);\n    struct buff_struct *priv = oa->priv;\n    if ((priv->len - priv->off) < sizeof(i)) {\n        int rc = resize_buffer(priv, priv->len + sizeof(i));\n        if (rc < 0) return rc;\n    }\n    memcpy(priv->buffer+priv->off, &i, sizeof(i));\n    priv->off+=sizeof(i);\n    return 0;\n}\nint oa_start_vector(struct oarchive *oa, const char *tag, const int32_t *count)\n{\n    return oa_serialize_int(oa, tag, count);\n}\nint oa_end_vector(struct oarchive *oa, const char *tag)\n{\n    return 0;\n}\nint oa_serialize_bool(struct oarchive *oa, const char *name, const int32_t *i)\n{\n    //return oa_serialize_int(oa, name, i);\n    struct buff_struct *priv = oa->priv;\n    if ((priv->len - priv->off) < 1) {\n        int rc = resize_buffer(priv, priv->len + 1);\n        if (rc < 0)\n            return rc;\n    }\n    priv->buffer[priv->off] = (*i == 0 ? '\\0' : '\\1');\n    priv->off++;\n    return 0;\n}\nstatic const int32_t negone = -1;\nint oa_serialize_buffer(struct oarchive *oa, const char *name,\n        const struct buffer *b)\n{\n    struct buff_struct *priv = oa->priv;\n    int rc;\n    if (!b) {\n        return oa_serialize_int(oa, \"len\", &negone);\n    }\n    rc = oa_serialize_int(oa, \"len\", &b->len);\n    if (rc < 0)\n        return rc;\n    // this means a buffer of NUll \n    // with size of -1. This is \n    // waht we use in java serialization for NULL\n    if (b->len == -1) {\n      return rc;\n    }\n    if ((priv->len - priv->off) < b->len) {\n        rc = resize_buffer(priv, priv->len + b->len);\n        if (rc < 0)\n            return rc;\n    }\n    memcpy(priv->buffer+priv->off, b->buff, b->len);\n    priv->off += b->len;\n    return 0;\n}\nint oa_serialize_string(struct oarchive *oa, const char *name, char **s)\n{\n    struct buff_struct *priv = oa->priv;\n    int32_t len;\n    int rc;\n    if (!*s) {\n        oa_serialize_int(oa, \"len\", &negone);\n        return 0;\n    }\n    len = strlen(*s);\n    rc = oa_serialize_int(oa, \"len\", &len);\n    if (rc < 0)\n        return rc;\n    if ((priv->len - priv->off) < len) {\n        rc = resize_buffer(priv, priv->len + len);\n        if (rc < 0)\n            return rc;\n    }\n    memcpy(priv->buffer+priv->off, *s, len);\n    priv->off += len;\n    return 0;\n}\nint ia_start_record(struct iarchive *ia, const char *tag)\n{\n    return 0;\n}\nint ia_end_record(struct iarchive *ia, const char *tag)\n{\n    return 0;\n}\nint ia_deserialize_int(struct iarchive *ia, const char *tag, int32_t *count)\n{\n    struct buff_struct *priv = ia->priv;\n    if ((priv->len - priv->off) < sizeof(*count)) {\n        return -E2BIG;\n    }\n    memcpy(count, priv->buffer+priv->off, sizeof(*count));\n    priv->off+=sizeof(*count);\n    *count = ntohl(*count);\n    return 0;\n}\n\nint ia_deserialize_long(struct iarchive *ia, const char *tag, int64_t *count)\n{\n    struct buff_struct *priv = ia->priv;\n    int64_t v = 0;\n    if ((priv->len - priv->off) < sizeof(*count)) {\n        return -E2BIG;\n    }\n    memcpy(count, priv->buffer+priv->off, sizeof(*count));\n    priv->off+=sizeof(*count);\n    v = zoo_htonll(*count); // htonll and  ntohll do the same\n    *count = v;\n    return 0;\n}\nint ia_start_vector(struct iarchive *ia, const char *tag, int32_t *count)\n{\n    return ia_deserialize_int(ia, tag, count);\n}\nint ia_end_vector(struct iarchive *ia, const char *tag)\n{\n    return 0;\n}\nint ia_deserialize_bool(struct iarchive *ia, const char *name, int32_t *v)\n{\n    struct buff_struct *priv = ia->priv;\n    //fprintf(stderr, \"Deserializing bool %d\\n\", priv->off);\n    //return ia_deserialize_int(ia, name, v);\n    if ((priv->len - priv->off) < 1) {\n        return -E2BIG;\n    }\n    *v = priv->buffer[priv->off];\n    priv->off+=1;\n    //fprintf(stderr, \"Deserializing bool end %d\\n\", priv->off);\n    return 0;\n}\nint ia_deserialize_buffer(struct iarchive *ia, const char *name,\n        struct buffer *b)\n{\n    struct buff_struct *priv = ia->priv;\n    int rc = ia_deserialize_int(ia, \"len\", &b->len);\n    if (rc < 0)\n        return rc;\n    if ((priv->len - priv->off) < b->len) {\n        return -E2BIG;\n    }\n    // set the buffer to null\n    if (b->len == -1) {\n       b->buff = NULL;\n       return rc;\n    }\n    b->buff = malloc(b->len);\n    if (!b->buff) {\n        return -ENOMEM;\n    }\n    memcpy(b->buff, priv->buffer+priv->off, b->len);\n    priv->off += b->len;\n    return 0;\n}\nint ia_deserialize_string(struct iarchive *ia, const char *name, char **s)\n{\n    struct buff_struct *priv = ia->priv;\n    int32_t len;\n    int rc = ia_deserialize_int(ia, \"len\", &len);\n    if (rc < 0)\n        return rc;\n    if ((priv->len - priv->off) < len) {\n        return -E2BIG;\n    }\n    if (len < 0) {\n        return -EINVAL;\n    }\n    *s = malloc(len+1);\n    if (!*s) {\n        return -ENOMEM;\n    }\n    memcpy(*s, priv->buffer+priv->off, len);\n    (*s)[len] = '\\0';\n    priv->off += len;\n    return 0;\n}\n\nstatic struct iarchive ia_default = { STRUCT_INITIALIZER (start_record ,ia_start_record),\n        STRUCT_INITIALIZER (end_record ,ia_end_record), STRUCT_INITIALIZER (start_vector , ia_start_vector),\n        STRUCT_INITIALIZER (end_vector ,ia_end_vector), STRUCT_INITIALIZER (deserialize_Bool , ia_deserialize_bool),\n        STRUCT_INITIALIZER (deserialize_Int ,ia_deserialize_int),\n        STRUCT_INITIALIZER (deserialize_Long , ia_deserialize_long) ,\n        STRUCT_INITIALIZER (deserialize_Buffer, ia_deserialize_buffer),\n        STRUCT_INITIALIZER (deserialize_String, ia_deserialize_string)   };\n\nstatic struct oarchive oa_default = { STRUCT_INITIALIZER (start_record , oa_start_record),\n        STRUCT_INITIALIZER (end_record , oa_end_record), STRUCT_INITIALIZER (start_vector , oa_start_vector),\n        STRUCT_INITIALIZER (end_vector , oa_end_vector), STRUCT_INITIALIZER (serialize_Bool , oa_serialize_bool),\n        STRUCT_INITIALIZER (serialize_Int , oa_serialize_int),\n        STRUCT_INITIALIZER (serialize_Long , oa_serialize_long) ,\n        STRUCT_INITIALIZER (serialize_Buffer , oa_serialize_buffer),\n        STRUCT_INITIALIZER (serialize_String , oa_serialize_string) };\n\nstruct iarchive *create_buffer_iarchive(char *buffer, int len)\n{\n    struct iarchive *ia;\n    struct buff_struct *buff;\n    ia = malloc(sizeof(*ia));\n    if (!ia) return 0;\n    buff = malloc(sizeof(struct buff_struct));\n    if (!buff) {\n        free(ia);\n        return 0;\n    }\n    *ia = ia_default;\n    buff->off = 0;\n    buff->buffer = buffer;\n    buff->len = len;\n    ia->priv = buff;\n    return ia;\n}\n\nstruct oarchive *create_buffer_oarchive()\n{\n    struct oarchive *oa;\n    struct buff_struct *buff;\n    oa = malloc(sizeof(*oa));\n    if (!oa) return 0;\n    buff = malloc(sizeof(struct buff_struct));\n    if (!buff) {\n        free(oa);\n        return 0;\n    }\n    *oa = oa_default;\n    buff->off = 0;\n    buff->buffer = malloc(128);\n    buff->len = 128;\n    oa->priv = buff;\n    return oa;\n}\n\nvoid close_buffer_iarchive(struct iarchive **ia)\n{\n    free((*ia)->priv);\n    free(*ia);\n    *ia = 0;\n}\n\nvoid close_buffer_oarchive(struct oarchive **oa, int free_buffer)\n{\n    if (free_buffer) {\n        struct buff_struct *buff = (struct buff_struct *)(*oa)->priv;\n        if (buff->buffer) {\n            free(buff->buffer);\n        }\n    }\n    free((*oa)->priv);\n    free(*oa);\n    *oa = 0;\n}\n\nchar *get_buffer(struct oarchive *oa)\n{\n    struct buff_struct *buff = oa->priv;\n    return buff->buffer;\n}\nint get_buffer_len(struct oarchive *oa)\n{\n    struct buff_struct *buff = oa->priv;\n    return buff->off;\n}\n"
  },
  {
    "path": "src/c/src/st_adaptor.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef DLL_EXPORT\n#  define USE_STATIC_LIB\n#endif\n\n#include \"zk_adaptor.h\"\n#include <stdlib.h>\n#include <time.h>\n\nint zoo_lock_auth(zhandle_t *zh)\n{\n\treturn 0;\n}\nint zoo_unlock_auth(zhandle_t *zh)\n{\n\treturn 0;\n}\nint lock_buffer_list(buffer_head_t *l)\n{\n\treturn 0;\n}\nint unlock_buffer_list(buffer_head_t *l)\n{\n\treturn 0;\n}\nint lock_completion_list(completion_head_t *l)\n{\n\treturn 0;\n}\nint unlock_completion_list(completion_head_t *l)\n{\n\treturn 0;\n}\nstruct sync_completion *alloc_sync_completion(void)\n{\n    return (struct sync_completion*)calloc(1, sizeof(struct sync_completion));\n}\nint wait_sync_completion(struct sync_completion *sc)\n{\n    return 0;\n}\n\nvoid free_sync_completion(struct sync_completion *sc)\n{\n    free(sc);\n}\n\nvoid notify_sync_completion(struct sync_completion *sc)\n{\n}\n\nint process_async(int outstanding_sync)\n{\n    return outstanding_sync == 0;\n}\n\nint adaptor_init(zhandle_t *zh)\n{\n    return 0;\n}\n\nvoid adaptor_finish(zhandle_t *zh){}\n\nvoid adaptor_destroy(zhandle_t *zh){}\n\nint flush_send_queue(zhandle_t *, int);\n\nint adaptor_send_queue(zhandle_t *zh, int timeout)\n{\n    return flush_send_queue(zh, timeout);\n}\n\nint32_t inc_ref_counter(zhandle_t* zh,int i)\n{\n    zh->ref_counter+=(i<0?-1:(i>0?1:0));\n    return zh->ref_counter;\n}\n\nint32_t get_xid()\n{\n    static int32_t xid = -1;\n    if (xid == -1) {\n        xid = time(0);\n    }\n    return xid++;\n}\n\nint enter_critical(zhandle_t* zh)\n{\n\treturn 0;\n}\n\nint leave_critical(zhandle_t* zh)\n{\n\treturn 0;\n}\n"
  },
  {
    "path": "src/c/src/winport.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifdef WIN32\n#include \"winport.h\"\n#include <stdlib.h>\n#include <stdint.h> /* for int64_t */\n#include <winsock2.h> /* must always be included before ws2tcpip.h */\n#include <ws2tcpip.h> /* for SOCKET */\n\nint pthread_mutex_lock(pthread_mutex_t* _mutex ){      \n       int rc = WaitForSingleObject( *_mutex,    // handle to mutex\n            INFINITE);  // no time-out interval\n       return ((rc == WAIT_OBJECT_0) ? 0: rc); \n}\n\nint pthread_mutex_unlock( pthread_mutex_t* _mutex ){   \n       int rc = ReleaseMutex(*_mutex);\n       return ((rc != 0)? 0: GetLastError());  \n}\n\nint pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr){\n       //use CreateMutex as we are using the HANDLES in pthread_cond\n       *_mutex = CreateMutex( \n        NULL,              // default security attributes\n        FALSE,             // initially not owned\n        NULL);             // unnamed mutex    \n       return ((*_mutex == NULL) ? GetLastError() : 0);\n}\n\nint pthread_mutex_destroy(pthread_mutex_t* _mutex)\n{\n       int rc = CloseHandle(*_mutex);\n       return ((rc != 0)? 0: GetLastError());  \n}\n\nint pthread_create(pthread_t *thread, const pthread_attr_t *attr, unsigned  (__stdcall* start_routine)(void* a), void *arg)\n{\n   int _intThreadId; \n   (*thread).thread_handle = (HANDLE)_beginthreadex( NULL, 0, start_routine , arg, 0, (unsigned int*)&_intThreadId );\n   (*thread).thread_id = _intThreadId;\n   return (((*thread).thread_handle == 0 ) ? errno : 0 );         \n}\n\n\nint pthread_equal(pthread_t t1, pthread_t t2){\n//Is there a better way to do this? GetThreadId(handle) is only supported Windows 2003 n above.\n       return ((t1.thread_id == t2.thread_id) ? 1:0);              \n}\n\npthread_t pthread_self(){\n    pthread_t thread_self;\n    thread_self.thread_handle = GetCurrentThread();\n    thread_self.thread_id     = GetCurrentThreadId();\n    return thread_self;\n}\n\nint pthread_join(pthread_t _thread, void** ignore)\n{\n       int rc = WaitForSingleObject( _thread.thread_handle, INFINITE );\n       return ((rc == WAIT_OBJECT_0) ? 0: rc); \n}\n\nint pthread_detach(pthread_t _thread)\n{\n       int rc = CloseHandle(_thread.thread_handle) ;\n       return  (rc != 0) ? 0: GetLastError();\n}\n\nvoid pthread_mutexattr_init(pthread_mutexattr_t* ignore){}\nvoid pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore){}\nvoid pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr){}\n       \nint \npthread_cond_init (pthread_cond_t *cv,\n                   const pthread_condattr_t * ignore)\n{\n  cv->waiters_count_ = 0;\n  cv->was_broadcast_ = 0;\n  cv->sema_ = CreateSemaphore (NULL,       // no security\n                                0,          // initially 0\n                                0x7fffffff, // max count\n                                NULL);      // unnamed \n  if (cv->sema_ == NULL ) \n               return GetLastError();\n  InitializeCriticalSection (&cv->waiters_count_lock_);\n  cv->waiters_done_ = CreateEvent (NULL,  // no security\n                                   FALSE, // auto-reset\n                                   FALSE, // non-signaled initially\n                                   NULL); // unnamed\n  return (cv->waiters_done_ == NULL) ? GetLastError() : 0;\n       \n}\n\n\nint pthread_cond_destroy(pthread_cond_t *cond)\n{\n       CloseHandle( cond->sema_);\n       DeleteCriticalSection(&cond->waiters_count_lock_);\n       return (CloseHandle( cond->waiters_done_ ) == 0)? GetLastError(): 0 ;\n}\n\n\nint\npthread_cond_signal (pthread_cond_t *cv)\n{\n  int have_waiters;\n  EnterCriticalSection (& (cv->waiters_count_lock_));\n  have_waiters = cv->waiters_count_ > 0;\n  LeaveCriticalSection (&cv->waiters_count_lock_);\n\n  // If there aren't any waiters, then this is a no-op.  \n  if (have_waiters){\n         return (ReleaseSemaphore (cv->sema_, 1, 0) == 0 )  ? GetLastError() : 0 ;\n  }else\n         return 0;\n}\n\n\nint\npthread_cond_broadcast (pthread_cond_t *cv)\n{\n  // This is needed to ensure that <waiters_count_> and <was_broadcast_> are\n  // consistent relative to each other.\n  int have_waiters = 0;\n  EnterCriticalSection (&cv->waiters_count_lock_);\n  \n  if (cv->waiters_count_ > 0) {\n    // We are broadcasting, even if there is just one waiter...\n    // Record that we are broadcasting, which helps optimize\n    // <pthread_cond_wait> for the non-broadcast case.\n    cv->was_broadcast_ = 1;\n    have_waiters = 1;\n  }\n\n  if (have_waiters) {\n    // Wake up all the waiters atomically.\n    ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);\n\n    LeaveCriticalSection (&cv->waiters_count_lock_);\n\n    // Wait for all the awakened threads to acquire the counting\n    // semaphore. \n    WaitForSingleObject (cv->waiters_done_, INFINITE);\n    // This assignment is okay, even without the <waiters_count_lock_> held \n    // because no other waiter threads can wake up to access it.\n    cv->was_broadcast_ = 0;\n  }\n  else\n    LeaveCriticalSection (&cv->waiters_count_lock_);\n}\n\n\nint\npthread_cond_wait (pthread_cond_t *cv, \n                   pthread_mutex_t *external_mutex)\n{\n  int last_waiter;\n  // Avoid race conditions.\n  EnterCriticalSection (&cv->waiters_count_lock_);\n  cv->waiters_count_++;\n  LeaveCriticalSection (&cv->waiters_count_lock_);\n\n  // This call atomically releases the mutex and waits on the\n  // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>\n  // are called by another thread.\n  SignalObjectAndWait (*external_mutex, cv->sema_, INFINITE, FALSE);\n\n  // Reacquire lock to avoid race conditions.\n  EnterCriticalSection (&cv->waiters_count_lock_);\n\n  // We're no longer waiting...\n  cv->waiters_count_--;\n\n  // Check to see if we're the last waiter after <pthread_cond_broadcast>.\n  last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;\n\n  LeaveCriticalSection (&cv->waiters_count_lock_);\n\n  // If we're the last waiter thread during this particular broadcast\n  // then let all the other threads proceed.\n  if (last_waiter)\n    // This call atomically signals the <waiters_done_> event and waits until\n    // it can acquire the <external_mutex>.  This is required to ensure fairness. \n    SignalObjectAndWait (cv->waiters_done_, *external_mutex, INFINITE, FALSE);\n  else\n    // Always regain the external mutex since that's the guarantee we\n    // give to our callers. \n    WaitForSingleObject (*external_mutex, INFINITE);\n}\n\nint pthread_key_create(pthread_key_t *key, void (*destructor)(void *) )\n{\n  int result = 0;\n  pthread_key_t* newkey;\n\n  if ((newkey = (pthread_key_t*) calloc (1, sizeof (pthread_key_t))) == NULL)\n    {\n      result = ENOMEM;\n    }\n  else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES)\n    {\n      result = EAGAIN;\n      free (newkey);\n      newkey = NULL;\n    }\n  else if (destructor != NULL)\n    {\n      //--we have to store the function pointer for destructor, so that we can call it \n         //--to free up the user allocated storage--       \n      newkey->destructor = destructor;\n    }\n  key = newkey;  \n  return (result);     \n}\n\nint pthread_key_delete(pthread_key_t key)\n{\n  int rc = 0;\n  LPVOID lpvData =  TlsGetValue(key.key);\n  rc = TlsFree (key.key);\n  rc = (rc != 0 ) ? 0 : GetLastError();\n  if (key.destructor != NULL && lpvData != 0){\n       key.destructor(lpvData);         //we take control of calling destructor, instead of calling it on thread exit.\n  }\n  free (&key);\n  return (rc);\n}\n\nvoid *pthread_getspecific(pthread_key_t key)\n{\n       LPVOID lpvData =  TlsGetValue(key.key);\n       if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS)) \n               return NULL;\n       else \n               return lpvData;\n}\n\nint pthread_setspecific(pthread_key_t key, const void *value)\n{\n       int rc = TlsSetValue (key.key, value);\n       return ((rc != 0 ) ? 0 : GetLastError());\n}\n\nint gettimeofday(struct timeval *tp, void *tzp) {\n        int64_t now = 0;\n        if (tzp != 0) { errno = EINVAL; return -1; }\n        GetSystemTimeAsFileTime( (LPFILETIME)&now );\n        tp->tv_sec = (long)(now / 10000000 - 11644473600LL);\n        tp->tv_usec = (now / 10) % 1000000;\n        return 0;\n}\n\nint close(SOCKET fd) {\n        return closesocket(fd);\n}\n\nint Win32WSAStartup()\n{\n       WORD    wVersionRq;\n       WSADATA wsaData;\n       int             err;\n\n       wVersionRq = MAKEWORD(2,0);\n       err = WSAStartup(wVersionRq, &wsaData);\n       if (err != 0)\n               return 1;\n       \n       // confirm the version information\n       if ((LOBYTE(wsaData.wVersion) != 2) ||\n           (HIBYTE(wsaData.wVersion) != 0))\n       {\n               Win32WSACleanup();              \n               return 1;\n       }\n       return 0;\n}\n\nvoid Win32WSACleanup()\n{\n       WSACleanup();\n}\n\n#endif //WIN32\n\n\n\n"
  },
  {
    "path": "src/c/src/winport.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * This header file is to port pthread lib , sockets and other utility methods on windows.\n * Specifically the threads function, mutexes, keys, and socket initialization.\n */\n\n#ifndef WINPORT_H_\n#define WINPORT_H_\n\n#ifdef WIN32\n#include \"winconfig.h\"\n\n#define _WINSOCK_DEPRECATED_NO_WARNINGS\n#include <winsock2.h> /* must always be included before ws2tcpip.h */\n#include <ws2tcpip.h> /* for struct sock_addr used in zookeeper.h */\n\n/* POSIX names are deprecated, use ISO conformant names instead. */\n#define strdup _strdup\n#define getcwd _getcwd\n#define getpid _getpid\n\n/* Windows \"secure\" versions of POSIX reentrant functions */\n#define strtok_r strtok_s\n#define localtime_r(a,b) localtime_s(b,a)\n\n/* After this version of MSVC, snprintf became a defined function,\n   and so cannot be redefined, nor can #ifndef be used to guard it. */\n#if ((defined(_MSC_VER) && _MSC_VER < 1900) || !defined(_MSC_VER))\n#define snprintf _snprintf\n#endif\n\n\n#include <errno.h>\n#include <process.h>\n#include <stdint.h> /* for int64_t */\n#include <stdlib.h>\n#include <malloc.h>\n\n\ntypedef int ssize_t;\ntypedef HANDLE pthread_mutex_t;\n\nstruct pthread_t_\n{\n  HANDLE thread_handle;\n  DWORD  thread_id;\n};\n\ntypedef struct pthread_t_ pthread_t;\ntypedef int pthread_mutexattr_t;       \ntypedef int pthread_condattr_t;        \ntypedef int pthread_attr_t; \n#define PTHREAD_MUTEX_RECURSIVE 0\n\nint pthread_mutex_lock(pthread_mutex_t* _mutex );\nint pthread_mutex_unlock( pthread_mutex_t* _mutex );\nint pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr);\nint pthread_mutex_destroy(pthread_mutex_t* _mutex);\nint pthread_create(pthread_t *thread, const pthread_attr_t *attr, unsigned  (__stdcall* start_routine)(void* a), void *arg);\nint pthread_equal(pthread_t t1, pthread_t t2);\npthread_t pthread_self();\nint pthread_join(pthread_t _thread, void** ignore);\nint pthread_detach(pthread_t _thread);\n\nvoid pthread_mutexattr_init(pthread_mutexattr_t* ignore);\nvoid pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore);\nvoid pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr);\n\n\n// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html\n \ntypedef struct \n{\n       int waiters_count_;\n    // Number of waiting threads.\n\n    CRITICAL_SECTION waiters_count_lock_;\n    // Serialize access to <waiters_count_>.\n\n    HANDLE sema_;\n       // Semaphore used to queue up threads waiting for the condition to\n    // become signaled. \n\n    HANDLE waiters_done_;\n    // An auto-reset event used by the broadcast/signal thread to wait\n    // for all the waiting thread(s) to wake up and be released from the\n    // semaphore. \n\n    size_t was_broadcast_;\n    // Keeps track of whether we were broadcasting or signaling.  This\n    // allows us to optimize the code if we're just signaling.\n}pthread_cond_t;\n       \nint pthread_cond_init (pthread_cond_t *cv,const pthread_condattr_t * ignore);\nint pthread_cond_destroy(pthread_cond_t *cond);\nint pthread_cond_signal (pthread_cond_t *cv);\nint pthread_cond_broadcast (pthread_cond_t *cv);\nint pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *external_mutex);\n\n\nstruct pthread_key_t_\n{\n  DWORD key;\n  void (*destructor) (void *);  \n};\n\ntypedef struct pthread_key_t_ pthread_key_t;\nint pthread_key_create(pthread_key_t *key, void (*destructor)(void *) );\nint pthread_key_delete(pthread_key_t key);\nvoid *pthread_getspecific(pthread_key_t key);\nint pthread_setspecific(pthread_key_t key, const void *value);\n\nint gettimeofday(struct timeval *tp, void *tzp);\nint close(SOCKET fd);\nint Win32WSAStartup();\nvoid Win32WSACleanup();\n#endif //WIN32\n\n\n\n#endif //WINPORT_H_\n"
  },
  {
    "path": "src/c/src/zk_adaptor.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZK_ADAPTOR_H_\n#define ZK_ADAPTOR_H_\n#include <zookeeper.jute.h>\n#ifdef THREADED\n#ifndef WIN32\n#include <pthread.h>\n#else\n#include \"winport.h\"\n#endif\n#endif\n#include \"zookeeper.h\"\n#include \"zk_hashtable.h\"\n\n/* predefined xid's values recognized as special by the server */\n#define WATCHER_EVENT_XID -1 \n#define PING_XID -2\n#define AUTH_XID -4\n#define SET_WATCHES_XID -8\n\n/* zookeeper state constants */\n#define EXPIRED_SESSION_STATE_DEF -112\n#define AUTH_FAILED_STATE_DEF -113\n#define CONNECTING_STATE_DEF 1\n#define ASSOCIATING_STATE_DEF 2\n#define CONNECTED_STATE_DEF 3\n#define NOTCONNECTED_STATE_DEF 999\n\n/* zookeeper event type constants */\n#define CREATED_EVENT_DEF 1\n#define DELETED_EVENT_DEF 2\n#define CHANGED_EVENT_DEF 3\n#define CHILD_EVENT_DEF 4\n#define SESSION_EVENT_DEF -1\n#define NOTWATCHING_EVENT_DEF -2\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct _buffer_list;\nstruct _completion_list;\n\ntypedef struct _buffer_head {\n    struct _buffer_list *volatile head;\n    struct _buffer_list *last;\n#ifdef THREADED\n    pthread_mutex_t lock;\n#endif\n} buffer_head_t;\n\ntypedef struct _completion_head {\n    struct _completion_list *volatile head;\n    struct _completion_list *last;\n#ifdef THREADED\n    pthread_cond_t cond;\n    pthread_mutex_t lock;\n#endif\n} completion_head_t;\n\nint lock_buffer_list(buffer_head_t *l);\nint unlock_buffer_list(buffer_head_t *l);\nint lock_completion_list(completion_head_t *l);\nint unlock_completion_list(completion_head_t *l);\n\nstruct sync_completion {\n    int rc;\n    union {\n        struct {\n            char *str;\n            int str_len;\n        } str;\n        struct Stat stat;\n        struct {\n            char *buffer;\n            int buff_len;\n            struct Stat stat;\n        } data;\n        struct {\n            struct ACL_vector acl;\n            struct Stat stat;\n        } acl;\n        struct String_vector strs2;\n        struct {\n            struct String_vector strs2;\n            struct Stat stat2;\n        } strs_stat;\n    } u;\n    int complete;\n#ifdef THREADED\n    pthread_cond_t cond;\n    pthread_mutex_t lock;\n#endif\n};\n\ntypedef struct _auth_info {\n    int state; /* 0=>inactive, >0 => active */\n    char* scheme;\n    struct buffer auth;\n    void_completion_t completion;\n    const char* data;\n    struct _auth_info *next;\n} auth_info;\n\n/**\n * This structure represents a packet being read or written.\n */\ntypedef struct _buffer_list {\n    char *buffer;\n    int len; /* This represents the length of sizeof(header) + length of buffer */\n    int curr_offset; /* This is the offset into the header followed by offset into the buffer */\n    struct _buffer_list *next;\n} buffer_list_t;\n\n/* the size of connect request */\n#define HANDSHAKE_REQ_SIZE 44\n/* connect request */\nstruct connect_req {\n    int32_t protocolVersion;\n    int64_t lastZxidSeen;\n    int32_t timeOut;\n    int64_t sessionId;\n    int32_t passwd_len;\n    char passwd[16];\n};\n\n/* the connect response */\nstruct prime_struct {\n    int32_t len;\n    int32_t protocolVersion;\n    int32_t timeOut;\n    int64_t sessionId;\n    int32_t passwd_len;\n    char passwd[16];\n}; \n\n#ifdef THREADED\n/* this is used by mt_adaptor internally for thread management */\nstruct adaptor_threads {\n     pthread_t io;\n     pthread_t completion;\n     int threadsToWait;         // barrier\n     pthread_cond_t cond;       // barrier's conditional\n     pthread_mutex_t lock;      // ... and a lock\n     pthread_mutex_t zh_lock;   // critical section lock\n#ifdef WIN32\n     SOCKET self_pipe[2];\n#else\n     int self_pipe[2];\n#endif\n};\n#endif\n\n/** the auth list for adding auth */\ntypedef struct _auth_list_head {\n     auth_info *auth;\n#ifdef THREADED\n     pthread_mutex_t lock;\n#endif\n} auth_list_head_t;\n\n/**\n * This structure represents the connection to zookeeper.\n */\n\nstruct _zhandle {\n#ifdef WIN32\n    SOCKET fd; /* the descriptor used to talk to zookeeper */\n#else\n    int fd; /* the descriptor used to talk to zookeeper */\n#endif\n    char *hostname; /* the hostname of zookeeper */\n    struct sockaddr_storage *addrs; /* the addresses that correspond to the hostname */\n    int addrs_count; /* The number of addresses in the addrs array */\n    watcher_fn watcher; /* the registered watcher */\n    struct timeval last_recv; /* The time that the last message was received */\n    struct timeval last_send; /* The time that the last message was sent */\n    struct timeval last_ping; /* The time that the last PING was sent */\n    struct timeval next_deadline; /* The time of the next deadline */\n    int recv_timeout; /* The maximum amount of time that can go by without \n     receiving anything from the zookeeper server */\n    buffer_list_t *input_buffer; /* the current buffer being read in */\n    buffer_head_t to_process; /* The buffers that have been read and are ready to be processed. */\n    buffer_head_t to_send; /* The packets queued to send */\n    completion_head_t sent_requests; /* The outstanding requests */\n    completion_head_t completions_to_process; /* completions that are ready to run */\n    int connect_index; /* The index of the address to connect to */\n    clientid_t client_id;\n    long long last_zxid;\n    int outstanding_sync; /* Number of outstanding synchronous requests */\n    struct _buffer_list primer_buffer; /* The buffer used for the handshake at the start of a connection */\n    struct prime_struct primer_storage; /* the connect response */\n    char primer_storage_buffer[40]; /* the true size of primer_storage */\n    volatile int state;\n    void *context;\n    auth_list_head_t auth_h; /* authentication data list */\n    /* zookeeper_close is not reentrant because it de-allocates the zhandler. \n     * This guard variable is used to defer the destruction of zhandle till \n     * right before top-level API call returns to the caller */\n    int32_t ref_counter;\n    volatile int close_requested;\n    void *adaptor_priv;\n    /* Used for debugging only: non-zero value indicates the time when the zookeeper_process\n     * call returned while there was at least one unprocessed server response \n     * available in the socket recv buffer */\n    struct timeval socket_readable;\n    \n    zk_hashtable* active_node_watchers;   \n    zk_hashtable* active_exist_watchers;\n    zk_hashtable* active_child_watchers;\n    /** used for chroot path at the client side **/\n    char *chroot;\n};\n\n\nint adaptor_init(zhandle_t *zh);\nvoid adaptor_finish(zhandle_t *zh);\nvoid adaptor_destroy(zhandle_t *zh);\nstruct sync_completion *alloc_sync_completion(void);\nint wait_sync_completion(struct sync_completion *sc);\nvoid free_sync_completion(struct sync_completion *sc);\nvoid notify_sync_completion(struct sync_completion *sc);\nint adaptor_send_queue(zhandle_t *zh, int timeout);\nint process_async(int outstanding_sync);\nvoid process_completions(zhandle_t *zh);\nint flush_send_queue(zhandle_t*zh, int timeout);\nchar* sub_string(zhandle_t *zh, const char* server_path);\nvoid free_duplicate_path(const char* free_path, const char* path);\nint zoo_lock_auth(zhandle_t *zh);\nint zoo_unlock_auth(zhandle_t *zh);\n\n// critical section guards\nint enter_critical(zhandle_t* zh);\nint leave_critical(zhandle_t* zh);\n// zhandle object reference counting\nvoid api_prolog(zhandle_t* zh);\nint api_epilog(zhandle_t *zh, int rc);\nint32_t get_xid();\n// returns the new value of the ref counter\nint32_t inc_ref_counter(zhandle_t* zh,int i);\n\n#ifdef THREADED\n// atomic post-increment\nint32_t fetch_and_add(volatile int32_t* operand, int incr);\n// in mt mode process session event asynchronously by the completion thread\n#define PROCESS_SESSION_EVENT(zh,newstate) queue_session_event(zh,newstate)\n#else\n// in single-threaded mode process session event immediately\n//#define PROCESS_SESSION_EVENT(zh,newstate) deliverWatchers(zh,ZOO_SESSION_EVENT,newstate,0)\n#define PROCESS_SESSION_EVENT(zh,newstate) queue_session_event(zh,newstate)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*ZK_ADAPTOR_H_*/\n\n\n"
  },
  {
    "path": "src/c/src/zk_hashtable.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"zk_hashtable.h\"\n#include \"zk_adaptor.h\"\n#include \"hashtable/hashtable.h\"\n#include \"hashtable/hashtable_itr.h\"\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n\ntypedef struct _watcher_object {\n    watcher_fn watcher;\n    void* context;\n    struct _watcher_object* next;\n} watcher_object_t;\n\n\nstruct _zk_hashtable {\n    struct hashtable* ht;\n};\n\nstruct watcher_object_list {\n    watcher_object_t* head;\n};\n\n/* the following functions are for testing only */\ntypedef struct hashtable hashtable_impl;\n\nhashtable_impl* getImpl(zk_hashtable* ht){\n    return ht->ht;\n}\n\nwatcher_object_t* getFirstWatcher(zk_hashtable* ht,const char* path)\n{\n    watcher_object_list_t* wl=hashtable_search(ht->ht,(void*)path);\n    if(wl!=0)\n        return wl->head;\n    return 0;\n}\n/* end of testing functions */\n\nwatcher_object_t* clone_watcher_object(watcher_object_t* wo)\n{\n    watcher_object_t* res=calloc(1,sizeof(watcher_object_t));\n    assert(res);\n    res->watcher=wo->watcher;\n    res->context=wo->context;\n    return res;\n}\n\nstatic unsigned int string_hash_djb2(void *str) \n{\n    unsigned int hash = 5381;\n    int c;\n    const char* cstr = (const char*)str;\n    while ((c = *cstr++))\n        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */\n\n    return hash;\n}\n\nstatic int string_equal(void *key1,void *key2)\n{\n    return strcmp((const char*)key1,(const char*)key2)==0;\n}\n\nstatic watcher_object_t* create_watcher_object(watcher_fn watcher,void* ctx)\n{\n    watcher_object_t* wo=calloc(1,sizeof(watcher_object_t));\n    assert(wo);\n    wo->watcher=watcher;\n    wo->context=ctx;\n    return wo;\n}\n\nstatic watcher_object_list_t* create_watcher_object_list(watcher_object_t* head) \n{\n    watcher_object_list_t* wl=calloc(1,sizeof(watcher_object_list_t));\n    assert(wl);\n    wl->head=head;\n    return wl;\n}\n\nstatic void destroy_watcher_object_list(watcher_object_list_t* list)\n{\n    watcher_object_t* e = NULL;\n\n    if(list==0)\n        return;\n    e=list->head;\n    while(e!=0){\n        watcher_object_t* this=e;\n        e=e->next;\n        free(this);\n    }\n    free(list);\n}\n\nzk_hashtable* create_zk_hashtable()\n{\n    struct _zk_hashtable *ht=calloc(1,sizeof(struct _zk_hashtable));\n    assert(ht);\n    ht->ht=create_hashtable(32,string_hash_djb2,string_equal);\n    return ht;\n}\n\nstatic void do_clean_hashtable(zk_hashtable* ht)\n{\n    struct hashtable_itr *it;\n    int hasMore;\n    if(hashtable_count(ht->ht)==0)\n        return;\n    it=hashtable_iterator(ht->ht);\n    do {\n        watcher_object_list_t* w=hashtable_iterator_value(it);\n        destroy_watcher_object_list(w);\n        hasMore=hashtable_iterator_remove(it);\n    } while(hasMore);\n    free(it);\n}\n\nvoid destroy_zk_hashtable(zk_hashtable* ht)\n{\n    if(ht!=0){\n        do_clean_hashtable(ht);\n        hashtable_destroy(ht->ht,0);\n        free(ht);\n    }\n}\n\n// searches for a watcher object instance in a watcher object list;\n// two watcher objects are equal if their watcher function and context pointers\n// are equal\nstatic watcher_object_t* search_watcher(watcher_object_list_t** wl,watcher_object_t* wo)\n{\n    watcher_object_t* wobj=(*wl)->head;\n    while(wobj!=0){\n        if(wobj->watcher==wo->watcher && wobj->context==wo->context)\n            return wobj;\n        wobj=wobj->next;\n    }\n    return 0;\n}\n\nstatic int add_to_list(watcher_object_list_t **wl, watcher_object_t *wo,\n                       int clone)\n{\n    if (search_watcher(wl, wo)==0) {\n        watcher_object_t* cloned=wo;\n        if (clone) {\n            cloned = clone_watcher_object(wo);\n            assert(cloned);\n        }\n        cloned->next = (*wl)->head;\n        (*wl)->head = cloned;\n        return 1;\n    } else if (!clone) {\n        // If it's here and we aren't supposed to clone, we must destroy\n        free(wo);\n    }\n    return 0;\n}\n\nstatic int do_insert_watcher_object(zk_hashtable *ht, const char *path, watcher_object_t* wo)\n{\n    int res=1;\n    watcher_object_list_t* wl;\n\n    wl=hashtable_search(ht->ht,(void*)path);\n    if(wl==0){\n        int res;\n        /* inserting a new path element */\n        res=hashtable_insert(ht->ht,strdup(path),create_watcher_object_list(wo));\n        assert(res);\n    }else{\n        /*\n         * Path already exists; check if the watcher already exists.\n         * Don't clone the watcher since it's allocated on the heap --- avoids\n         * a memory leak and saves a clone operation (calloc + copy).\n         */\n        res = add_to_list(&wl, wo, 0);\n    }\n    return res;    \n}\n\n\nchar **collect_keys(zk_hashtable *ht, int *count)\n{\n    char **list;\n    struct hashtable_itr *it;\n    int i;\n\n    *count = hashtable_count(ht->ht);\n    list = calloc(*count, sizeof(char*));\n    it=hashtable_iterator(ht->ht);\n    for(i = 0; i < *count; i++) {\n        list[i] = strdup(hashtable_iterator_key(it));\n        hashtable_iterator_advance(it);\n    }\n    free(it);\n    return list;\n}\n\nstatic int insert_watcher_object(zk_hashtable *ht, const char *path,\n                                 watcher_object_t* wo)\n{\n    int res;\n    res=do_insert_watcher_object(ht,path,wo);\n    return res;\n}\n\nstatic void copy_watchers(watcher_object_list_t *from, watcher_object_list_t *to, int clone)\n{\n    watcher_object_t* wo=from->head;\n    while(wo){\n        watcher_object_t *next = wo->next;\n        add_to_list(&to, wo, clone);\n        wo=next;\n    }\n}\n\nstatic void copy_table(zk_hashtable *from, watcher_object_list_t *to) {\n    struct hashtable_itr *it;\n    int hasMore;\n    if(hashtable_count(from->ht)==0)\n        return;\n    it=hashtable_iterator(from->ht);\n    do {\n        watcher_object_list_t *w = hashtable_iterator_value(it);\n        copy_watchers(w, to, 1);\n        hasMore=hashtable_iterator_advance(it);\n    } while(hasMore);\n    free(it);\n}\n\nstatic void collect_session_watchers(zhandle_t *zh,\n                                     watcher_object_list_t **list)\n{\n    copy_table(zh->active_node_watchers, *list);\n    copy_table(zh->active_exist_watchers, *list);\n    copy_table(zh->active_child_watchers, *list);\n}\n\nstatic void add_for_event(zk_hashtable *ht, char *path, watcher_object_list_t **list)\n{\n    watcher_object_list_t* wl;\n    wl = (watcher_object_list_t*)hashtable_remove(ht->ht, path);\n    if (wl) {\n        copy_watchers(wl, *list, 0);\n        // Since we move, not clone the watch_objects, we just need to free the\n        // head pointer\n        free(wl);\n    }\n}\n\nstatic void do_foreach_watcher(watcher_object_t* wo,zhandle_t* zh,\n        const char* path,int type,int state)\n{\n    // session event's don't have paths\n    const char *client_path =\n        (type != ZOO_SESSION_EVENT ? sub_string(zh, path) : path);\n    while(wo!=0){\n        wo->watcher(zh,type,state,client_path,wo->context);\n        wo=wo->next;\n    }    \n    free_duplicate_path(client_path, path);\n}\n\nwatcher_object_list_t *collectWatchers(zhandle_t *zh,int type, char *path)\n{\n    struct watcher_object_list *list = create_watcher_object_list(0); \n\n    if(type==ZOO_SESSION_EVENT){\n        watcher_object_t defWatcher;\n        defWatcher.watcher=zh->watcher;\n        defWatcher.context=zh->context;\n        add_to_list(&list, &defWatcher, 1);\n        collect_session_watchers(zh, &list);\n        return list;\n    }\n    switch(type){\n    case CREATED_EVENT_DEF:\n    case CHANGED_EVENT_DEF:\n        // look up the watchers for the path and move them to a delivery list\n        add_for_event(zh->active_node_watchers,path,&list);\n        add_for_event(zh->active_exist_watchers,path,&list);\n        break;\n    case CHILD_EVENT_DEF:\n        // look up the watchers for the path and move them to a delivery list\n        add_for_event(zh->active_child_watchers,path,&list);\n        break;\n    case DELETED_EVENT_DEF:\n        // look up the watchers for the path and move them to a delivery list\n        add_for_event(zh->active_node_watchers,path,&list);\n        add_for_event(zh->active_exist_watchers,path,&list);\n        add_for_event(zh->active_child_watchers,path,&list);\n        break;\n    }\n    return list;\n}\n\nvoid deliverWatchers(zhandle_t *zh, int type,int state, char *path, watcher_object_list_t **list)\n{\n    if (!list || !(*list)) return;\n    do_foreach_watcher((*list)->head, zh, path, type, state);\n    destroy_watcher_object_list(*list);\n    *list = 0;\n}\n\nvoid activateWatcher(zhandle_t *zh, watcher_registration_t* reg, int rc)\n{\n    if(reg){\n        /* in multithreaded lib, this code is executed \n         * by the IO thread */\n        zk_hashtable *ht = reg->checker(zh, rc);\n        if(ht){\n            insert_watcher_object(ht,reg->path,\n                    create_watcher_object(reg->watcher, reg->context));\n        }\n    }    \n}\n"
  },
  {
    "path": "src/c/src/zk_hashtable.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZK_HASHTABLE_H_\n#define ZK_HASHTABLE_H_\n\n#include <zookeeper.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n    typedef struct watcher_object_list watcher_object_list_t;\ntypedef struct _zk_hashtable zk_hashtable;\n\n/**\n * The function must return a non-zero value if the watcher object can be activated\n * as a result of the server response. Normally, a watch can only be activated\n * if the server returns a success code (ZOK). However in the case when zoo_exists() \n * returns a ZNONODE code the watcher should be activated nevertheless.\n */\ntypedef zk_hashtable *(*result_checker_fn)(zhandle_t *, int rc);\n\n/**\n * A watcher object gets temporarily stored with the completion entry until \n * the server response comes back at which moment the watcher object is moved\n * to the active watchers map.\n */\ntypedef struct _watcher_registration {\n    watcher_fn watcher;\n    void* context;\n    result_checker_fn checker;\n    const char* path;\n} watcher_registration_t;\n\nzk_hashtable* create_zk_hashtable();\nvoid destroy_zk_hashtable(zk_hashtable* ht);\n\nchar **collect_keys(zk_hashtable *ht, int *count);\n\n/**\n * check if the completion has a watcher object associated\n * with it. If it does, move the watcher object to the map of\n * active watchers (only if the checker allows to do so)\n */\n    void activateWatcher(zhandle_t *zh, watcher_registration_t* reg, int rc);\n    watcher_object_list_t *collectWatchers(zhandle_t *zh,int type, char *path);\n    void deliverWatchers(zhandle_t *zh, int type, int state, char *path, struct watcher_object_list **list);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*ZK_HASHTABLE_H_*/\n"
  },
  {
    "path": "src/c/src/zk_log.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)\n#  define USE_STATIC_LIB\n#endif\n\n#include \"zookeeper_log.h\"\n#ifndef WIN32\n#include <unistd.h>\n#else\ntypedef DWORD pid_t;\n#include <process.h> /* for getpid */\n#endif\n\n#include <stdarg.h>\n#include <time.h>\n\n#define TIME_NOW_BUF_SIZE 1024\n#define FORMAT_LOG_BUF_SIZE 4096\n\n#ifdef THREADED\n#ifndef WIN32\n#include <pthread.h>\n#else \n#include \"winport.h\"\n#endif\n\nstatic pthread_key_t time_now_buffer;\nstatic pthread_key_t format_log_msg_buffer;\n\nvoid freeBuffer(void* p){\n    if(p) free(p);\n}\n\n__attribute__((constructor)) void prepareTSDKeys() {\n    pthread_key_create (&time_now_buffer, freeBuffer);\n    pthread_key_create (&format_log_msg_buffer, freeBuffer);\n}\n\nchar* getTSData(pthread_key_t key,int size){\n    char* p=pthread_getspecific(key);\n    if(p==0){\n        int res;\n        p=calloc(1,size);\n        res=pthread_setspecific(key,p);\n        if(res!=0){\n            fprintf(stderr,\"Failed to set TSD key: %d\",res);\n        }\n    }\n    return p;\n}\n\nchar* get_time_buffer(){\n    return getTSData(time_now_buffer,TIME_NOW_BUF_SIZE);\n}\n\nchar* get_format_log_buffer(){  \n    return getTSData(format_log_msg_buffer,FORMAT_LOG_BUF_SIZE);\n}\n#else\nchar* get_time_buffer(){\n    static char buf[TIME_NOW_BUF_SIZE];\n    return buf;    \n}\n\nchar* get_format_log_buffer(){\n    static char buf[FORMAT_LOG_BUF_SIZE];\n    return buf;\n}\n\n#endif\n\nZooLogLevel logLevel=ZOO_LOG_LEVEL_INFO;\n\nstatic FILE* logStream=0;\nFILE* getLogStream(){\n    if(logStream==0)\n        logStream=stderr;\n    return logStream;\n}\n\nvoid zoo_set_log_stream(FILE* stream){\n    logStream=stream;\n}\n\nstatic const char* time_now(char* now_str){\n    struct timeval tv;\n    struct tm lt;\n    time_t now = 0;\n    size_t len = 0;\n    \n    gettimeofday(&tv,0);\n\n    now = tv.tv_sec;\n    localtime_r(&now, &lt);\n\n    // clone the format used by log4j ISO8601DateFormat\n    // specifically: \"yyyy-MM-dd HH:mm:ss,SSS\"\n\n    len = strftime(now_str, TIME_NOW_BUF_SIZE,\n                          \"%Y-%m-%d %H:%M:%S\",\n                          &lt);\n\n    len += snprintf(now_str + len,\n                    TIME_NOW_BUF_SIZE - len,\n                    \",%03d\",\n                    (int)(tv.tv_usec/1000));\n\n    return now_str;\n}\n\nvoid log_message(ZooLogLevel curLevel,int line,const char* funcName,\n    const char* message)\n{\n    static const char* dbgLevelStr[]={\"ZOO_INVALID\",\"ZOO_ERROR\",\"ZOO_WARN\",\n            \"ZOO_INFO\",\"ZOO_DEBUG\"};\n    static pid_t pid=0;\n#ifdef WIN32\n    char timebuf [TIME_NOW_BUF_SIZE];\n#endif\n    if(pid==0)pid=getpid();\n#ifndef THREADED\n    // pid_t is long on Solaris\n    fprintf(LOGSTREAM, \"%s:%ld:%s@%s@%d: %s\\n\", time_now(get_time_buffer()),(long)pid,\n            dbgLevelStr[curLevel],funcName,line,message);\n#else\n#ifdef WIN32\n    fprintf(LOGSTREAM, \"%s:%d(0x%lx):%s@%s@%d: %s\\n\", time_now(timebuf),pid,\n            (unsigned long int)(pthread_self().thread_id),\n            dbgLevelStr[curLevel],funcName,line,message);      \n#else\n    fprintf(LOGSTREAM, \"%s:%ld(0x%lx):%s@%s@%d: %s\\n\", time_now(get_time_buffer()),(long)pid,\n            (unsigned long int)pthread_self(),\n            dbgLevelStr[curLevel],funcName,line,message);      \n#endif\n#endif\n    fflush(LOGSTREAM);\n}\n\nconst char* format_log_message(const char* format,...)\n{\n    va_list va;\n    char* buf=get_format_log_buffer();\n    if(!buf)\n        return \"format_log_message: Unable to allocate memory buffer\";\n    \n    va_start(va,format);\n    vsnprintf(buf, FORMAT_LOG_BUF_SIZE-1,format,va);\n    va_end(va); \n    return buf;\n}\n\nvoid zoo_set_debug_level(ZooLogLevel level)\n{\n    if(level==0){\n        // disable logging (unit tests do this)\n        logLevel=(ZooLogLevel)0;\n        return;\n    }\n    if(level<ZOO_LOG_LEVEL_ERROR)level=ZOO_LOG_LEVEL_ERROR;\n    if(level>ZOO_LOG_LEVEL_DEBUG)level=ZOO_LOG_LEVEL_DEBUG;\n    logLevel=level;\n}\n\n"
  },
  {
    "path": "src/c/src/zookeeper.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)\n#  define USE_STATIC_LIB\n#endif\n\n#if defined(__CYGWIN__)\n#define USE_IPV6\n#endif\n\n#include \"config.h\"\n#include <zookeeper.h>\n#include <zookeeper.jute.h>\n#include <proto.h>\n#include \"zk_adaptor.h\"\n#include \"zookeeper_log.h\"\n#include \"zk_hashtable.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <time.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <assert.h>\n#include <stdarg.h>\n#include <limits.h>\n\n#ifdef HAVE_SYS_TIME_H\n#include <sys/time.h>\n#endif\n\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n\n#ifdef HAVE_POLL\n#include <poll.h>\n#endif\n\n#ifdef HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#endif\n\n#ifdef HAVE_ARPA_INET_H\n#include <arpa/inet.h>\n#endif\n\n#ifdef HAVE_NETDB_H\n#include <netdb.h>\n#endif\n\n#ifdef HAVE_UNISTD_H\n#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK\n#endif\n\n#ifdef HAVE_SYS_UTSNAME_H\n#include <sys/utsname.h>\n#endif\n\n#ifdef HAVE_GETPWUID_R\n#include <pwd.h>\n#endif\n\n#ifdef WIN32\n#define random rand /* replace POSIX random with Windows rand */\n#include <process.h> /* for getpid */\n#include <direct.h> /* for getcwd */\n#define EAI_ADDRFAMILY WSAEINVAL /* is this still needed? */\n#define EHOSTDOWN EPIPE\n#define ESTALE ENODEV\n#endif\n\n#define IF_DEBUG(x) if(logLevel==ZOO_LOG_LEVEL_DEBUG) {x;}\n\nconst int ZOOKEEPER_WRITE = 1 << 0;\nconst int ZOOKEEPER_READ = 1 << 1;\n\nconst int ZOO_EPHEMERAL = 1 << 0;\nconst int ZOO_SEQUENCE = 1 << 1;\n\nconst int ZOO_EXPIRED_SESSION_STATE = EXPIRED_SESSION_STATE_DEF;\nconst int ZOO_AUTH_FAILED_STATE = AUTH_FAILED_STATE_DEF;\nconst int ZOO_CONNECTING_STATE = CONNECTING_STATE_DEF;\nconst int ZOO_ASSOCIATING_STATE = ASSOCIATING_STATE_DEF;\nconst int ZOO_CONNECTED_STATE = CONNECTED_STATE_DEF;\nstatic __attribute__ ((unused)) const char* state2String(int state){\n    switch(state){\n    case 0:\n        return \"ZOO_CLOSED_STATE\";\n    case CONNECTING_STATE_DEF:\n        return \"ZOO_CONNECTING_STATE\";\n    case ASSOCIATING_STATE_DEF:\n        return \"ZOO_ASSOCIATING_STATE\";\n    case CONNECTED_STATE_DEF:\n        return \"ZOO_CONNECTED_STATE\";\n    case EXPIRED_SESSION_STATE_DEF:\n        return \"ZOO_EXPIRED_SESSION_STATE\";\n    case AUTH_FAILED_STATE_DEF:\n        return \"ZOO_AUTH_FAILED_STATE\";\n    }\n    return \"INVALID_STATE\";\n}\n\nconst int ZOO_CREATED_EVENT = CREATED_EVENT_DEF;\nconst int ZOO_DELETED_EVENT = DELETED_EVENT_DEF;\nconst int ZOO_CHANGED_EVENT = CHANGED_EVENT_DEF;\nconst int ZOO_CHILD_EVENT = CHILD_EVENT_DEF;\nconst int ZOO_SESSION_EVENT = SESSION_EVENT_DEF;\nconst int ZOO_NOTWATCHING_EVENT = NOTWATCHING_EVENT_DEF;\nstatic __attribute__ ((unused)) const char* watcherEvent2String(int ev){\n    switch(ev){\n    case 0:\n        return \"ZOO_ERROR_EVENT\";\n    case CREATED_EVENT_DEF:\n        return \"ZOO_CREATED_EVENT\";\n    case DELETED_EVENT_DEF:\n        return \"ZOO_DELETED_EVENT\";\n    case CHANGED_EVENT_DEF:\n        return \"ZOO_CHANGED_EVENT\";\n    case CHILD_EVENT_DEF:\n        return \"ZOO_CHILD_EVENT\";\n    case SESSION_EVENT_DEF:\n        return \"ZOO_SESSION_EVENT\";\n    case NOTWATCHING_EVENT_DEF:\n        return \"ZOO_NOTWATCHING_EVENT\";\n    }\n    return \"INVALID_EVENT\";\n}\n\nconst int ZOO_PERM_READ = 1 << 0;\nconst int ZOO_PERM_WRITE = 1 << 1;\nconst int ZOO_PERM_CREATE = 1 << 2;\nconst int ZOO_PERM_DELETE = 1 << 3;\nconst int ZOO_PERM_ADMIN = 1 << 4;\nconst int ZOO_PERM_ALL = 0x1f;\nstruct Id ZOO_ANYONE_ID_UNSAFE = {\"world\", \"anyone\"};\nstruct Id ZOO_AUTH_IDS = {\"auth\", \"\"};\nstatic struct ACL _OPEN_ACL_UNSAFE_ACL[] = {{0x1f, {\"world\", \"anyone\"}}};\nstatic struct ACL _READ_ACL_UNSAFE_ACL[] = {{0x01, {\"world\", \"anyone\"}}};\nstatic struct ACL _CREATOR_ALL_ACL_ACL[] = {{0x1f, {\"auth\", \"\"}}};\nstruct ACL_vector ZOO_OPEN_ACL_UNSAFE = { 1, _OPEN_ACL_UNSAFE_ACL};\nstruct ACL_vector ZOO_READ_ACL_UNSAFE = { 1, _READ_ACL_UNSAFE_ACL};\nstruct ACL_vector ZOO_CREATOR_ALL_ACL = { 1, _CREATOR_ALL_ACL_ACL};\n\n#define COMPLETION_WATCH -1\n#define COMPLETION_VOID 0\n#define COMPLETION_STAT 1\n#define COMPLETION_DATA 2\n#define COMPLETION_STRINGLIST 3\n#define COMPLETION_STRINGLIST_STAT 4\n#define COMPLETION_ACLLIST 5\n#define COMPLETION_STRING 6\n#define COMPLETION_MULTI 7\n\ntypedef struct _auth_completion_list {\n    void_completion_t completion;\n    const char *auth_data;\n    struct _auth_completion_list *next;\n} auth_completion_list_t;\n\ntypedef struct completion {\n    int type; /* one of COMPLETION_* values above */\n    union {\n        void_completion_t void_result;\n        stat_completion_t stat_result;\n        data_completion_t data_result;\n        strings_completion_t strings_result;\n        strings_stat_completion_t strings_stat_result;\n        acl_completion_t acl_result;\n        string_completion_t string_result;\n        struct watcher_object_list *watcher_result;\n    };\n    completion_head_t clist; /* For multi-op */\n} completion_t;\n\ntypedef struct _completion_list {\n    int xid;\n    completion_t c;\n    const void *data;\n    buffer_list_t *buffer;\n    struct _completion_list *next;\n    watcher_registration_t* watcher;\n} completion_list_t;\n\nconst char*err2string(int err);\nstatic int queue_session_event(zhandle_t *zh, int state);\nstatic const char* format_endpoint_info(const struct sockaddr_storage* ep);\nstatic const char* format_current_endpoint_info(zhandle_t* zh);\n\n/* deserialize forward declarations */\nstatic void deserialize_response(int type, int xid, int failed, int rc, completion_list_t *cptr, struct iarchive *ia);\nstatic int deserialize_multi(int xid, completion_list_t *cptr, struct iarchive *ia);\n\n/* completion routine forward declarations */\nstatic int add_completion(zhandle_t *zh, int xid, int completion_type,\n        const void *dc, const void *data, int add_to_front, \n        watcher_registration_t* wo, completion_head_t *clist);\nstatic completion_list_t* create_completion_entry(int xid, int completion_type,\n        const void *dc, const void *data, watcher_registration_t* wo, \n        completion_head_t *clist);\nstatic void destroy_completion_entry(completion_list_t* c);\nstatic void queue_completion_nolock(completion_head_t *list, completion_list_t *c,\n        int add_to_front);\nstatic void queue_completion(completion_head_t *list, completion_list_t *c,\n        int add_to_front);\nstatic int handle_socket_error_msg(zhandle_t *zh, int line, int rc,\n    const char* format,...);\nstatic void cleanup_bufs(zhandle_t *zh,int callCompletion,int rc);\n\nstatic int disable_conn_permute=0; // permute enabled by default\n\nstatic __attribute__((unused)) void print_completion_queue(zhandle_t *zh);\n\nstatic void *SYNCHRONOUS_MARKER = (void*)&SYNCHRONOUS_MARKER;\nstatic int isValidPath(const char* path, const int flags);\n\n#ifdef _WINDOWS\nstatic int zookeeper_send(SOCKET s, const char* buf, int len)\n#else\nstatic ssize_t zookeeper_send(int s, const void* buf, size_t len)\n#endif\n{\n#ifdef __linux__\n  return send(s, buf, len, MSG_NOSIGNAL);\n#else\n  return send(s, buf, len, 0);\n#endif\n}\n\nconst void *zoo_get_context(zhandle_t *zh)\n{\n    return zh->context;\n}\n\nvoid zoo_set_context(zhandle_t *zh, void *context)\n{\n    if (zh != NULL) {\n        zh->context = context;\n    }\n}\n\nint zoo_recv_timeout(zhandle_t *zh)\n{\n    return zh->recv_timeout;\n}\n\n/** these functions are thread unsafe, so make sure that\n    zoo_lock_auth is called before you access them **/\nstatic auth_info* get_last_auth(auth_list_head_t *auth_list) {\n    auth_info *element;\n    element = auth_list->auth;\n    if (element == NULL) {\n        return NULL;\n    }\n    while (element->next != NULL) {\n        element = element->next;\n    }\n    return element;\n}\n\nstatic void free_auth_completion(auth_completion_list_t *a_list) {\n    auth_completion_list_t *tmp, *ftmp;\n    if (a_list == NULL) {\n        return;\n    }\n    tmp = a_list->next;\n    while (tmp != NULL) {\n        ftmp = tmp;\n        tmp = tmp->next;\n        ftmp->completion = NULL;\n        ftmp->auth_data = NULL;\n        free(ftmp);\n    }\n    a_list->completion = NULL;\n    a_list->auth_data = NULL;\n    a_list->next = NULL;\n    return;\n}\n\nstatic void add_auth_completion(auth_completion_list_t* a_list, void_completion_t* completion,\n                                const char *data) {\n    auth_completion_list_t *element;\n    auth_completion_list_t *n_element;\n    element = a_list;\n    if (a_list->completion == NULL) {\n        //this is the first element\n        a_list->completion = *completion;\n        a_list->next = NULL;\n        a_list->auth_data = data;\n        return;\n    }\n    while (element->next != NULL) {\n        element = element->next;\n    }\n    n_element = (auth_completion_list_t*) malloc(sizeof(auth_completion_list_t));\n    n_element->next = NULL;\n    n_element->completion = *completion;\n    n_element->auth_data = data;\n    element->next = n_element;\n    return;\n}\n\nstatic void get_auth_completions(auth_list_head_t *auth_list, auth_completion_list_t *a_list) {\n    auth_info *element;\n    element = auth_list->auth;\n    if (element == NULL) {\n        return;\n    }\n    while (element) {\n        if (element->completion) {\n            add_auth_completion(a_list, &element->completion, element->data);\n        }\n        element->completion = NULL;\n        element = element->next;\n    }\n    return;\n}\n\nstatic void add_last_auth(auth_list_head_t *auth_list, auth_info *add_el) {\n    auth_info  *element;\n    element = auth_list->auth;\n    if (element == NULL) {\n        //first element in the list\n        auth_list->auth = add_el;\n        return;\n    }\n    while (element->next != NULL) {\n        element = element->next;\n    }\n    element->next = add_el;\n    return;\n}\n\nstatic void init_auth_info(auth_list_head_t *auth_list)\n{\n    auth_list->auth = NULL;\n}\n\nstatic void mark_active_auth(zhandle_t *zh) {\n    auth_list_head_t auth_h = zh->auth_h;\n    auth_info *element;\n    if (auth_h.auth == NULL) {\n        return;\n    }\n    element = auth_h.auth;\n    while (element != NULL) {\n        element->state = 1;\n        element = element->next;\n    }\n}\n\nstatic void free_auth_info(auth_list_head_t *auth_list)\n{\n    auth_info *auth = auth_list->auth;\n    while (auth != NULL) {\n        auth_info* old_auth = NULL;\n        if(auth->scheme!=NULL)\n            free(auth->scheme);\n        deallocate_Buffer(&auth->auth);\n        old_auth = auth;\n        auth = auth->next;\n        free(old_auth);\n    }\n    init_auth_info(auth_list);\n}\n\nint is_unrecoverable(zhandle_t *zh)\n{\n    return (zh->state<0)? ZINVALIDSTATE: ZOK;\n}\n\nzk_hashtable *exists_result_checker(zhandle_t *zh, int rc)\n{\n    if (rc == ZOK) {\n        return zh->active_node_watchers;\n    } else if (rc == ZNONODE) {\n        return zh->active_exist_watchers;\n    }\n    return 0;\n}\n\nzk_hashtable *data_result_checker(zhandle_t *zh, int rc)\n{\n    return rc==ZOK ? zh->active_node_watchers : 0;\n}\n\nzk_hashtable *child_result_checker(zhandle_t *zh, int rc)\n{\n    return rc==ZOK ? zh->active_child_watchers : 0;\n}\n\n/**\n * Frees and closes everything associated with a handle,\n * including the handle itself.\n */\nstatic void destroy(zhandle_t *zh)\n{\n    if (zh == NULL) {\n        return;\n    }\n    /* call any outstanding completions with a special error code */\n    cleanup_bufs(zh,1,ZCLOSING);\n    if (zh->hostname != 0) {\n        free(zh->hostname);\n        zh->hostname = NULL;\n    }\n    if (zh->fd != -1) {\n        close(zh->fd);\n        zh->fd = -1;\n        zh->state = 0;\n    }\n    if (zh->addrs != 0) {\n        free(zh->addrs);\n        zh->addrs = NULL;\n    }\n\n    if (zh->chroot != 0) {\n        free(zh->chroot);\n        zh->chroot = NULL;\n    }\n\n    free_auth_info(&zh->auth_h);\n    destroy_zk_hashtable(zh->active_node_watchers);\n    destroy_zk_hashtable(zh->active_exist_watchers);\n    destroy_zk_hashtable(zh->active_child_watchers);\n}\n\nstatic void setup_random()\n{\n#ifndef WIN32          // TODO: better seed\n    int seed;\n    int fd = open(\"/dev/urandom\", O_RDONLY);\n    if (fd == -1) {\n        seed = getpid();\n    } else {\n        int seed_len = 0;\n\n        /* Enter a loop to fill in seed with random data from /dev/urandom.\n         * This is done in a loop so that we can safely handle short reads\n         * which can happen due to signal interruptions.\n         */\n        while (seed_len < sizeof(seed)) {\n            /* Assert we either read something or we were interrupted due to a\n             * signal (errno == EINTR) in which case we need to retry.\n             */\n            int rc = read(fd, &seed + seed_len, sizeof(seed) - seed_len);\n            assert(rc > 0 || errno == EINTR);\n            if (rc > 0) {\n                seed_len += rc;\n            }\n        }\n        close(fd);\n    }\n    srandom(seed);\n#endif\n}\n\n#ifndef __CYGWIN__\n/**\n * get the errno from the return code \n * of get addrinfo. Errno is not set\n * with the call to getaddrinfo, so thats\n * why we have to do this.\n */\nstatic int getaddrinfo_errno(int rc) { \n    switch(rc) {\n    case EAI_NONAME:\n// ZOOKEEPER-1323 EAI_NODATA and EAI_ADDRFAMILY are deprecated in FreeBSD.\n#if defined EAI_NODATA && EAI_NODATA != EAI_NONAME\n    case EAI_NODATA:\n#endif\n        return ENOENT;\n    case EAI_MEMORY:\n        return ENOMEM;\n    default:\n        return EINVAL;\n    }\n}\n#endif\n\n/**\n * fill in the addrs array of the zookeeper servers in the zhandle. after filling\n * them in, we will permute them for load balancing.\n */\nint getaddrs(zhandle_t *zh)\n{\n    char *hosts = strdup(zh->hostname);\n    char *host;\n    char *strtok_last;\n    struct sockaddr_storage *addr;\n    int i;\n    int rc;\n    int alen = 0; /* the allocated length of the addrs array */\n\n    zh->addrs_count = 0;\n    if (zh->addrs) {\n        free(zh->addrs);\n        zh->addrs = 0;\n    }\n    if (!hosts) {\n         LOG_ERROR((\"out of memory\"));\n        errno=ENOMEM;\n        return ZSYSTEMERROR;\n    }\n    zh->addrs = 0;\n    host=strtok_r(hosts, \",\", &strtok_last);\n    while(host) {\n        char *port_spec = strrchr(host, ':');\n        char *end_port_spec;\n        int port;\n        if (!port_spec) {\n            LOG_ERROR((\"no port in %s\", host));\n            errno=EINVAL;\n            rc=ZBADARGUMENTS;\n            goto fail;\n        }\n        *port_spec = '\\0';\n        port_spec++;\n        port = strtol(port_spec, &end_port_spec, 0);\n        if (!*port_spec || *end_port_spec || port == 0) {\n            LOG_ERROR((\"invalid port in %s\", host));\n            errno=EINVAL;\n            rc=ZBADARGUMENTS;\n            goto fail;\n        }\n#if defined(__CYGWIN__)\n        // sadly CYGWIN doesn't have getaddrinfo\n        // but happily gethostbyname is threadsafe in windows\n        {\n        struct hostent *he;\n        char **ptr;\n        struct sockaddr_in *addr4;\n\n        he = gethostbyname(host);\n        if (!he) {\n            LOG_ERROR((\"could not resolve %s\", host));\n            errno=ENOENT;\n            rc=ZBADARGUMENTS;\n            goto fail;\n        }\n\n        /* Setup the address array */\n        for(ptr = he->h_addr_list;*ptr != 0; ptr++) {\n            if (zh->addrs_count == alen) {\n                alen += 16;\n                zh->addrs = realloc(zh->addrs, sizeof(*zh->addrs)*alen);\n                if (zh->addrs == 0) {\n                    LOG_ERROR((\"out of memory\"));\n                    errno=ENOMEM;\n                    rc=ZSYSTEMERROR;\n                    goto fail;\n                }\n            }\n            addr = &zh->addrs[zh->addrs_count];\n            addr4 = (struct sockaddr_in*)addr;\n            addr->ss_family = he->h_addrtype;\n            if (addr->ss_family == AF_INET) {\n                addr4->sin_port = htons(port);\n                memset(&addr4->sin_zero, 0, sizeof(addr4->sin_zero));\n                memcpy(&addr4->sin_addr, *ptr, he->h_length);\n                zh->addrs_count++;\n            }\n#if defined(AF_INET6)\n            else if (addr->ss_family == AF_INET6) {\n                struct sockaddr_in6 *addr6;\n\n                addr6 = (struct sockaddr_in6*)addr;\n                addr6->sin6_port = htons(port);\n                addr6->sin6_scope_id = 0;\n                addr6->sin6_flowinfo = 0;\n                memcpy(&addr6->sin6_addr, *ptr, he->h_length);\n                zh->addrs_count++;\n            }\n#endif\n            else {\n                LOG_WARN((\"skipping unknown address family %x for %s\",\n                         addr->ss_family, zh->hostname));\n            }\n        }\n        host = strtok_r(0, \",\", &strtok_last);\n        }\n#else\n        {\n        struct addrinfo hints, *res, *res0;\n\n        memset(&hints, 0, sizeof(hints));\n#ifdef AI_ADDRCONFIG\n        hints.ai_flags = AI_ADDRCONFIG;\n#else\n        hints.ai_flags = 0;\n#endif\n        hints.ai_family = AF_UNSPEC;\n        hints.ai_socktype = SOCK_STREAM;\n        hints.ai_protocol = IPPROTO_TCP;\n\n        while(isspace(*host) && host != strtok_last)\n            host++;\n\n        if ((rc = getaddrinfo(host, port_spec, &hints, &res0)) != 0) {\n            //bug in getaddrinfo implementation when it returns\n            //EAI_BADFLAGS or EAI_ADDRFAMILY with AF_UNSPEC and \n            // ai_flags as AI_ADDRCONFIG\n#ifdef AI_ADDRCONFIG\n            if ((hints.ai_flags == AI_ADDRCONFIG) && \n// ZOOKEEPER-1323 EAI_NODATA and EAI_ADDRFAMILY are deprecated in FreeBSD.\n#ifdef EAI_ADDRFAMILY\n                ((rc ==EAI_BADFLAGS) || (rc == EAI_ADDRFAMILY))) {\n#else\n                (rc == EAI_BADFLAGS)) {\n#endif\n                //reset ai_flags to null\n                hints.ai_flags = 0;\n                //retry getaddrinfo\n                rc = getaddrinfo(host, port_spec, &hints, &res0);\n            }\n#endif\n            if (rc != 0) {\n                errno = getaddrinfo_errno(rc);\n#ifdef WIN32\n                LOG_ERROR((\"Win32 message: %s\\n\", gai_strerror(rc)));\n#else\n                LOG_ERROR((\"getaddrinfo: %s\\n\", strerror(errno)));\n#endif\n                rc=ZSYSTEMERROR;\n                goto fail;\n            }\n        }\n\n        for (res = res0; res; res = res->ai_next) {\n            // Expand address list if needed\n            if (zh->addrs_count == alen) {\n                void *tmpaddr;\n                alen += 16;\n                tmpaddr = realloc(zh->addrs, sizeof(*zh->addrs)*alen);\n                if (tmpaddr == 0) {\n                    LOG_ERROR((\"out of memory\"));\n                    errno=ENOMEM;\n                    rc=ZSYSTEMERROR;\n                    goto fail;\n                }\n                zh->addrs=tmpaddr;\n            }\n\n            // Copy addrinfo into address list\n            addr = &zh->addrs[zh->addrs_count];\n            switch (res->ai_family) {\n            case AF_INET:\n#if defined(AF_INET6)\n            case AF_INET6:\n#endif\n                memcpy(addr, res->ai_addr, res->ai_addrlen);\n                ++zh->addrs_count;\n                break;\n            default:\n                LOG_WARN((\"skipping unknown address family %x for %s\",\n                res->ai_family, zh->hostname));\n                break;\n            }\n        }\n\n        freeaddrinfo(res0);\n\n        host = strtok_r(0, \",\", &strtok_last);\n        }\n#endif\n    }\n    free(hosts);\n\n    if(!disable_conn_permute){\n        setup_random();\n        /* Permute */\n        for (i = zh->addrs_count - 1; i > 0; --i) {\n            long int j = random()%(i+1);\n            if (i != j) {\n                struct sockaddr_storage t = zh->addrs[i];\n                zh->addrs[i] = zh->addrs[j];\n                zh->addrs[j] = t;\n            }\n        }\n    }\n    return ZOK;\nfail:\n    if (zh->addrs) {\n        free(zh->addrs);\n        zh->addrs=0;\n    }\n    if (hosts) {\n        free(hosts);\n    }\n    return rc;\n}\n\nconst clientid_t *zoo_client_id(zhandle_t *zh)\n{\n    return &zh->client_id;\n}\n\nstatic void null_watcher_fn(zhandle_t* p1, int p2, int p3,const char* p4,void*p5){}\n\nwatcher_fn zoo_set_watcher(zhandle_t *zh,watcher_fn newFn)\n{\n    watcher_fn oldWatcher=zh->watcher;\n    if (newFn) {\n       zh->watcher = newFn;\n    } else {\n       zh->watcher = null_watcher_fn;\n    }\n    return oldWatcher;\n}\n\nstruct sockaddr* zookeeper_get_connected_host(zhandle_t *zh,\n                 struct sockaddr *addr, socklen_t *addr_len)\n{\n    if (zh->state!=ZOO_CONNECTED_STATE) {\n        return NULL;\n    }\n    if (getpeername(zh->fd, addr, addr_len)==-1) {\n        return NULL;\n    }\n    return addr;\n}\n\nstatic void log_env() {\n  char buf[2048];\n#ifdef HAVE_SYS_UTSNAME_H\n  struct utsname utsname;\n#endif\n\n#if defined(HAVE_GETUID) && defined(HAVE_GETPWUID_R)\n  struct passwd pw;\n  struct passwd *pwp = NULL;\n  uid_t uid = 0;\n#endif\n\n  LOG_INFO((\"Client environment:zookeeper.version=%s\", PACKAGE_STRING));\n\n#ifdef HAVE_GETHOSTNAME\n  gethostname(buf, sizeof(buf));\n  LOG_INFO((\"Client environment:host.name=%s\", buf));\n#else\n  LOG_INFO((\"Client environment:host.name=<not implemented>\"));\n#endif\n\n#ifdef HAVE_SYS_UTSNAME_H\n  uname(&utsname);\n  LOG_INFO((\"Client environment:os.name=%s\", utsname.sysname));\n  LOG_INFO((\"Client environment:os.arch=%s\", utsname.release));\n  LOG_INFO((\"Client environment:os.version=%s\", utsname.version));\n#else\n  LOG_INFO((\"Client environment:os.name=<not implemented>\"));\n  LOG_INFO((\"Client environment:os.arch=<not implemented>\"));\n  LOG_INFO((\"Client environment:os.version=<not implemented>\"));\n#endif\n\n#ifdef HAVE_GETLOGIN\n  LOG_INFO((\"Client environment:user.name=%s\", getlogin()));\n#else\n  LOG_INFO((\"Client environment:user.name=<not implemented>\"));\n#endif\n\n#if defined(HAVE_GETUID) && defined(HAVE_GETPWUID_R)\n  uid = getuid();\n  if (!getpwuid_r(uid, &pw, buf, sizeof(buf), &pwp)) {\n    LOG_INFO((\"Client environment:user.home=%s\", pw.pw_dir));\n  } else {\n    LOG_INFO((\"Client environment:user.home=<NA>\"));\n  }\n#else\n  LOG_INFO((\"Client environment:user.home=<not implemented>\"));\n#endif\n\n#ifdef HAVE_GETCWD\n  if (!getcwd(buf, sizeof(buf))) {\n    LOG_INFO((\"Client environment:user.dir=<toolong>\"));\n  } else {\n    LOG_INFO((\"Client environment:user.dir=%s\", buf));\n  }\n#else\n  LOG_INFO((\"Client environment:user.dir=<not implemented>\"));\n#endif\n}\n\n/**\n * Create a zookeeper handle associated with the given host and port.\n */\nzhandle_t *zookeeper_init(const char *host, watcher_fn watcher,\n  int recv_timeout, const clientid_t *clientid, void *context, int flags)\n{\n    int errnosave = 0;\n    zhandle_t *zh = NULL;\n    char *index_chroot = NULL;\n\n    log_env();\n#ifdef WIN32\n       if (Win32WSAStartup()){\n               LOG_ERROR((\"Error initializing ws2_32.dll\"));\n               return 0;\n       }\n#endif\n    LOG_INFO((\"Initiating client connection, host=%s sessionTimeout=%d watcher=%p\"\n          \" sessionId=%#llx sessionPasswd=%s context=%p flags=%d\",\n              host,\n              recv_timeout,\n              watcher,\n              (clientid == 0 ? 0 : clientid->client_id),\n              ((clientid == 0) || (clientid->passwd[0] == 0) ?\n               \"<null>\" : \"<hidden>\"),\n              context,\n              flags));\n\n    zh = calloc(1, sizeof(*zh));\n    if (!zh) {\n        return 0;\n    }\n    zh->fd = -1;\n    zh->state = NOTCONNECTED_STATE_DEF;\n    zh->context = context;\n    zh->recv_timeout = recv_timeout;\n    init_auth_info(&zh->auth_h);\n    if (watcher) {\n       zh->watcher = watcher;\n    } else {\n       zh->watcher = null_watcher_fn;\n    }\n    if (host == 0 || *host == 0) { // what we shouldn't dup\n        errno=EINVAL;\n        goto abort;\n    }\n    //parse the host to get the chroot if\n    //available\n    index_chroot = strchr(host, '/');\n    if (index_chroot) {\n        zh->chroot = strdup(index_chroot);\n        if (zh->chroot == NULL) {\n            goto abort;\n        }\n        // if chroot is just / set it to null\n        if (strlen(zh->chroot) == 1) {\n            free(zh->chroot);\n            zh->chroot = NULL;\n        }\n        // cannot use strndup so allocate and strcpy\n        zh->hostname = (char *) malloc(index_chroot - host + 1);\n        zh->hostname = strncpy(zh->hostname, host, (index_chroot - host));\n        //strncpy does not null terminate\n        *(zh->hostname + (index_chroot - host)) = '\\0';\n\n    } else {\n        zh->chroot = NULL;\n        zh->hostname = strdup(host);\n    }\n    if (zh->chroot && !isValidPath(zh->chroot, 0)) {\n        errno = EINVAL;\n        goto abort;\n    }\n    if (zh->hostname == 0) {\n        goto abort;\n    }\n    if(getaddrs(zh)!=0) {\n        goto abort;\n    }\n    zh->connect_index = 0;\n    if (clientid) {\n        memcpy(&zh->client_id, clientid, sizeof(zh->client_id));\n    } else {\n        memset(&zh->client_id, 0, sizeof(zh->client_id));\n    }\n    zh->primer_buffer.buffer = zh->primer_storage_buffer;\n    zh->primer_buffer.curr_offset = 0;\n    zh->primer_buffer.len = sizeof(zh->primer_storage_buffer);\n    zh->primer_buffer.next = 0;\n    zh->last_zxid = 0;\n    zh->next_deadline.tv_sec=zh->next_deadline.tv_usec=0;\n    zh->socket_readable.tv_sec=zh->socket_readable.tv_usec=0;\n    zh->active_node_watchers=create_zk_hashtable();\n    zh->active_exist_watchers=create_zk_hashtable();\n    zh->active_child_watchers=create_zk_hashtable();\n\n    if (adaptor_init(zh) == -1) {\n        goto abort;\n    }\n\n    return zh;\nabort:\n    errnosave=errno;\n    destroy(zh);\n    free(zh);\n    errno=errnosave;\n    return 0;\n}\n\n/**\n * deallocated the free_path only its beeen allocated\n * and not equal to path\n */\nvoid free_duplicate_path(const char *free_path, const char* path) {\n    if (free_path != path) {\n        free((void*)free_path);\n    }\n}\n\n/**\n  prepend the chroot path if available else return the path\n*/\nstatic char* prepend_string(zhandle_t *zh, const char* client_path) {\n    char *ret_str;\n    if (zh == NULL || zh->chroot == NULL)\n        return (char *) client_path;\n    // handle the chroot itself, client_path = \"/\"\n    if (strlen(client_path) == 1) {\n        return strdup(zh->chroot);\n    }\n    ret_str = (char *) malloc(strlen(zh->chroot) + strlen(client_path) + 1);\n    strcpy(ret_str, zh->chroot);\n    return strcat(ret_str, client_path);\n}\n\n/**\n   strip off the chroot string from the server path\n   if there is one else return the exact path\n */\nchar* sub_string(zhandle_t *zh, const char* server_path) {\n    char *ret_str;\n    if (zh->chroot == NULL)\n        return (char *) server_path;\n    //ZOOKEEPER-1027\n    if (strncmp(server_path, zh->chroot, strlen(zh->chroot)) != 0) {\n        LOG_ERROR((\"server path %s does not include chroot path %s\",\n                   server_path, zh->chroot));\n        return (char *) server_path;\n    }\n    if (strlen(server_path) == strlen(zh->chroot)) {\n        //return \"/\"\n        ret_str = strdup(\"/\");\n        return ret_str;\n    }\n    ret_str = strdup(server_path + strlen(zh->chroot));\n    return ret_str;\n}\n\nstatic buffer_list_t *allocate_buffer(char *buff, int len)\n{\n    buffer_list_t *buffer = calloc(1, sizeof(*buffer));\n    if (buffer == 0)\n        return 0;\n\n    buffer->len = len==0?sizeof(*buffer):len;\n    buffer->curr_offset = 0;\n    buffer->buffer = buff;\n    buffer->next = 0;\n    return buffer;\n}\n\nstatic void free_buffer(buffer_list_t *b)\n{\n    if (!b) {\n        return;\n    }\n    if (b->buffer) {\n        free(b->buffer);\n    }\n    free(b);\n}\n\nstatic buffer_list_t *dequeue_buffer(buffer_head_t *list)\n{\n    buffer_list_t *b;\n    lock_buffer_list(list);\n    b = list->head;\n    if (b) {\n        list->head = b->next;\n        if (!list->head) {\n            assert(b == list->last);\n            list->last = 0;\n        }\n    }\n    unlock_buffer_list(list);\n    return b;\n}\n\nstatic int remove_buffer(buffer_head_t *list)\n{\n    buffer_list_t *b = dequeue_buffer(list);\n    if (!b) {\n        return 0;\n    }\n    free_buffer(b);\n    return 1;\n}\n\nstatic void queue_buffer(buffer_head_t *list, buffer_list_t *b, int add_to_front)\n{\n    b->next = 0;\n    lock_buffer_list(list);\n    if (list->head) {\n        assert(list->last);\n        // The list is not empty\n        if (add_to_front) {\n            b->next = list->head;\n            list->head = b;\n        } else {\n            list->last->next = b;\n            list->last = b;\n        }\n    }else{\n        // The list is empty\n        assert(!list->head);\n        list->head = b;\n        list->last = b;\n    }\n    unlock_buffer_list(list);\n}\n\nstatic int queue_buffer_bytes(buffer_head_t *list, char *buff, int len)\n{\n    buffer_list_t *b  = allocate_buffer(buff,len);\n    if (!b)\n        return ZSYSTEMERROR;\n    queue_buffer(list, b, 0);\n    return ZOK;\n}\n\nstatic int queue_front_buffer_bytes(buffer_head_t *list, char *buff, int len)\n{\n    buffer_list_t *b  = allocate_buffer(buff,len);\n    if (!b)\n        return ZSYSTEMERROR;\n    queue_buffer(list, b, 1);\n    return ZOK;\n}\n\nstatic __attribute__ ((unused)) int get_queue_len(buffer_head_t *list)\n{\n    int i;\n    buffer_list_t *ptr;\n    lock_buffer_list(list);\n    ptr = list->head;\n    for (i=0; ptr!=0; ptr=ptr->next, i++)\n        ;\n    unlock_buffer_list(list);\n    return i;\n}\n/* returns:\n * -1 if send failed,\n * 0 if send would block while sending the buffer (or a send was incomplete),\n * 1 if success\n */\n#ifdef WIN32\nstatic int send_buffer(SOCKET fd, buffer_list_t *buff)\n#else\nstatic int send_buffer(int fd, buffer_list_t *buff)\n#endif\n{\n    int len = buff->len;\n    int off = buff->curr_offset;\n    int rc = -1;\n\n    if (off < 4) {\n        /* we need to send the length at the beginning */\n        int nlen = htonl(len);\n        char *b = (char*)&nlen;\n        rc = zookeeper_send(fd, b + off, sizeof(nlen) - off);\n        if (rc == -1) {\n#ifndef _WINDOWS\n            if (errno != EAGAIN) {\n#else            \n            if (WSAGetLastError() != WSAEWOULDBLOCK) {\n#endif            \n                return -1;\n            } else {\n                return 0;\n            }\n        } else {\n            buff->curr_offset  += rc;\n        }\n        off = buff->curr_offset;\n    }\n    if (off >= 4) {\n        /* want off to now represent the offset into the buffer */\n        off -= sizeof(buff->len);\n        rc = zookeeper_send(fd, buff->buffer + off, len - off);\n        if (rc == -1) {\n#ifndef _WINDOWS\n            if (errno != EAGAIN) {\n#else            \n            if (WSAGetLastError() != WSAEWOULDBLOCK) {\n#endif            \n                return -1;\n            }\n        } else {\n            buff->curr_offset += rc;\n        }\n    }\n    return buff->curr_offset == len + sizeof(buff->len);\n}\n\n/* returns:\n * -1 if recv call failed,\n * 0 if recv would block,\n * 1 if success\n */\n#ifdef WIN32\nstatic int recv_buffer(SOCKET fd, buffer_list_t *buff)\n#else\nstatic int recv_buffer(int fd, buffer_list_t *buff)\n#endif\n{\n    int off = buff->curr_offset;\n    int rc = 0;\n    //fprintf(LOGSTREAM, \"rc = %d, off = %d, line %d\\n\", rc, off, __LINE__);\n\n    /* if buffer is less than 4, we are reading in the length */\n    if (off < 4) {\n        char *buffer = (char*)&(buff->len);\n        rc = recv(fd, buffer+off, sizeof(int)-off, 0);\n        //fprintf(LOGSTREAM, \"rc = %d, off = %d, line %d\\n\", rc, off, __LINE__);\n        switch(rc) {\n        case 0:\n            errno = EHOSTDOWN;\n        case -1:\n#ifndef _WINDOWS\n            if (errno == EAGAIN) {\n#else\n            if (WSAGetLastError() == WSAEWOULDBLOCK) {\n#endif\n                return 0;\n            }\n            return -1;\n        default:\n            buff->curr_offset += rc;\n        }\n        off = buff->curr_offset;\n        if (buff->curr_offset == sizeof(buff->len)) {\n            buff->len = ntohl(buff->len);\n            buff->buffer = calloc(1, buff->len);\n        }\n    }\n    if (buff->buffer) {\n        /* want off to now represent the offset into the buffer */\n        off -= sizeof(buff->len);\n\n        rc = recv(fd, buff->buffer+off, buff->len-off, 0);\n        switch(rc) {\n        case 0:\n            errno = EHOSTDOWN;\n        case -1:\n#ifndef _WINDOWS\n            if (errno == EAGAIN) {\n#else\n            if (WSAGetLastError() == WSAEWOULDBLOCK) {\n#endif\n                break;\n            }\n            return -1;\n        default:\n            buff->curr_offset += rc;\n        }\n    }\n    return buff->curr_offset == buff->len + sizeof(buff->len);\n}\n\nvoid free_buffers(buffer_head_t *list)\n{\n    while (remove_buffer(list))\n        ;\n}\n\nvoid free_completions(zhandle_t *zh,int callCompletion,int reason)\n{\n    completion_head_t tmp_list;\n    struct oarchive *oa;\n    struct ReplyHeader h;\n    void_completion_t auth_completion = NULL;\n    auth_completion_list_t a_list, *a_tmp;\n\n    if (lock_completion_list(&zh->sent_requests) == 0) {\n        tmp_list = zh->sent_requests;\n        zh->sent_requests.head = 0;\n        zh->sent_requests.last = 0;\n        unlock_completion_list(&zh->sent_requests);\n    \n        while (tmp_list.head) {\n            completion_list_t *cptr = tmp_list.head;\n\n            tmp_list.head = cptr->next;\n            if (cptr->c.data_result == SYNCHRONOUS_MARKER) {\n                struct sync_completion\n                            *sc = (struct sync_completion*)cptr->data;\n                sc->rc = reason;\n                notify_sync_completion(sc);\n                zh->outstanding_sync--;\n                destroy_completion_entry(cptr);\n            } else if (callCompletion) {\n                // Fake the response\n                buffer_list_t *bptr;\n                h.xid = cptr->xid;\n                h.zxid = -1;\n                h.err = reason;\n                oa = create_buffer_oarchive();\n                serialize_ReplyHeader(oa, \"header\", &h);\n                bptr = calloc(sizeof(*bptr), 1);\n                assert(bptr);\n                bptr->len = get_buffer_len(oa);\n                bptr->buffer = get_buffer(oa);\n                close_buffer_oarchive(&oa, 0);\n                cptr->buffer = bptr;\n                queue_completion(&zh->completions_to_process, cptr, 0);\n            }\n        }\n    }\n    if (zoo_lock_auth(zh) == 0) {\n        a_list.completion = NULL;\n        a_list.next = NULL;\n    \n        get_auth_completions(&zh->auth_h, &a_list);\n        zoo_unlock_auth(zh);\n    \n        a_tmp = &a_list;\n        // chain call user's completion function\n        while (a_tmp->completion != NULL) {\n            auth_completion = a_tmp->completion;\n            auth_completion(reason, a_tmp->auth_data);\n            a_tmp = a_tmp->next;\n            if (a_tmp == NULL)\n                break;\n        }\n    }\n    free_auth_completion(&a_list);\n}\n\nstatic void cleanup_bufs(zhandle_t *zh,int callCompletion,int rc)\n{\n    enter_critical(zh);\n    free_buffers(&zh->to_send);\n    free_buffers(&zh->to_process);\n    free_completions(zh,callCompletion,rc);\n    leave_critical(zh);\n    if (zh->input_buffer && zh->input_buffer != &zh->primer_buffer) {\n        free_buffer(zh->input_buffer);\n        zh->input_buffer = 0;\n    }\n}\n\nstatic void handle_error(zhandle_t *zh,int rc)\n{\n    close(zh->fd);\n    if (is_unrecoverable(zh)) {\n        LOG_DEBUG((\"Calling a watcher for a ZOO_SESSION_EVENT and the state=%s\",\n                state2String(zh->state)));\n        PROCESS_SESSION_EVENT(zh, zh->state);\n    } else if (zh->state == ZOO_CONNECTED_STATE) {\n        LOG_DEBUG((\"Calling a watcher for a ZOO_SESSION_EVENT and the state=CONNECTING_STATE\"));\n        PROCESS_SESSION_EVENT(zh, ZOO_CONNECTING_STATE);\n    }\n    cleanup_bufs(zh,1,rc);\n    zh->fd = -1;\n    zh->connect_index++;\n    if (!is_unrecoverable(zh)) {\n        zh->state = 0;\n    }\n    if (process_async(zh->outstanding_sync)) {\n        process_completions(zh);\n    }\n}\n\nstatic int handle_socket_error_msg(zhandle_t *zh, int line, int rc,\n        const char* format, ...)\n{\n    if(logLevel>=ZOO_LOG_LEVEL_ERROR){\n        va_list va;\n        char buf[1024];\n        va_start(va,format);\n        vsnprintf(buf, sizeof(buf)-1,format,va);\n        log_message(ZOO_LOG_LEVEL_ERROR,line,__func__,\n            format_log_message(\"Socket [%s] zk retcode=%d, errno=%d(%s): %s\",\n            format_current_endpoint_info(zh),rc,errno,strerror(errno),buf));\n        va_end(va);\n    }\n    handle_error(zh,rc);\n    return rc;\n}\n\nstatic void auth_completion_func(int rc, zhandle_t* zh)\n{\n    void_completion_t auth_completion = NULL;\n    auth_completion_list_t a_list;\n    auth_completion_list_t *a_tmp;\n\n    if(zh==NULL)\n        return;\n\n    zoo_lock_auth(zh);\n\n    if(rc!=0){\n        zh->state=ZOO_AUTH_FAILED_STATE;\n    }else{\n        //change state for all auths\n        mark_active_auth(zh);\n    }\n    a_list.completion = NULL;\n    a_list.next = NULL;\n    get_auth_completions(&zh->auth_h, &a_list);\n    zoo_unlock_auth(zh);\n    if (rc) {\n        LOG_ERROR((\"Authentication scheme %s failed. Connection closed.\",\n                   zh->auth_h.auth->scheme));\n    }\n    else {\n        LOG_INFO((\"Authentication scheme %s succeeded\", zh->auth_h.auth->scheme));\n    }\n    a_tmp = &a_list;\n    // chain call user's completion function\n    while (a_tmp->completion != NULL) {\n        auth_completion = a_tmp->completion;\n        auth_completion(rc, a_tmp->auth_data);\n        a_tmp = a_tmp->next;\n        if (a_tmp == NULL)\n            break;\n    }\n    free_auth_completion(&a_list);\n}\n\nstatic int send_info_packet(zhandle_t *zh, auth_info* auth) {\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid , AUTH_XID), STRUCT_INITIALIZER(type , ZOO_SETAUTH_OP)};\n    struct AuthPacket req;\n    int rc;\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    req.type=0;   // ignored by the server\n    req.scheme = auth->scheme;\n    req.auth = auth->auth;\n    rc = rc < 0 ? rc : serialize_AuthPacket(oa, \"req\", &req);\n    /* add this buffer to the head of the send queue */\n    rc = rc < 0 ? rc : queue_front_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    return rc;\n}\n\n/** send all auths, not just the last one **/\nstatic int send_auth_info(zhandle_t *zh) {\n    int rc = 0;\n    auth_info *auth = NULL;\n\n    zoo_lock_auth(zh);\n    auth = zh->auth_h.auth;\n    if (auth == NULL) {\n        zoo_unlock_auth(zh);\n        return ZOK;\n    }\n    while (auth != NULL) {\n        rc = send_info_packet(zh, auth);\n        auth = auth->next;\n    }\n    zoo_unlock_auth(zh);\n    LOG_DEBUG((\"Sending all auth info request to %s\", format_current_endpoint_info(zh)));\n    return (rc <0) ? ZMARSHALLINGERROR:ZOK;\n}\n\nstatic int send_last_auth_info(zhandle_t *zh)\n{    \n    int rc = 0;\n    auth_info *auth = NULL;\n\n    zoo_lock_auth(zh);\n    auth = get_last_auth(&zh->auth_h);\n    if(auth==NULL) {\n      zoo_unlock_auth(zh);\n      return ZOK; // there is nothing to send\n    }\n    rc = send_info_packet(zh, auth);\n    zoo_unlock_auth(zh);\n    LOG_DEBUG((\"Sending auth info request to %s\",format_current_endpoint_info(zh)));\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nstatic void free_key_list(char **list, int count)\n{\n    int i;\n\n    for(i = 0; i < count; i++) {\n        free(list[i]);\n    }\n    free(list);\n}\n\nstatic int send_set_watches(zhandle_t *zh)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid , SET_WATCHES_XID), STRUCT_INITIALIZER(type , ZOO_SETWATCHES_OP)};\n    struct SetWatches req;\n    int rc;\n\n    req.relativeZxid = zh->last_zxid;\n    req.dataWatches.data = collect_keys(zh->active_node_watchers, (int*)&req.dataWatches.count);\n    req.existWatches.data = collect_keys(zh->active_exist_watchers, (int*)&req.existWatches.count);\n    req.childWatches.data = collect_keys(zh->active_child_watchers, (int*)&req.childWatches.count);\n\n    // return if there are no pending watches\n    if (!req.dataWatches.count && !req.existWatches.count &&\n        !req.childWatches.count) {\n        free_key_list(req.dataWatches.data, req.dataWatches.count);\n        free_key_list(req.existWatches.data, req.existWatches.count);\n        free_key_list(req.childWatches.data, req.childWatches.count);\n        return ZOK;\n    }\n\n\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_SetWatches(oa, \"req\", &req);\n    /* add this buffer to the head of the send queue */\n    rc = rc < 0 ? rc : queue_front_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    /* We queued the buffer, so don't free it */   \n    close_buffer_oarchive(&oa, 0);\n    free_key_list(req.dataWatches.data, req.dataWatches.count);\n    free_key_list(req.existWatches.data, req.existWatches.count);\n    free_key_list(req.childWatches.data, req.childWatches.count);\n    LOG_DEBUG((\"Sending set watches request to %s\",format_current_endpoint_info(zh)));\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nstatic int serialize_prime_connect(struct connect_req *req, char* buffer){\n    //this should be the order of serialization\n    int offset = 0;\n    req->protocolVersion = htonl(req->protocolVersion);\n    memcpy(buffer + offset, &req->protocolVersion, sizeof(req->protocolVersion));\n    offset = offset +  sizeof(req->protocolVersion);\n\n    req->lastZxidSeen = zoo_htonll(req->lastZxidSeen);\n    memcpy(buffer + offset, &req->lastZxidSeen, sizeof(req->lastZxidSeen));\n    offset = offset +  sizeof(req->lastZxidSeen);\n\n    req->timeOut = htonl(req->timeOut);\n    memcpy(buffer + offset, &req->timeOut, sizeof(req->timeOut));\n    offset = offset +  sizeof(req->timeOut);\n\n    req->sessionId = zoo_htonll(req->sessionId);\n    memcpy(buffer + offset, &req->sessionId, sizeof(req->sessionId));\n    offset = offset +  sizeof(req->sessionId);\n\n    req->passwd_len = htonl(req->passwd_len);\n    memcpy(buffer + offset, &req->passwd_len, sizeof(req->passwd_len));\n    offset = offset +  sizeof(req->passwd_len);\n\n    memcpy(buffer + offset, req->passwd, sizeof(req->passwd));\n\n    return 0;\n}\n\n static int deserialize_prime_response(struct prime_struct *req, char* buffer){\n     //this should be the order of deserialization\n     int offset = 0;\n     memcpy(&req->len, buffer + offset, sizeof(req->len));\n     offset = offset +  sizeof(req->len);\n\n     req->len = ntohl(req->len);\n     memcpy(&req->protocolVersion, buffer + offset, sizeof(req->protocolVersion));\n     offset = offset +  sizeof(req->protocolVersion);\n\n     req->protocolVersion = ntohl(req->protocolVersion);\n     memcpy(&req->timeOut, buffer + offset, sizeof(req->timeOut));\n     offset = offset +  sizeof(req->timeOut);\n\n     req->timeOut = ntohl(req->timeOut);\n     memcpy(&req->sessionId, buffer + offset, sizeof(req->sessionId));\n     offset = offset +  sizeof(req->sessionId);\n\n     req->sessionId = zoo_htonll(req->sessionId);\n     memcpy(&req->passwd_len, buffer + offset, sizeof(req->passwd_len));\n     offset = offset +  sizeof(req->passwd_len);\n\n     req->passwd_len = ntohl(req->passwd_len);\n     memcpy(req->passwd, buffer + offset, sizeof(req->passwd));\n     return 0;\n }\n\nstatic int prime_connection(zhandle_t *zh)\n{\n    int rc;\n    /*this is the size of buffer to serialize req into*/\n    char buffer_req[HANDSHAKE_REQ_SIZE];\n    int len = sizeof(buffer_req);\n    int hlen = 0;\n    struct connect_req req;\n    req.protocolVersion = 0;\n    req.sessionId = zh->client_id.client_id;\n    req.passwd_len = sizeof(req.passwd);\n    memcpy(req.passwd, zh->client_id.passwd, sizeof(zh->client_id.passwd));\n    req.timeOut = zh->recv_timeout;\n    req.lastZxidSeen = zh->last_zxid;\n    hlen = htonl(len);\n    /* We are running fast and loose here, but this string should fit in the initial buffer! */\n    rc=zookeeper_send(zh->fd, &hlen, sizeof(len));\n    serialize_prime_connect(&req, buffer_req);\n    rc=rc<0 ? rc : zookeeper_send(zh->fd, buffer_req, len);\n    if (rc<0) {\n        return handle_socket_error_msg(zh, __LINE__, ZCONNECTIONLOSS,\n                \"failed to send a handshake packet: %s\", strerror(errno));\n    }\n    zh->state = ZOO_ASSOCIATING_STATE;\n\n    zh->input_buffer = &zh->primer_buffer;\n    /* This seems a bit weird to to set the offset to 4, but we already have a\n     * length, so we skip reading the length (and allocating the buffer) by\n     * saying that we are already at offset 4 */\n    zh->input_buffer->curr_offset = 4;\n\n    return ZOK;\n}\n\nstatic inline int calculate_interval(const struct timeval *start,\n        const struct timeval *end)\n{\n    int interval;\n    struct timeval i = *end;\n    i.tv_sec -= start->tv_sec;\n    i.tv_usec -= start->tv_usec;\n    interval = i.tv_sec * 1000 + (i.tv_usec/1000);\n    return interval;\n}\n\nstatic struct timeval get_timeval(int interval)\n{\n    struct timeval tv;\n    if (interval < 0) {\n        interval = 0;\n    }\n    tv.tv_sec = interval/1000;\n    tv.tv_usec = (interval%1000)*1000;\n    return tv;\n}\n\n static int add_void_completion(zhandle_t *zh, int xid, void_completion_t dc,\n     const void *data);\n static int add_string_completion(zhandle_t *zh, int xid,\n     string_completion_t dc, const void *data);\n\n int send_ping(zhandle_t* zh)\n {\n    int rc;\n    struct oarchive *oa = create_buffer_oarchive();\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid ,PING_XID), STRUCT_INITIALIZER (type , ZOO_PING_OP) };\n\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    enter_critical(zh);\n    gettimeofday(&zh->last_ping, 0);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    close_buffer_oarchive(&oa, 0);\n    return rc<0 ? rc : adaptor_send_queue(zh, 0);\n}\n\n#ifdef WIN32\nint zookeeper_interest(zhandle_t *zh, SOCKET *fd, int *interest,\n     struct timeval *tv)\n{\n\n    ULONG nonblocking_flag = 1;\n#else\nint zookeeper_interest(zhandle_t *zh, int *fd, int *interest,\n     struct timeval *tv)\n{\n#endif\n    struct timeval now;\n    if(zh==0 || fd==0 ||interest==0 || tv==0)\n        return ZBADARGUMENTS;\n    if (is_unrecoverable(zh))\n        return ZINVALIDSTATE;\n    gettimeofday(&now, 0);\n    if(zh->next_deadline.tv_sec!=0 || zh->next_deadline.tv_usec!=0){\n        int time_left = calculate_interval(&zh->next_deadline, &now);\n        if (time_left > 10)\n            LOG_WARN((\"Exceeded deadline by %dms\", time_left));\n    }\n    api_prolog(zh);\n    *fd = zh->fd;\n    *interest = 0;\n    tv->tv_sec = 0;\n    tv->tv_usec = 0;\n    if (*fd == -1) {\n        if (zh->connect_index == zh->addrs_count) {\n            /* Wait a bit before trying again so that we don't spin */\n            zh->connect_index = 0;\n        }else {\n            int rc;\n#ifdef WIN32\n            char enable_tcp_nodelay = 1;\n#else\n            int enable_tcp_nodelay = 1;\n#endif\n            int ssoresult;\n\n            zh->fd = socket(zh->addrs[zh->connect_index].ss_family, SOCK_STREAM, 0);\n            if (zh->fd < 0) {\n                return api_epilog(zh,handle_socket_error_msg(zh,__LINE__,\n                                                             ZSYSTEMERROR, \"socket() call failed\"));\n            }\n            ssoresult = setsockopt(zh->fd, IPPROTO_TCP, TCP_NODELAY, &enable_tcp_nodelay, sizeof(enable_tcp_nodelay));\n            if (ssoresult != 0) {\n                LOG_WARN((\"Unable to set TCP_NODELAY, operation latency may be effected\"));\n            }\n#ifdef WIN32\n            ioctlsocket(zh->fd, FIONBIO, &nonblocking_flag);                    \n#else\n            fcntl(zh->fd, F_SETFL, O_NONBLOCK|fcntl(zh->fd, F_GETFL, 0));\n#endif\n#if defined(AF_INET6)\n            if (zh->addrs[zh->connect_index].ss_family == AF_INET6) {\n                rc = connect(zh->fd, (struct sockaddr*) &zh->addrs[zh->connect_index], sizeof(struct sockaddr_in6));\n            } else {\n#else\n               LOG_DEBUG((\"[zk] connect()\\n\"));\n            {\n#endif\n                rc = connect(zh->fd, (struct sockaddr*) &zh->addrs[zh->connect_index], sizeof(struct sockaddr_in));\n#ifdef WIN32\n                errno = GetLastError();\n\n#ifndef EWOULDBLOCK\n#define EWOULDBLOCK WSAEWOULDBLOCK\n#endif\n\n#ifndef EINPROGRESS\n#define EINPROGRESS WSAEINPROGRESS\n#endif\n\n#if _MSC_VER >= 1600\n                switch (errno) {\n                case WSAEWOULDBLOCK:\n                    errno = EWOULDBLOCK;\n                    break;\n                case WSAEINPROGRESS:\n                    errno = EINPROGRESS;\n                    break;\n                }\n#endif\n#endif\n            }\n            if (rc == -1) {\n                /* we are handling the non-blocking connect according to\n                 * the description in section 16.3 \"Non-blocking connect\"\n                 * in UNIX Network Programming vol 1, 3rd edition */\n                if (errno == EWOULDBLOCK || errno == EINPROGRESS)\n                    zh->state = ZOO_CONNECTING_STATE;\n                else\n                    return api_epilog(zh,handle_socket_error_msg(zh,__LINE__,\n                            ZCONNECTIONLOSS,\"connect() call failed\"));\n            } else {\n                if((rc=prime_connection(zh))!=0)\n                    return api_epilog(zh,rc);\n\n                LOG_INFO((\"Initiated connection to server [%s]\",\n                        format_endpoint_info(&zh->addrs[zh->connect_index])));\n            }\n        }\n        *fd = zh->fd;\n        *tv = get_timeval(zh->recv_timeout/3);\n        zh->last_recv = now;\n        zh->last_send = now;\n        zh->last_ping = now;\n    }\n    if (zh->fd != -1) {\n        int idle_recv = calculate_interval(&zh->last_recv, &now);\n        int idle_send = calculate_interval(&zh->last_send, &now);\n        int recv_to = zh->recv_timeout*2/3 - idle_recv;\n        int send_to = zh->recv_timeout/3;\n        // have we exceeded the receive timeout threshold?\n        if (recv_to <= 0) {\n            // We gotta cut our losses and connect to someone else\n#ifdef WIN32\n            errno = WSAETIMEDOUT;\n#else\n            errno = ETIMEDOUT;\n#endif\n            *interest=0;\n            *tv = get_timeval(0);\n            return api_epilog(zh,handle_socket_error_msg(zh,\n                    __LINE__,ZOPERATIONTIMEOUT,\n                    \"connection to %s timed out (exceeded timeout by %dms)\",\n                    format_endpoint_info(&zh->addrs[zh->connect_index]),\n                    -recv_to));\n\n        }\n        // We only allow 1/3 of our timeout time to expire before sending\n        // a PING\n        if (zh->state==ZOO_CONNECTED_STATE) {\n            send_to = zh->recv_timeout/3 - idle_send;\n            if (send_to <= 0) {\n                if (zh->sent_requests.head==0) {\n//                    LOG_DEBUG((\"Sending PING to %s (exceeded idle by %dms)\",\n//                                    format_current_endpoint_info(zh),-send_to));\n                    int rc=send_ping(zh);\n                    if (rc < 0){\n                        LOG_ERROR((\"failed to send PING request (zk retcode=%d)\",rc));\n                        return api_epilog(zh,rc);\n                    }\n                }\n                send_to = zh->recv_timeout/3;\n            }\n        }\n        // choose the lesser value as the timeout\n        *tv = get_timeval(recv_to < send_to? recv_to:send_to);\n        zh->next_deadline.tv_sec = now.tv_sec + tv->tv_sec;\n        zh->next_deadline.tv_usec = now.tv_usec + tv->tv_usec;\n        if (zh->next_deadline.tv_usec > 1000000) {\n            zh->next_deadline.tv_sec += zh->next_deadline.tv_usec / 1000000;\n            zh->next_deadline.tv_usec = zh->next_deadline.tv_usec % 1000000;\n        }\n        *interest = ZOOKEEPER_READ;\n        /* we are interested in a write if we are connected and have something\n         * to send, or we are waiting for a connect to finish. */\n        if ((zh->to_send.head && (zh->state == ZOO_CONNECTED_STATE))\n        || zh->state == ZOO_CONNECTING_STATE) {\n            *interest |= ZOOKEEPER_WRITE;\n        }\n    }\n    return api_epilog(zh,ZOK);\n}\n\nstatic int check_events(zhandle_t *zh, int events)\n{\n    if (zh->fd == -1)\n        return ZINVALIDSTATE;\n    if ((events&ZOOKEEPER_WRITE)&&(zh->state == ZOO_CONNECTING_STATE)) {\n        int rc, error;\n        socklen_t len = sizeof(error);\n        rc = getsockopt(zh->fd, SOL_SOCKET, SO_ERROR, &error, &len);\n        /* the description in section 16.4 \"Non-blocking connect\"\n         * in UNIX Network Programming vol 1, 3rd edition, points out\n         * that sometimes the error is in errno and sometimes in error */\n        if (rc < 0 || error) {\n            if (rc == 0)\n                errno = error;\n            return handle_socket_error_msg(zh, __LINE__,ZCONNECTIONLOSS,\n                \"server refused to accept the client\");\n        }\n        if((rc=prime_connection(zh))!=0)\n            return rc;\n        LOG_INFO((\"initiated connection to server [%s]\",\n                format_endpoint_info(&zh->addrs[zh->connect_index])));\n        return ZOK;\n    }\n    if (zh->to_send.head && (events&ZOOKEEPER_WRITE)) {\n        /* make the flush call non-blocking by specifying a 0 timeout */\n        int rc=flush_send_queue(zh,0);\n        if (rc < 0)\n            return handle_socket_error_msg(zh,__LINE__,ZCONNECTIONLOSS,\n                \"failed while flushing send queue\");\n    }\n    if (events&ZOOKEEPER_READ) {\n        int rc;\n        if (zh->input_buffer == 0) {\n            zh->input_buffer = allocate_buffer(0,0);\n        }\n\n        rc = recv_buffer(zh->fd, zh->input_buffer);\n        if (rc < 0) {\n            return handle_socket_error_msg(zh, __LINE__,ZCONNECTIONLOSS,\n                \"failed while receiving a server response\");\n        }\n        if (rc > 0) {\n            gettimeofday(&zh->last_recv, 0);\n            if (zh->input_buffer != &zh->primer_buffer) {\n                queue_buffer(&zh->to_process, zh->input_buffer, 0);\n            } else  {\n                int64_t oldid,newid;\n                //deserialize\n                deserialize_prime_response(&zh->primer_storage, zh->primer_buffer.buffer);\n                /* We are processing the primer_buffer, so we need to finish\n                 * the connection handshake */\n                oldid = zh->client_id.client_id;\n                newid = zh->primer_storage.sessionId;\n                if (oldid != 0 && oldid != newid) {\n                    zh->state = ZOO_EXPIRED_SESSION_STATE;\n                    errno = ESTALE;\n                    return handle_socket_error_msg(zh,__LINE__,ZSESSIONEXPIRED,\n                            \"sessionId=%#llx has expired.\",oldid);\n                } else {\n                    zh->recv_timeout = zh->primer_storage.timeOut;\n                    zh->client_id.client_id = newid;\n                 \n                    memcpy(zh->client_id.passwd, &zh->primer_storage.passwd,\n                           sizeof(zh->client_id.passwd));\n                    zh->state = ZOO_CONNECTED_STATE;\n                    LOG_INFO((\"session establishment complete on server [%s], sessionId=%#llx, negotiated timeout=%d\",\n                              format_endpoint_info(&zh->addrs[zh->connect_index]),\n                              newid, zh->recv_timeout));\n                    /* we want the auth to be sent for, but since both call push to front\n                       we need to call send_watch_set first */\n                    send_set_watches(zh);\n                    /* send the authentication packet now */\n                    send_auth_info(zh);\n                    LOG_DEBUG((\"Calling a watcher for a ZOO_SESSION_EVENT and the state=ZOO_CONNECTED_STATE\"));\n                    zh->input_buffer = 0; // just in case the watcher calls zookeeper_process() again\n                    PROCESS_SESSION_EVENT(zh, ZOO_CONNECTED_STATE);\n                }\n            }\n            zh->input_buffer = 0;\n        } else {\n            // zookeeper_process was called but there was nothing to read\n            // from the socket\n            return ZNOTHING;\n        }\n    }\n    return ZOK;\n}\n\nvoid api_prolog(zhandle_t* zh)\n{\n    inc_ref_counter(zh,1);\n}\n\nint api_epilog(zhandle_t *zh,int rc)\n{\n    if(inc_ref_counter(zh,-1)==0 && zh->close_requested!=0)\n        zookeeper_close(zh);\n    return rc;\n}\n\nstatic __attribute__((unused)) void print_completion_queue(zhandle_t *zh)\n{\n    completion_list_t* cptr;\n\n    if(logLevel<ZOO_LOG_LEVEL_DEBUG) return;\n\n    fprintf(LOGSTREAM,\"Completion queue: \");\n    if (zh->sent_requests.head==0) {\n        fprintf(LOGSTREAM,\"empty\\n\");\n        return;\n    }\n\n    cptr=zh->sent_requests.head;\n    while(cptr){\n        fprintf(LOGSTREAM,\"%d,\",cptr->xid);\n        cptr=cptr->next;\n    }\n    fprintf(LOGSTREAM,\"end\\n\");\n}\n\n//#ifdef THREADED\n// IO thread queues session events to be processed by the completion thread\nstatic int queue_session_event(zhandle_t *zh, int state)\n{\n    int rc;\n    struct WatcherEvent evt = { ZOO_SESSION_EVENT, state, \"\" };\n    struct ReplyHeader hdr = { WATCHER_EVENT_XID, 0, 0 };\n    struct oarchive *oa;\n    completion_list_t *cptr;\n\n    if ((oa=create_buffer_oarchive())==NULL) {\n        LOG_ERROR((\"out of memory\"));\n        goto error;\n    }\n    rc = serialize_ReplyHeader(oa, \"hdr\", &hdr);\n    rc = rc<0?rc: serialize_WatcherEvent(oa, \"event\", &evt);\n    if(rc<0){\n        close_buffer_oarchive(&oa, 1);\n        goto error;\n    }\n    cptr = create_completion_entry(WATCHER_EVENT_XID,-1,0,0,0,0);\n    cptr->buffer = allocate_buffer(get_buffer(oa), get_buffer_len(oa));\n    cptr->buffer->curr_offset = get_buffer_len(oa);\n    if (!cptr->buffer) {\n        free(cptr);\n        close_buffer_oarchive(&oa, 1);\n        goto error;\n    }\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n    cptr->c.watcher_result = collectWatchers(zh, ZOO_SESSION_EVENT, \"\");\n    queue_completion(&zh->completions_to_process, cptr, 0);\n    if (process_async(zh->outstanding_sync)) {\n        process_completions(zh);\n    }\n    return ZOK;\nerror:\n    errno=ENOMEM;\n    return ZSYSTEMERROR;\n}\n//#endif\n\ncompletion_list_t *dequeue_completion(completion_head_t *list)\n{\n    completion_list_t *cptr;\n    lock_completion_list(list);\n    cptr = list->head;\n    if (cptr) {\n        list->head = cptr->next;\n        if (!list->head) {\n            assert(list->last == cptr);\n            list->last = 0;\n        }\n    }\n    unlock_completion_list(list);\n    return cptr;\n}\n\nstatic void process_sync_completion(\n        completion_list_t *cptr,\n        struct sync_completion *sc,\n        struct iarchive *ia,\n\tzhandle_t *zh)\n{\n    LOG_DEBUG((\"Processing sync_completion with type=%d xid=%#x rc=%d\",\n            cptr->c.type, cptr->xid, sc->rc));\n\n    switch(cptr->c.type) {\n    case COMPLETION_DATA: \n        if (sc->rc==0) {\n            struct GetDataResponse res;\n            int len;\n            deserialize_GetDataResponse(ia, \"reply\", &res);\n            if (res.data.len <= sc->u.data.buff_len) {\n                len = res.data.len;\n            } else {\n                len = sc->u.data.buff_len;\n            }\n            sc->u.data.buff_len = len;\n            // check if len is negative\n            // just of NULL which is -1 int\n            if (len == -1) {\n                sc->u.data.buffer = NULL;\n            } else {\n                memcpy(sc->u.data.buffer, res.data.buff, len);\n            }\n            sc->u.data.stat = res.stat;\n            deallocate_GetDataResponse(&res);\n        }\n        break;\n    case COMPLETION_STAT:\n        if (sc->rc==0) {\n            struct SetDataResponse res;\n            deserialize_SetDataResponse(ia, \"reply\", &res);\n            sc->u.stat = res.stat;\n            deallocate_SetDataResponse(&res);\n        }\n        break;\n    case COMPLETION_STRINGLIST:\n        if (sc->rc==0) {\n            struct GetChildrenResponse res;\n            deserialize_GetChildrenResponse(ia, \"reply\", &res);\n            sc->u.strs2 = res.children;\n            /* We don't deallocate since we are passing it back */\n            // deallocate_GetChildrenResponse(&res);\n        }\n        break;\n    case COMPLETION_STRINGLIST_STAT:\n        if (sc->rc==0) {\n            struct GetChildren2Response res;\n            deserialize_GetChildren2Response(ia, \"reply\", &res);\n            sc->u.strs_stat.strs2 = res.children;\n            sc->u.strs_stat.stat2 = res.stat;\n            /* We don't deallocate since we are passing it back */\n            // deallocate_GetChildren2Response(&res);\n        }\n        break;\n    case COMPLETION_STRING:\n        if (sc->rc==0) {\n            struct CreateResponse res;\n            int len;\n            const char * client_path;\n            deserialize_CreateResponse(ia, \"reply\", &res);\n            //ZOOKEEPER-1027\n            client_path = sub_string(zh, res.path); \n            len = strlen(client_path) + 1;if (len > sc->u.str.str_len) {\n                len = sc->u.str.str_len;\n            }\n            if (len > 0) {\n                memcpy(sc->u.str.str, client_path, len - 1);\n                sc->u.str.str[len - 1] = '\\0';\n            }\n            free_duplicate_path(client_path, res.path);\n            deallocate_CreateResponse(&res);\n        }\n        break;\n    case COMPLETION_ACLLIST:\n        if (sc->rc==0) {\n            struct GetACLResponse res;\n            deserialize_GetACLResponse(ia, \"reply\", &res);\n            sc->u.acl.acl = res.acl;\n            sc->u.acl.stat = res.stat;\n            /* We don't deallocate since we are passing it back */\n            //deallocate_GetACLResponse(&res);\n        }\n        break;\n    case COMPLETION_VOID:\n        break;\n    case COMPLETION_MULTI:\n        sc->rc = deserialize_multi(cptr->xid, cptr, ia);\n        break;\n    default:\n        LOG_DEBUG((\"Unsupported completion type=%d\", cptr->c.type));\n        break;\n    }\n}\n\nstatic int deserialize_multi(int xid, completion_list_t *cptr, struct iarchive *ia)\n{\n    int rc = 0;\n    completion_head_t *clist = &cptr->c.clist;\n    struct MultiHeader mhdr = { STRUCT_INITIALIZER(type , 0), STRUCT_INITIALIZER(done , 0), STRUCT_INITIALIZER(err , 0) };\n    assert(clist);\n    deserialize_MultiHeader(ia, \"multiheader\", &mhdr);\n    while (!mhdr.done) {\n        completion_list_t *entry = dequeue_completion(clist);\n        assert(entry);\n\n        if (mhdr.type == -1) {\n            struct ErrorResponse er;\n            deserialize_ErrorResponse(ia, \"error\", &er);\n            mhdr.err = er.err ;\n            if (rc == 0 && er.err != 0 && er.err != ZRUNTIMEINCONSISTENCY) {\n                rc = er.err;\n            }\n        }\n\n        deserialize_response(entry->c.type, xid, mhdr.type == -1, mhdr.err, entry, ia);\n        deserialize_MultiHeader(ia, \"multiheader\", &mhdr);\n        //While deserializing the response we must destroy completion entry for each operation in \n        //the zoo_multi transaction. Otherwise this results in memory leak when client invokes zoo_multi\n        //operation.\n        destroy_completion_entry(entry);\n    }\n\n    return rc;\n}\n\nstatic void deserialize_response(int type, int xid, int failed, int rc, completion_list_t *cptr, struct iarchive *ia)\n{\n    switch (type) {\n    case COMPLETION_DATA:\n        LOG_DEBUG((\"Calling COMPLETION_DATA for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.data_result(rc, 0, 0, 0, cptr->data);\n        } else {\n            struct GetDataResponse res;\n            deserialize_GetDataResponse(ia, \"reply\", &res);\n            cptr->c.data_result(rc, res.data.buff, res.data.len,\n                    &res.stat, cptr->data);\n            deallocate_GetDataResponse(&res);\n        }\n        break;\n    case COMPLETION_STAT:\n        LOG_DEBUG((\"Calling COMPLETION_STAT for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.stat_result(rc, 0, cptr->data);\n        } else {\n            struct SetDataResponse res;\n            deserialize_SetDataResponse(ia, \"reply\", &res);\n            cptr->c.stat_result(rc, &res.stat, cptr->data);\n            deallocate_SetDataResponse(&res);\n        }\n        break;\n    case COMPLETION_STRINGLIST:\n        LOG_DEBUG((\"Calling COMPLETION_STRINGLIST for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.strings_result(rc, 0, cptr->data);\n        } else {\n            struct GetChildrenResponse res;\n            deserialize_GetChildrenResponse(ia, \"reply\", &res);\n            cptr->c.strings_result(rc, &res.children, cptr->data);\n            deallocate_GetChildrenResponse(&res);\n        }\n        break;\n    case COMPLETION_STRINGLIST_STAT:\n        LOG_DEBUG((\"Calling COMPLETION_STRINGLIST_STAT for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.strings_stat_result(rc, 0, 0, cptr->data);\n        } else {\n            struct GetChildren2Response res;\n            deserialize_GetChildren2Response(ia, \"reply\", &res);\n            cptr->c.strings_stat_result(rc, &res.children, &res.stat, cptr->data);\n            deallocate_GetChildren2Response(&res);\n        }\n        break;\n    case COMPLETION_STRING:\n        LOG_DEBUG((\"Calling COMPLETION_STRING for xid=%#x failed=%d, rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.string_result(rc, 0, cptr->data);\n        } else {\n            struct CreateResponse res;\n            memset(&res, 0, sizeof(res));\n            deserialize_CreateResponse(ia, \"reply\", &res);\n            cptr->c.string_result(rc, res.path, cptr->data);\n            deallocate_CreateResponse(&res);\n        }\n        break;\n    case COMPLETION_ACLLIST:\n        LOG_DEBUG((\"Calling COMPLETION_ACLLIST for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        if (failed) {\n            cptr->c.acl_result(rc, 0, 0, cptr->data);\n        } else {\n            struct GetACLResponse res;\n            deserialize_GetACLResponse(ia, \"reply\", &res);\n            cptr->c.acl_result(rc, &res.acl, &res.stat, cptr->data);\n            deallocate_GetACLResponse(&res);\n        }\n        break;\n    case COMPLETION_VOID:\n        LOG_DEBUG((\"Calling COMPLETION_VOID for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        assert(cptr->c.void_result);\n        cptr->c.void_result(rc, cptr->data);\n        break;\n    case COMPLETION_MULTI:\n        LOG_DEBUG((\"Calling COMPLETION_MULTI for xid=%#x failed=%d rc=%d\",\n                    cptr->xid, failed, rc));\n        rc = deserialize_multi(xid, cptr, ia);\n        assert(cptr->c.void_result);\n        cptr->c.void_result(rc, cptr->data);\n        break;\n    default:\n        LOG_DEBUG((\"Unsupported completion type=%d\", cptr->c.type));\n    }\n}\n\n\n/* handles async completion (both single- and multithreaded) */\nvoid process_completions(zhandle_t *zh)\n{\n    completion_list_t *cptr;\n    while ((cptr = dequeue_completion(&zh->completions_to_process)) != 0) {\n        struct ReplyHeader hdr;\n        buffer_list_t *bptr = cptr->buffer;\n        struct iarchive *ia = create_buffer_iarchive(bptr->buffer,\n                bptr->len);\n        deserialize_ReplyHeader(ia, \"hdr\", &hdr);\n\n        if (hdr.xid == WATCHER_EVENT_XID) {\n            int type, state;\n            struct WatcherEvent evt;\n            deserialize_WatcherEvent(ia, \"event\", &evt);\n            /* We are doing a notification, so there is no pending request */\n            type = evt.type;\n            state = evt.state;\n            /* This is a notification so there aren't any pending requests */\n            LOG_DEBUG((\"Calling a watcher for node [%s], type = %d event=%s\",\n                       (evt.path==NULL?\"NULL\":evt.path), cptr->c.type,\n                       watcherEvent2String(type)));\n            deliverWatchers(zh,type,state,evt.path, &cptr->c.watcher_result);\n            deallocate_WatcherEvent(&evt);\n        } else {\n            deserialize_response(cptr->c.type, hdr.xid, hdr.err != 0, hdr.err, cptr, ia);\n        }\n        destroy_completion_entry(cptr);\n        close_buffer_iarchive(&ia);\n    }\n}\n\nstatic void isSocketReadable(zhandle_t* zh)\n{\n#ifndef WIN32\n    struct pollfd fds;\n    fds.fd = zh->fd;\n    fds.events = POLLIN;\n    if (poll(&fds,1,0)<=0) {\n        // socket not readable -- no more responses to process\n        zh->socket_readable.tv_sec=zh->socket_readable.tv_usec=0;\n    }\n#else\n    fd_set rfds;\n    struct timeval waittime = {0, 0};\n    FD_ZERO(&rfds);\n    FD_SET( zh->fd , &rfds);\n    if (select(0, &rfds, NULL, NULL, &waittime) <= 0){\n        // socket not readable -- no more responses to process\n        zh->socket_readable.tv_sec=zh->socket_readable.tv_usec=0;\n    }\n#endif\n    else{\n        gettimeofday(&zh->socket_readable,0);\n    }\n}\n\nstatic void checkResponseLatency(zhandle_t* zh)\n{\n    int delay;\n    struct timeval now;\n\n    if(zh->socket_readable.tv_sec==0)\n        return;\n\n    gettimeofday(&now,0);\n    delay=calculate_interval(&zh->socket_readable, &now);\n    if(delay>20)\n        LOG_DEBUG((\"The following server response has spent at least %dms sitting in the client socket recv buffer\",delay));\n\n    zh->socket_readable.tv_sec=zh->socket_readable.tv_usec=0;\n}\n\nint zookeeper_process(zhandle_t *zh, int events)\n{\n    buffer_list_t *bptr;\n    int rc;\n\n    if (zh==NULL)\n        return ZBADARGUMENTS;\n    if (is_unrecoverable(zh))\n        return ZINVALIDSTATE;\n    api_prolog(zh);\n    IF_DEBUG(checkResponseLatency(zh));\n    rc = check_events(zh, events);\n    if (rc!=ZOK)\n        return api_epilog(zh, rc);\n\n    IF_DEBUG(isSocketReadable(zh));\n\n    while (rc >= 0 && (bptr=dequeue_buffer(&zh->to_process))) {\n        struct ReplyHeader hdr;\n        struct iarchive *ia = create_buffer_iarchive(\n                                    bptr->buffer, bptr->curr_offset);\n        deserialize_ReplyHeader(ia, \"hdr\", &hdr);\n        if (hdr.zxid > 0) {\n            zh->last_zxid = hdr.zxid;\n        } else {\n            // fprintf(stderr, \"Got %#x for %#x\\n\", hdr.zxid, hdr.xid);\n        }\n\n        if (hdr.xid == PING_XID) {\n            // Ping replies can arrive out-of-order\n            int elapsed = 0;\n            struct timeval now;\n            gettimeofday(&now, 0);\n            elapsed = calculate_interval(&zh->last_ping, &now);\n            LOG_DEBUG((\"Got ping response in %d ms\", elapsed));\n            free_buffer(bptr);\n        } else if (hdr.xid == WATCHER_EVENT_XID) {\n            struct WatcherEvent evt;\n            int type = 0;\n            char *path = NULL;\n            completion_list_t *c = NULL;\n\n            LOG_DEBUG((\"Processing WATCHER_EVENT\"));\n\n            deserialize_WatcherEvent(ia, \"event\", &evt);\n            type = evt.type;\n            path = evt.path;\n            /* We are doing a notification, so there is no pending request */\n            c = create_completion_entry(WATCHER_EVENT_XID,-1,0,0,0,0);\n            c->buffer = bptr;\n            c->c.watcher_result = collectWatchers(zh, type, path);\n\n            // We cannot free until now, otherwise path will become invalid\n            deallocate_WatcherEvent(&evt);\n            queue_completion(&zh->completions_to_process, c, 0);\n        } else if (hdr.xid == SET_WATCHES_XID) {\n            LOG_DEBUG((\"Processing SET_WATCHES\"));\n            free_buffer(bptr);\n        } else if (hdr.xid == AUTH_XID){\n            LOG_DEBUG((\"Processing AUTH_XID\"));\n\n            /* special handling for the AUTH response as it may come back\n             * out-of-band */\n            auth_completion_func(hdr.err,zh);\n            free_buffer(bptr);\n            /* authentication completion may change the connection state to\n             * unrecoverable */\n            if(is_unrecoverable(zh)){\n                handle_error(zh, ZAUTHFAILED);\n                close_buffer_iarchive(&ia);\n                return api_epilog(zh, ZAUTHFAILED);\n            }\n        } else {\n            int rc = hdr.err;\n            /* Find the request corresponding to the response */\n            completion_list_t *cptr = dequeue_completion(&zh->sent_requests);\n\n            /* [ZOOKEEPER-804] Don't assert if zookeeper_close has been called. */\n            if (zh->close_requested == 1 && cptr == NULL) {\n                LOG_DEBUG((\"Completion queue has been cleared by zookeeper_close()\"));\n                close_buffer_iarchive(&ia);\n                free_buffer(bptr);\n                return api_epilog(zh,ZINVALIDSTATE);\n            }\n            assert(cptr);\n            /* The requests are going to come back in order */\n            if (cptr->xid != hdr.xid) {\n                LOG_DEBUG((\"Processing unexpected or out-of-order response!\"));\n\n                // received unexpected (or out-of-order) response\n                close_buffer_iarchive(&ia);\n                free_buffer(bptr);\n                // put the completion back on the queue (so it gets properly\n                // signaled and deallocated) and disconnect from the server\n                queue_completion(&zh->sent_requests,cptr,1);\n                return api_epilog(zh,\n                                  handle_socket_error_msg(zh, __LINE__,ZRUNTIMEINCONSISTENCY,\n                                  \"unexpected server response: expected %#x, but received %#x\",\n                                  hdr.xid,cptr->xid));\n            }\n\n            activateWatcher(zh, cptr->watcher, rc);\n\n            if (cptr->c.void_result != SYNCHRONOUS_MARKER) {\n                LOG_DEBUG((\"Queueing asynchronous response\"));\n                cptr->buffer = bptr;\n                queue_completion(&zh->completions_to_process, cptr, 0);\n            } else {\n                struct sync_completion\n                        *sc = (struct sync_completion*)cptr->data;\n                sc->rc = rc;\n                \n                process_sync_completion(cptr, sc, ia, zh); \n                \n                notify_sync_completion(sc);\n                free_buffer(bptr);\n                zh->outstanding_sync--;\n                destroy_completion_entry(cptr);\n            }\n        }\n\n        close_buffer_iarchive(&ia);\n\n    }\n    if (process_async(zh->outstanding_sync)) {\n        process_completions(zh);\n    }\n    return api_epilog(zh,ZOK);}\n\nint zoo_state(zhandle_t *zh)\n{\n    if(zh!=0)\n        return zh->state;\n    return 0;\n}\n\nstatic watcher_registration_t* create_watcher_registration(const char* path,\n        result_checker_fn checker,watcher_fn watcher,void* ctx){\n    watcher_registration_t* wo;\n    if(watcher==0)\n        return 0;\n    wo=calloc(1,sizeof(watcher_registration_t));\n    wo->path=strdup(path);\n    wo->watcher=watcher;\n    wo->context=ctx;\n    wo->checker=checker;\n    return wo;\n}\n\nstatic void destroy_watcher_registration(watcher_registration_t* wo){\n    if(wo!=0){\n        free((void*)wo->path);\n        free(wo);\n    }\n}\n\nstatic completion_list_t* create_completion_entry(int xid, int completion_type,\n        const void *dc, const void *data,watcher_registration_t* wo, completion_head_t *clist)\n{\n    completion_list_t *c = calloc(1,sizeof(completion_list_t));\n    if (!c) {\n        LOG_ERROR((\"out of memory\"));\n        return 0;\n    }\n    c->c.type = completion_type;\n    c->data = data;\n    switch(c->c.type) {\n    case COMPLETION_VOID:\n        c->c.void_result = (void_completion_t)dc;\n        break;\n    case COMPLETION_STRING:\n        c->c.string_result = (string_completion_t)dc;\n        break;\n    case COMPLETION_DATA:\n        c->c.data_result = (data_completion_t)dc;\n        break;\n    case COMPLETION_STAT:\n        c->c.stat_result = (stat_completion_t)dc;\n        break;\n    case COMPLETION_STRINGLIST:\n        c->c.strings_result = (strings_completion_t)dc;\n        break;\n    case COMPLETION_STRINGLIST_STAT:\n        c->c.strings_stat_result = (strings_stat_completion_t)dc;\n        break;\n    case COMPLETION_ACLLIST:\n        c->c.acl_result = (acl_completion_t)dc;\n        break;\n    case COMPLETION_MULTI:\n        assert(clist);\n        c->c.void_result = (void_completion_t)dc;\n        c->c.clist = *clist;\n        break;\n    }\n    c->xid = xid;\n    c->watcher = wo;\n    \n    return c;\n}\n\nstatic void destroy_completion_entry(completion_list_t* c){\n    if(c!=0){\n        destroy_watcher_registration(c->watcher);\n        if(c->buffer!=0)\n            free_buffer(c->buffer);\n        free(c);\n    }\n}\n\nstatic void queue_completion_nolock(completion_head_t *list, \n                                    completion_list_t *c,\n                                    int add_to_front) \n{\n    c->next = 0;\n    /* appending a new entry to the back of the list */\n    if (list->last) {\n        assert(list->head);\n        // List is not empty\n        if (!add_to_front) {\n            list->last->next = c;\n            list->last = c;\n        } else {\n            c->next = list->head;\n            list->head = c;\n        }\n    } else {\n        // List is empty\n        assert(!list->head);\n        list->head = c;\n        list->last = c;\n    }\n}\n\nstatic void queue_completion(completion_head_t *list, completion_list_t *c,\n        int add_to_front)\n{\n\n    lock_completion_list(list);\n    queue_completion_nolock(list, c, add_to_front);\n    unlock_completion_list(list);\n}\n\nstatic int add_completion(zhandle_t *zh, int xid, int completion_type,\n        const void *dc, const void *data, int add_to_front,\n        watcher_registration_t* wo, completion_head_t *clist)\n{\n    completion_list_t *c =create_completion_entry(xid, completion_type, dc,\n            data, wo, clist);\n    int rc = 0;\n    if (!c)\n        return ZSYSTEMERROR;\n    lock_completion_list(&zh->sent_requests);\n    if (zh->close_requested != 1) {\n        queue_completion_nolock(&zh->sent_requests, c, add_to_front);\n        if (dc == SYNCHRONOUS_MARKER) {\n            zh->outstanding_sync++;\n        }\n        rc = ZOK;\n    } else {\n        free(c);\n        rc = ZINVALIDSTATE;\n    }\n    unlock_completion_list(&zh->sent_requests);\n    return rc;\n}\n\nstatic int add_data_completion(zhandle_t *zh, int xid, data_completion_t dc,\n        const void *data,watcher_registration_t* wo)\n{\n    return add_completion(zh, xid, COMPLETION_DATA, dc, data, 0, wo, 0);\n}\n\nstatic int add_stat_completion(zhandle_t *zh, int xid, stat_completion_t dc,\n        const void *data,watcher_registration_t* wo)\n{\n    return add_completion(zh, xid, COMPLETION_STAT, dc, data, 0, wo, 0);\n}\n\nstatic int add_strings_completion(zhandle_t *zh, int xid,\n        strings_completion_t dc, const void *data,watcher_registration_t* wo)\n{\n    return add_completion(zh, xid, COMPLETION_STRINGLIST, dc, data, 0, wo, 0);\n}\n\nstatic int add_strings_stat_completion(zhandle_t *zh, int xid,\n        strings_stat_completion_t dc, const void *data,watcher_registration_t* wo)\n{\n    return add_completion(zh, xid, COMPLETION_STRINGLIST_STAT, dc, data, 0, wo, 0);\n}\n\nstatic int add_acl_completion(zhandle_t *zh, int xid, acl_completion_t dc,\n        const void *data)\n{\n    return add_completion(zh, xid, COMPLETION_ACLLIST, dc, data, 0, 0, 0);\n}\n\nstatic int add_void_completion(zhandle_t *zh, int xid, void_completion_t dc,\n        const void *data)\n{\n    return add_completion(zh, xid, COMPLETION_VOID, dc, data, 0, 0, 0);\n}\n\nstatic int add_string_completion(zhandle_t *zh, int xid,\n        string_completion_t dc, const void *data)\n{\n    return add_completion(zh, xid, COMPLETION_STRING, dc, data, 0, 0, 0);\n}\n\nstatic int add_multi_completion(zhandle_t *zh, int xid, void_completion_t dc,\n        const void *data, completion_head_t *clist)\n{\n    return add_completion(zh, xid, COMPLETION_MULTI, dc, data, 0,0, clist);\n}\n\nint zookeeper_close(zhandle_t *zh)\n{\n    int rc=ZOK;\n    if (zh==0)\n        return ZBADARGUMENTS;\n\n    zh->close_requested=1;\n    if (inc_ref_counter(zh,1)>1) {\n        /* We have incremented the ref counter to prevent the\n         * completions from calling zookeeper_close before we have\n         * completed the adaptor_finish call below. */\n\n\t/* Signal any syncronous completions before joining the threads */\n        enter_critical(zh);\n        free_completions(zh,1,ZCLOSING);\n        leave_critical(zh);\n\n        adaptor_finish(zh);\n        /* Now we can allow the handle to be cleaned up, if the completion\n         * threads finished during the adaptor_finish call. */\n        api_epilog(zh, 0);\n        return ZOK;\n    }\n    /* No need to decrement the counter since we're just going to\n     * destroy the handle later. */\n    if(zh->state==ZOO_CONNECTED_STATE){\n        struct oarchive *oa;\n        struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type , ZOO_CLOSE_OP)};\n        LOG_INFO((\"Closing zookeeper sessionId=%#llx to [%s]\\n\",\n                zh->client_id.client_id,format_current_endpoint_info(zh)));\n        oa = create_buffer_oarchive();\n        rc = serialize_RequestHeader(oa, \"header\", &h);\n        rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n                get_buffer_len(oa));\n        /* We queued the buffer, so don't free it */\n        close_buffer_oarchive(&oa, 0);\n        if (rc < 0) {\n            rc = ZMARSHALLINGERROR;\n            goto finish;\n        }\n\n        /* make sure the close request is sent; we set timeout to an arbitrary\n         * (but reasonable) number of milliseconds since we want the call to block*/\n        rc=adaptor_send_queue(zh, 3000);\n    }else{\n        LOG_INFO((\"Freeing zookeeper resources for sessionId=%#llx\\n\",\n                zh->client_id.client_id));\n        rc = ZOK;\n    }\n\nfinish:\n    destroy(zh);\n    adaptor_destroy(zh);\n    free(zh);\n#ifdef WIN32\n    Win32WSACleanup();\n#endif\n    return rc;\n}\n\nstatic int isValidPath(const char* path, const int flags) {\n    int len = 0;\n    char lastc = '/';\n    char c;\n    int i = 0;\n\n  if (path == 0)\n    return 0;\n  len = strlen(path);\n  if (len == 0)\n    return 0;\n  if (path[0] != '/')\n    return 0;\n  if (len == 1) // done checking - it's the root\n    return 1;\n  if (path[len - 1] == '/' && !(flags & ZOO_SEQUENCE))\n    return 0;\n\n  i = 1;\n  for (; i < len; lastc = path[i], i++) {\n    c = path[i];\n\n    if (c == 0) {\n      return 0;\n    } else if (c == '/' && lastc == '/') {\n      return 0;\n    } else if (c == '.' && lastc == '.') {\n      if (path[i-2] == '/' && (((i + 1 == len) && !(flags & ZOO_SEQUENCE))\n                               || path[i+1] == '/')) {\n        return 0;\n      }\n    } else if (c == '.') {\n      if ((path[i-1] == '/') && (((i + 1 == len) && !(flags & ZOO_SEQUENCE))\n                                 || path[i+1] == '/')) {\n        return 0;\n      }\n    } else if (c > 0x00 && c < 0x1f) {\n      return 0;\n    }\n  }\n\n  return 1;\n}\n\n/*---------------------------------------------------------------------------*\n * REQUEST INIT HELPERS\n *---------------------------------------------------------------------------*/\n/* Common Request init helper functions to reduce code duplication */\nstatic int Request_path_init(zhandle_t *zh, int flags, \n        char **path_out, const char *path)\n{\n    assert(path_out);\n    \n    *path_out = prepend_string(zh, path);\n    if (zh == NULL || !isValidPath(*path_out, flags)) {\n        free_duplicate_path(*path_out, path);\n        return ZBADARGUMENTS;\n    }\n    if (is_unrecoverable(zh)) {\n        free_duplicate_path(*path_out, path);\n        return ZINVALIDSTATE;\n    }\n\n    return ZOK;\n}\n\nstatic int Request_path_watch_init(zhandle_t *zh, int flags,\n        char **path_out, const char *path,\n        int32_t *watch_out, uint32_t watch)\n{\n    int rc = Request_path_init(zh, flags, path_out, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    *watch_out = watch;\n    return ZOK;\n}\n\n/*---------------------------------------------------------------------------*\n * ASYNC API\n *---------------------------------------------------------------------------*/\nint zoo_aget(zhandle_t *zh, const char *path, int watch, data_completion_t dc,\n        const void *data)\n{\n    return zoo_awget(zh,path,watch?zh->watcher:0,zh->context,dc,data);\n}\n\nint zoo_awget(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        data_completion_t dc, const void *data)\n{\n    struct oarchive *oa;\n    char *server_path = prepend_string(zh, path);\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type ,ZOO_GETDATA_OP)};\n    struct GetDataRequest req =  { (char*)server_path, watcher!=0 };\n    int rc;\n\n    if (zh==0 || !isValidPath(server_path, 0)) {\n        free_duplicate_path(server_path, path);\n        return ZBADARGUMENTS;\n    }\n    if (is_unrecoverable(zh)) {\n        free_duplicate_path(server_path, path);\n        return ZINVALIDSTATE;\n    }\n    oa=create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_GetDataRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_data_completion(zh, h.xid, dc, data,\n        create_watcher_registration(server_path,data_result_checker,watcher,watcherCtx));\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(server_path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nstatic int SetDataRequest_init(zhandle_t *zh, struct SetDataRequest *req,\n        const char *path, const char *buffer, int buflen, int version)\n{\n    int rc;\n    assert(req);\n    rc = Request_path_init(zh, 0, &req->path, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    req->data.buff = (char*)buffer;\n    req->data.len = buflen;\n    req->version = version;\n\n    return ZOK;\n}\n\nint zoo_aset(zhandle_t *zh, const char *path, const char *buffer, int buflen,\n        int version, stat_completion_t dc, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid , get_xid()), STRUCT_INITIALIZER (type , ZOO_SETDATA_OP)};\n    struct SetDataRequest req;\n    int rc = SetDataRequest_init(zh, &req, path, buffer, buflen, version);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_SetDataRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_stat_completion(zh, h.xid, dc, data,0);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nstatic int CreateRequest_init(zhandle_t *zh, struct CreateRequest *req,\n        const char *path, const char *value,\n        int valuelen, const struct ACL_vector *acl_entries, int flags)\n{\n    int rc;\n    assert(req);\n    rc = Request_path_init(zh, flags, &req->path, path);\n    assert(req);\n    if (rc != ZOK) {\n        return rc;\n    }\n    req->flags = flags;\n    req->data.buff = (char*)value;\n    req->data.len = valuelen;\n    if (acl_entries == 0) {\n        req->acl.count = 0;\n        req->acl.data = 0;\n    } else {\n        req->acl = *acl_entries;\n    }\n\n    return ZOK;\n}\n\nint zoo_acreate(zhandle_t *zh, const char *path, const char *value,\n        int valuelen, const struct ACL_vector *acl_entries, int flags,\n        string_completion_t completion, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type ,ZOO_CREATE_OP) };\n    struct CreateRequest req;\n\n    int rc = CreateRequest_init(zh, &req, \n            path, value, valuelen, acl_entries, flags);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_CreateRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_string_completion(zh, h.xid, completion, data);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nint DeleteRequest_init(zhandle_t *zh, struct DeleteRequest *req, \n        const char *path, int version)\n{\n    int rc = Request_path_init(zh, 0, &req->path, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    req->version = version;\n    return ZOK;\n}\n\nint zoo_adelete(zhandle_t *zh, const char *path, int version,\n        void_completion_t completion, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type , ZOO_DELETE_OP)};\n    struct DeleteRequest req;\n    int rc = DeleteRequest_init(zh, &req, path, version);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_DeleteRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_void_completion(zh, h.xid, completion, data);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nint zoo_aexists(zhandle_t *zh, const char *path, int watch,\n        stat_completion_t sc, const void *data)\n{\n    return zoo_awexists(zh,path,watch?zh->watcher:0,zh->context,sc,data);\n}\n\nint zoo_awexists(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        stat_completion_t completion, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid ,get_xid()), STRUCT_INITIALIZER (type , ZOO_EXISTS_OP) };\n    struct ExistsRequest req;\n    int rc = Request_path_watch_init(zh, 0, &req.path, path, \n            &req.watch, watcher != NULL);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_ExistsRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_stat_completion(zh, h.xid, completion, data,\n        create_watcher_registration(req.path,exists_result_checker,\n                watcher,watcherCtx));\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nstatic int zoo_awget_children_(zhandle_t *zh, const char *path,\n         watcher_fn watcher, void* watcherCtx,\n         strings_completion_t sc,\n         const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type , ZOO_GETCHILDREN_OP)};\n    struct GetChildrenRequest req ;\n    int rc = Request_path_watch_init(zh, 0, &req.path, path, \n            &req.watch, watcher != NULL);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_GetChildrenRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_strings_completion(zh, h.xid, sc, data,\n            create_watcher_registration(req.path,child_result_checker,watcher,watcherCtx));\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nint zoo_aget_children(zhandle_t *zh, const char *path, int watch,\n        strings_completion_t dc, const void *data)\n{\n    return zoo_awget_children_(zh,path,watch?zh->watcher:0,zh->context,dc,data);\n}\n\nint zoo_awget_children(zhandle_t *zh, const char *path,\n         watcher_fn watcher, void* watcherCtx,\n         strings_completion_t dc,\n         const void *data)\n{\n    return zoo_awget_children_(zh,path,watcher,watcherCtx,dc,data);\n}\n\nstatic int zoo_awget_children2_(zhandle_t *zh, const char *path,\n         watcher_fn watcher, void* watcherCtx,\n         strings_stat_completion_t ssc,\n         const void *data)\n{\n    /* invariant: (sc == NULL) != (sc == NULL) */\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER( xid, get_xid()), STRUCT_INITIALIZER (type ,ZOO_GETCHILDREN2_OP)};\n    struct GetChildren2Request req ;\n    int rc = Request_path_watch_init(zh, 0, &req.path, path, \n            &req.watch, watcher != NULL);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_GetChildren2Request(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_strings_stat_completion(zh, h.xid, ssc, data,\n            create_watcher_registration(req.path,child_result_checker,watcher,watcherCtx));\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nint zoo_aget_children2(zhandle_t *zh, const char *path, int watch,\n        strings_stat_completion_t dc, const void *data)\n{\n    return zoo_awget_children2_(zh,path,watch?zh->watcher:0,zh->context,dc,data);\n}\n\nint zoo_awget_children2(zhandle_t *zh, const char *path,\n         watcher_fn watcher, void* watcherCtx,\n         strings_stat_completion_t dc,\n         const void *data)\n{\n    return zoo_awget_children2_(zh,path,watcher,watcherCtx,dc,data);\n}\n\nint zoo_async(zhandle_t *zh, const char *path,\n        string_completion_t completion, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER (type , ZOO_SYNC_OP)};\n    struct SyncRequest req;\n    int rc = Request_path_init(zh, 0, &req.path, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_SyncRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_string_completion(zh, h.xid, completion, data);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\n\nint zoo_aget_acl(zhandle_t *zh, const char *path, acl_completion_t completion,\n        const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER (xid , get_xid()), STRUCT_INITIALIZER(type ,ZOO_GETACL_OP)};\n    struct GetACLRequest req;\n    int rc = Request_path_init(zh, 0, &req.path, path) ;\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_GetACLRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_acl_completion(zh, h.xid, completion, data);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\nint zoo_aset_acl(zhandle_t *zh, const char *path, int version,\n        struct ACL_vector *acl, void_completion_t completion, const void *data)\n{\n    struct oarchive *oa;\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid ,get_xid()), STRUCT_INITIALIZER (type , ZOO_SETACL_OP)};\n    struct SetACLRequest req;\n    int rc = Request_path_init(zh, 0, &req.path, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    oa = create_buffer_oarchive();\n    req.acl = *acl;\n    req.version = version;\n    rc = serialize_RequestHeader(oa, \"header\", &h);\n    rc = rc < 0 ? rc : serialize_SetACLRequest(oa, \"req\", &req);\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_void_completion(zh, h.xid, completion, data);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    free_duplicate_path(req.path, path);\n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending request xid=%#x for path [%s] to %s\",h.xid,path,\n            format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n    return (rc < 0)?ZMARSHALLINGERROR:ZOK;\n}\n\n/* Completions for multi-op results */\nstatic void op_result_string_completion(int err, const char *value, const void *data)\n{\n    struct zoo_op_result *result = (struct zoo_op_result *)data;\n    assert(result);\n    result->err = err;\n    \n    if (result->value && value) {\n        int len = strlen(value) + 1;\n\t\tif (len > result->valuelen) {\n\t\t\tlen = result->valuelen;\n\t\t}\n\t\tif (len > 0) {\n\t\t\tmemcpy(result->value, value, len - 1);\n\t\t\tresult->value[len - 1] = '\\0';\n\t\t}\n    } else {\n        result->value = NULL;\n    }\n}\n\nstatic void op_result_void_completion(int err, const void *data)\n{\n    struct zoo_op_result *result = (struct zoo_op_result *)data;\n    assert(result);\n    result->err = err;\n}\n\nstatic void op_result_stat_completion(int err, const struct Stat *stat, const void *data)\n{\n    struct zoo_op_result *result = (struct zoo_op_result *)data;\n    assert(result);\n    result->err = err;\n\n    if (result->stat && err == 0 && stat) {\n        *result->stat = *stat;\n    } else {\n        result->stat = NULL ;\n    }\n}   \n\nstatic int CheckVersionRequest_init(zhandle_t *zh, struct CheckVersionRequest *req,\n        const char *path, int version)\n{\n    int rc ;\n    assert(req);\n    rc = Request_path_init(zh, 0, &req->path, path);\n    if (rc != ZOK) {\n        return rc;\n    }\n    req->version = version;\n\n    return ZOK;\n}\n\nint zoo_amulti(zhandle_t *zh, int count, const zoo_op_t *ops,\n        zoo_op_result_t *results, void_completion_t completion, const void *data)\n{\n    struct RequestHeader h = { STRUCT_INITIALIZER(xid, get_xid()), STRUCT_INITIALIZER(type, ZOO_MULTI_OP) };\n    struct MultiHeader mh = { STRUCT_INITIALIZER(type, -1), STRUCT_INITIALIZER(done, 1), STRUCT_INITIALIZER(err, -1) };\n    struct oarchive *oa = create_buffer_oarchive();\n    completion_head_t clist = { 0 };\n\n    int rc = serialize_RequestHeader(oa, \"header\", &h);\n\n    int index = 0;\n    for (index=0; index < count; index++) {\n        const zoo_op_t *op = ops+index;\n        zoo_op_result_t *result = results+index;\n        completion_list_t *entry = NULL;\n\n        struct MultiHeader mh = { STRUCT_INITIALIZER(type, op->type), STRUCT_INITIALIZER(done, 0), STRUCT_INITIALIZER(err, -1) };\n        rc = rc < 0 ? rc : serialize_MultiHeader(oa, \"multiheader\", &mh);\n     \n        switch(op->type) {\n            case ZOO_CREATE_OP: {\n                struct CreateRequest req;\n\n                rc = rc < 0 ? rc : CreateRequest_init(zh, &req, \n                                        op->create_op.path, op->create_op.data, \n                                        op->create_op.datalen, op->create_op.acl, \n                                        op->create_op.flags);\n                rc = rc < 0 ? rc : serialize_CreateRequest(oa, \"req\", &req);\n                result->value = op->create_op.buf;\n\t\t\t\tresult->valuelen = op->create_op.buflen;\n\n                enter_critical(zh);\n                entry = create_completion_entry(h.xid, COMPLETION_STRING, op_result_string_completion, result, 0, 0); \n                leave_critical(zh);\n                free_duplicate_path(req.path, op->create_op.path);\n                break;\n            }\n\n            case ZOO_DELETE_OP: {\n                struct DeleteRequest req;\n                rc = rc < 0 ? rc : DeleteRequest_init(zh, &req, op->delete_op.path, op->delete_op.version);\n                rc = rc < 0 ? rc : serialize_DeleteRequest(oa, \"req\", &req);\n\n                enter_critical(zh);\n                entry = create_completion_entry(h.xid, COMPLETION_VOID, op_result_void_completion, result, 0, 0); \n                leave_critical(zh);\n                free_duplicate_path(req.path, op->delete_op.path);\n                break;\n            }\n\n            case ZOO_SETDATA_OP: {\n                struct SetDataRequest req;\n                rc = rc < 0 ? rc : SetDataRequest_init(zh, &req,\n                                        op->set_op.path, op->set_op.data, \n                                        op->set_op.datalen, op->set_op.version);\n                rc = rc < 0 ? rc : serialize_SetDataRequest(oa, \"req\", &req);\n                result->stat = op->set_op.stat;\n\n                enter_critical(zh);\n                entry = create_completion_entry(h.xid, COMPLETION_STAT, op_result_stat_completion, result, 0, 0); \n                leave_critical(zh);\n                free_duplicate_path(req.path, op->set_op.path);\n                break;\n            }\n\n            case ZOO_CHECK_OP: {\n                struct CheckVersionRequest req;\n                rc = rc < 0 ? rc : CheckVersionRequest_init(zh, &req,\n                                        op->check_op.path, op->check_op.version);\n                rc = rc < 0 ? rc : serialize_CheckVersionRequest(oa, \"req\", &req);\n\n                enter_critical(zh);\n                entry = create_completion_entry(h.xid, COMPLETION_VOID, op_result_void_completion, result, 0, 0); \n                leave_critical(zh);\n                free_duplicate_path(req.path, op->check_op.path);\n                break;\n            } \n\n            default:\n                LOG_ERROR((\"Unimplemented sub-op type=%d in multi-op\", op->type));\n                return ZUNIMPLEMENTED; \n        }\n\n        queue_completion(&clist, entry, 0);\n    }\n\n    rc = rc < 0 ? rc : serialize_MultiHeader(oa, \"multiheader\", &mh);\n  \n    /* BEGIN: CRTICIAL SECTION */\n    enter_critical(zh);\n    rc = rc < 0 ? rc : add_multi_completion(zh, h.xid, completion, data, &clist);\n    rc = rc < 0 ? rc : queue_buffer_bytes(&zh->to_send, get_buffer(oa),\n            get_buffer_len(oa));\n    leave_critical(zh);\n    \n    /* We queued the buffer, so don't free it */\n    close_buffer_oarchive(&oa, 0);\n\n    LOG_DEBUG((\"Sending multi request xid=%#x with %d subrequests to %s\",\n            h.xid, index, format_current_endpoint_info(zh)));\n    /* make a best (non-blocking) effort to send the requests asap */\n    adaptor_send_queue(zh, 0);\n\n    return (rc < 0) ? ZMARSHALLINGERROR : ZOK;\n}\n\nvoid zoo_create_op_init(zoo_op_t *op, const char *path, const char *value,\n        int valuelen,  const struct ACL_vector *acl, int flags, \n        char *path_buffer, int path_buffer_len)\n{\n    assert(op);\n    op->type = ZOO_CREATE_OP;\n    op->create_op.path = path;\n    op->create_op.data = value;\n    op->create_op.datalen = valuelen;\n    op->create_op.acl = acl;\n    op->create_op.flags = flags;\n    op->create_op.buf = path_buffer;\n    op->create_op.buflen = path_buffer_len;\n}\n\nvoid zoo_delete_op_init(zoo_op_t *op, const char *path, int version)\n{\n    assert(op);\n    op->type = ZOO_DELETE_OP;\n    op->delete_op.path = path;\n    op->delete_op.version = version;\n}\n\nvoid zoo_set_op_init(zoo_op_t *op, const char *path, const char *buffer, \n        int buflen, int version, struct Stat *stat)\n{\n    assert(op);\n    op->type = ZOO_SETDATA_OP;\n    op->set_op.path = path;\n    op->set_op.data = buffer;\n    op->set_op.datalen = buflen;\n    op->set_op.version = version;\n    op->set_op.stat = stat;\n}\n\nvoid zoo_check_op_init(zoo_op_t *op, const char *path, int version)\n{\n    assert(op);\n    op->type = ZOO_CHECK_OP;\n    op->check_op.path = path;\n    op->check_op.version = version;\n}\n\nint zoo_multi(zhandle_t *zh, int count, const zoo_op_t *ops, zoo_op_result_t *results)\n{\n    int rc;\n \n    struct sync_completion *sc = alloc_sync_completion();\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n   \n    rc = zoo_amulti(zh, count, ops, results, SYNCHRONOUS_MARKER, sc);\n    if (rc == ZOK) {\n        wait_sync_completion(sc);\n        rc = sc->rc;\n    }\n    free_sync_completion(sc);\n\n    return rc;\n}\n\n/* specify timeout of 0 to make the function non-blocking */\n/* timeout is in milliseconds */\nint flush_send_queue(zhandle_t*zh, int timeout)\n{\n    int rc= ZOK;\n    struct timeval started;\n#ifdef WIN32\n    fd_set pollSet; \n    struct timeval wait;\n#endif\n    gettimeofday(&started,0);\n    // we can't use dequeue_buffer() here because if (non-blocking) send_buffer()\n    // returns EWOULDBLOCK we'd have to put the buffer back on the queue.\n    // we use a recursive lock instead and only dequeue the buffer if a send was\n    // successful\n    lock_buffer_list(&zh->to_send);\n    while (zh->to_send.head != 0&& zh->state == ZOO_CONNECTED_STATE) {\n        if(timeout!=0){\n            int elapsed;\n            struct timeval now;\n            gettimeofday(&now,0);\n            elapsed=calculate_interval(&started,&now);\n            if (elapsed>timeout) {\n                rc = ZOPERATIONTIMEOUT;\n                break;\n            }\n\n#ifdef WIN32\n            wait = get_timeval(timeout-elapsed);\n            FD_ZERO(&pollSet);\n            FD_SET(zh->fd, &pollSet);\n            // Poll the socket\n            rc = select((int)(zh->fd)+1, NULL,  &pollSet, NULL, &wait);      \n#else\n            struct pollfd fds;\n            fds.fd = zh->fd;\n            fds.events = POLLOUT;\n            fds.revents = 0;\n            rc = poll(&fds, 1, timeout-elapsed);\n#endif\n            if (rc<=0) {\n                /* timed out or an error or POLLERR */\n                rc = rc==0 ? ZOPERATIONTIMEOUT : ZSYSTEMERROR;\n                break;\n            }\n        }\n\n        rc = send_buffer(zh->fd, zh->to_send.head);\n        if(rc==0 && timeout==0){\n            /* send_buffer would block while sending this buffer */\n            rc = ZOK;\n            break;\n        }\n        if (rc < 0) {\n            rc = ZCONNECTIONLOSS;\n            break;\n        }\n        // if the buffer has been sent successfully, remove it from the queue\n        if (rc > 0)\n            remove_buffer(&zh->to_send);\n        gettimeofday(&zh->last_send, 0);\n        rc = ZOK;\n    }\n    unlock_buffer_list(&zh->to_send);\n    return rc;\n}\n\nconst char* zerror(int c)\n{\n    switch (c){\n    case ZOK:\n      return \"ok\";\n    case ZSYSTEMERROR:\n      return \"system error\";\n    case ZRUNTIMEINCONSISTENCY:\n      return \"run time inconsistency\";\n    case ZDATAINCONSISTENCY:\n      return \"data inconsistency\";\n    case ZCONNECTIONLOSS:\n      return \"connection loss\";\n    case ZMARSHALLINGERROR:\n      return \"marshalling error\";\n    case ZUNIMPLEMENTED:\n      return \"unimplemented\";\n    case ZOPERATIONTIMEOUT:\n      return \"operation timeout\";\n    case ZBADARGUMENTS:\n      return \"bad arguments\";\n    case ZINVALIDSTATE:\n      return \"invalid zhandle state\";\n    case ZAPIERROR:\n      return \"api error\";\n    case ZNONODE:\n      return \"no node\";\n    case ZNOAUTH:\n      return \"not authenticated\";\n    case ZBADVERSION:\n      return \"bad version\";\n    case  ZNOCHILDRENFOREPHEMERALS:\n      return \"no children for ephemerals\";\n    case ZNODEEXISTS:\n      return \"node exists\";\n    case ZNOTEMPTY:\n      return \"not empty\";\n    case ZSESSIONEXPIRED:\n      return \"session expired\";\n    case ZINVALIDCALLBACK:\n      return \"invalid callback\";\n    case ZINVALIDACL:\n      return \"invalid acl\";\n    case ZAUTHFAILED:\n      return \"authentication failed\";\n    case ZCLOSING:\n      return \"zookeeper is closing\";\n    case ZNOTHING:\n      return \"(not error) no server responses to process\";\n    case ZSESSIONMOVED:\n      return \"session moved to another server, so operation is ignored\";\n    }\n    if (c > 0) {\n      return strerror(c);\n    }\n    return \"unknown error\";\n}\n\nint zoo_add_auth(zhandle_t *zh,const char* scheme,const char* cert,\n        int certLen,void_completion_t completion, const void *data)\n{\n    struct buffer auth;\n    auth_info *authinfo;\n    if(scheme==NULL || zh==NULL)\n        return ZBADARGUMENTS;\n\n    if (is_unrecoverable(zh))\n        return ZINVALIDSTATE;\n\n    // [ZOOKEEPER-800] zoo_add_auth should return ZINVALIDSTATE if\n    // the connection is closed. \n    if (zoo_state(zh) == 0) {\n        return ZINVALIDSTATE;\n    }\n\n    if(cert!=NULL && certLen!=0){\n        auth.buff=calloc(1,certLen);\n        if(auth.buff==0) {\n            return ZSYSTEMERROR;\n        }\n        memcpy(auth.buff,cert,certLen);\n        auth.len=certLen;\n    } else {\n        auth.buff = 0;\n        auth.len = 0;\n    }\n\n    zoo_lock_auth(zh);\n    authinfo = (auth_info*) malloc(sizeof(auth_info));\n    authinfo->scheme=strdup(scheme);\n    authinfo->auth=auth;\n    authinfo->completion=completion;\n    authinfo->data=data;\n    authinfo->next = NULL;\n    add_last_auth(&zh->auth_h, authinfo);\n    zoo_unlock_auth(zh);\n\n    if(zh->state == ZOO_CONNECTED_STATE || zh->state == ZOO_ASSOCIATING_STATE)\n        return send_last_auth_info(zh);\n\n    return ZOK;\n}\n\nstatic const char* format_endpoint_info(const struct sockaddr_storage* ep)\n{\n    static char buf[128];\n    char addrstr[128];\n    void *inaddr;\n#ifdef WIN32\n    char * addrstring;\n#endif\n    int port;\n    if(ep==0)\n        return \"null\";\n\n#if defined(AF_INET6)\n    if(ep->ss_family==AF_INET6){\n        inaddr=&((struct sockaddr_in6*)ep)->sin6_addr;\n        port=((struct sockaddr_in6*)ep)->sin6_port;\n    } else {\n#endif\n        inaddr=&((struct sockaddr_in*)ep)->sin_addr;\n        port=((struct sockaddr_in*)ep)->sin_port;\n#if defined(AF_INET6)\n    }\n#endif\n#ifdef WIN32\n    addrstring = inet_ntoa (*(struct in_addr*)inaddr); \n    sprintf(buf,\"%s:%d\",addrstring,ntohs(port));\n#else\n    inet_ntop(ep->ss_family,inaddr,addrstr,sizeof(addrstr)-1);\n    sprintf(buf,\"%s:%d\",addrstr,ntohs(port));\n#endif    \n    return buf;\n}\n\nstatic const char* format_current_endpoint_info(zhandle_t* zh)\n{\n    return format_endpoint_info(&zh->addrs[zh->connect_index]);\n}\n\nvoid zoo_deterministic_conn_order(int yesOrNo)\n{\n    disable_conn_permute=yesOrNo;\n}\n\n/*---------------------------------------------------------------------------*\n * SYNC API\n *---------------------------------------------------------------------------*/\nint zoo_create(zhandle_t *zh, const char *path, const char *value,\n        int valuelen, const struct ACL_vector *acl, int flags,\n        char *path_buffer, int path_buffer_len)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    sc->u.str.str = path_buffer;\n    sc->u.str.str_len = path_buffer_len;\n    rc=zoo_acreate(zh, path, value, valuelen, acl, flags, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_delete(zhandle_t *zh, const char *path, int version)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc=zoo_adelete(zh, path, version, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat)\n{\n    return zoo_wexists(zh,path,watch?zh->watcher:0,zh->context,stat);\n}\n\nint zoo_wexists(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx, struct Stat *stat)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc=zoo_awexists(zh,path,watcher,watcherCtx,SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0&& stat) {\n            *stat = sc->u.stat;\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer,\n        int* buffer_len, struct Stat *stat)\n{\n    return zoo_wget(zh,path,watch?zh->watcher:0,zh->context,\n            buffer,buffer_len,stat);\n}\n\nint zoo_wget(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        char *buffer, int* buffer_len, struct Stat *stat)\n{\n    struct sync_completion *sc;\n    int rc=0;\n\n    if(buffer_len==NULL)\n        return ZBADARGUMENTS;\n    if((sc=alloc_sync_completion())==NULL)\n        return ZSYSTEMERROR;\n\n    sc->u.data.buffer = buffer;\n    sc->u.data.buff_len = *buffer_len;\n    rc=zoo_awget(zh, path, watcher, watcherCtx, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0) {\n            if(stat)\n                *stat = sc->u.data.stat;\n            *buffer_len = sc->u.data.buff_len;\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_set(zhandle_t *zh, const char *path, const char *buffer, int buflen,\n        int version)\n{\n  return zoo_set2(zh, path, buffer, buflen, version, 0);\n}\n\nint zoo_set2(zhandle_t *zh, const char *path, const char *buffer, int buflen,\n        int version, struct Stat *stat)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc=zoo_aset(zh, path, buffer, buflen, version, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0 && stat) {\n            *stat = sc->u.stat;\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nstatic int zoo_wget_children_(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc= zoo_awget_children (zh, path, watcher, watcherCtx, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0) {\n            if (strings) {\n                *strings = sc->u.strs2;\n            } else {\n                deallocate_String_vector(&sc->u.strs2);\n            }\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nstatic int zoo_wget_children2_(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings, struct Stat *stat)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc= zoo_awget_children2(zh, path, watcher, watcherCtx, SYNCHRONOUS_MARKER, sc);\n\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0) {\n            *stat = sc->u.strs_stat.stat2;\n            if (strings) {\n                *strings = sc->u.strs_stat.strs2;\n            } else {\n                deallocate_String_vector(&sc->u.strs_stat.strs2);\n            }\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_get_children(zhandle_t *zh, const char *path, int watch,\n        struct String_vector *strings)\n{\n    return zoo_wget_children_(zh,path,watch?zh->watcher:0,zh->context,strings);\n}\n\nint zoo_wget_children(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings)\n{\n    return zoo_wget_children_(zh,path,watcher,watcherCtx,strings);\n}\n\nint zoo_get_children2(zhandle_t *zh, const char *path, int watch,\n        struct String_vector *strings, struct Stat *stat)\n{\n    return zoo_wget_children2_(zh,path,watch?zh->watcher:0,zh->context,strings,stat);\n}\n\nint zoo_wget_children2(zhandle_t *zh, const char *path,\n        watcher_fn watcher, void* watcherCtx,\n        struct String_vector *strings, struct Stat *stat)\n{\n    return zoo_wget_children2_(zh,path,watcher,watcherCtx,strings,stat);\n}\n\nint zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl,\n        struct Stat *stat)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc=zoo_aget_acl(zh, path, SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n        if (rc == 0&& stat) {\n            *stat = sc->u.acl.stat;\n        }\n        if (rc == 0) {\n            if (acl) {\n                *acl = sc->u.acl.acl;\n            } else {\n                deallocate_ACL_vector(&sc->u.acl.acl);\n            }\n        }\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n\nint zoo_set_acl(zhandle_t *zh, const char *path, int version,\n        const struct ACL_vector *acl)\n{\n    struct sync_completion *sc = alloc_sync_completion();\n    int rc;\n    if (!sc) {\n        return ZSYSTEMERROR;\n    }\n    rc=zoo_aset_acl(zh, path, version, (struct ACL_vector*)acl,\n            SYNCHRONOUS_MARKER, sc);\n    if(rc==ZOK){\n        wait_sync_completion(sc);\n        rc = sc->rc;\n    }\n    free_sync_completion(sc);\n    return rc;\n}\n"
  },
  {
    "path": "src/c/tests/CollectionUtil.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef _COLLECTION_UTIL_H_\n#define _COLLECTION_UTIL_H_\n\n/**\n * \\file\n * CollectionBuilder and DictionaryBuilder classes and collection utility functions\n */\n\nnamespace Util \n{\n\n// *********************************************************\n/** A shortcut to use for building collections.\n * This class is a wrapper around standard STL collection containers such as vector.\n * It allows one to conveniently build collections at the variable initialization time:\n * \\code\n * #include \"CollectionUtil.h\"\n * #include \"Vector.h\"  // for ostream << operator overload for STL vector\n * using Util;\n * \n * int main()\n * {\n *   typedef vector<string> MyVector;\n *   MyVector myVector=CollectionBuilder<MyVector>()(\"str1\")(\"str2\")(\"str3\");\n *   cout<<myVector;\n *   // the following output will be produced:\n *   // [str1,str2,str3]\n * }\n * \\endcode\n */\ntemplate <class CONT>\nclass CollectionBuilder\n{\npublic:\n  /// Type of the collection container. \n  typedef CONT CollectionType;\n  /// Container's value type.\n  typedef typename CollectionType::value_type value_type;\n  /// Container's constant iterator type.\n  typedef typename CollectionType::const_iterator const_iterator;\n  /// Container's size type.\n  typedef typename CollectionType::size_type size_type;\n\n  /** Operator function call overload to allow call chaining.\n   * \\param value the value to be inserted into the container\n   */\n  CollectionBuilder<CONT>& operator()(const value_type& value){\n    return push_back(value);\n  }\n  /** Same as regular STL push_back() but allows call chaining.\n   * \\param value the value to be inserted into the container\n   */\n  CollectionBuilder<CONT>& push_back(const value_type& value){\n    collection_.push_back(value);\n    return *this;\n  }\n  /// \\name Standard STL container interface\n  /// @{\n  const_iterator begin() const{return collection_.begin();}\n  const_iterator end() const{return collection_.end();}\n  size_type size() const{return collection_.size();}\n  void clear() {collection_.clear();}\n  ///@}\n  /// Explicit typecast operator.\n  operator const CollectionType&() const {return collection_;}\nprivate:\n  /// \\cond PRIVATE\n  CollectionType collection_;\n  /// \\endcond\n};\n\n\n// *********************************************************\n/** A shortcut to use for building dictionaries.\n * This class is a wrapper around standard STL associative containers such as map.\n * It allows one to conveniently build dictionaries at the variable initialization time:\n * \\code\n * #include \"CollectionUtil.h\"\n * #include \"Map.h\"  // for ostream << operator overload for STL map\n * using Util;\n * \n * int main()\n * {\n *   typedef map<string,int> MyMap;\n *   MyMap myMap=DictionaryBuilder<MyMap>()(\"str1\",1)(\"str2\",2)(\"str3\",3);\n *   cout<<myMap;\n *   // the following output will be produced:\n *   // [str1=1,str2=2,str3=3]\n * }\n * \\endcode\n */\ntemplate <class CONT>\nclass DictionaryBuilder\n{\npublic:\n  /// The type of the associative container\n  typedef CONT DictionaryType;\n  /// Container's element type (usually a pair<key_type,mapped_type>)\n  typedef typename DictionaryType::value_type value_type;\n  /// Container's key type\n  typedef typename DictionaryType::key_type key_type;\n  /// Container's value type \n  typedef typename DictionaryType::mapped_type mapped_type;\n  /// Container's constant iterator type \n  typedef typename DictionaryType::const_iterator const_iterator;\n  /// Container's writable iterator type   \n  typedef typename DictionaryType::iterator iterator;\n  /// Container's size type\n  typedef typename DictionaryType::size_type size_type;\n \n  /** Operator function call overload to allow call chaining.\n   * \\param key the value key to be inserted\n   * \\param value the value to be inserted into the container\n   * \\return a non-const reference to self\n   */\n  DictionaryBuilder<CONT>& operator()(const key_type& key,const mapped_type& value){\n    dict_.insert(value_type(key,value));\n    return *this;\n  }\n  /** Lookup value by key.\n   * \\param key the key associated with the value.\n   * \\return a non-const iterator pointing to the element whose key matched the \\a key parameter\n   */\n  iterator find(const key_type& key){\n    return dict_.find(key);\n  }\n  /** Lookup value by key.\n   * \\param key the key associated with the value.\n   * \\return a const iterator pointing to the element whose key matched the \\a key parameter\n   */\n  const_iterator find(const key_type& key) const{\n    return dict_.find(key);\n  }\n\n  /// \\name Standard STL container interface\n  /// @{\n  const_iterator begin() const{return dict_.begin();}\n  const_iterator end() const{return dict_.end();}\n  size_type size() const{return dict_.size();}\n  void clear() {dict_.clear();}\n  ///@}\n  /// Explicit typecast operator.\n  operator const DictionaryType&() const {return dict_;}\nprivate:\n  DictionaryType dict_;\n};\n\n\n// ***********************************************************\n/** Deletes all dynamically allocated elements of a collection.\n * C::value_type is expected to be a pointer to a dynamically allocated object, or it won't compile.\n * The function will iterate over all container elements and call delete for each of them.\n * \\param c a collection (vector,set) whose elements are being deleted.\n */\ntemplate <class C>\nvoid clearCollection(C& c){\n  for(typename C::const_iterator it=c.begin();it!=c.end();++it)\n    delete *it;\n  c.clear();\n}\n\n/** Deletes all dynamically allocated values of the assotiative container.\n * The function expects the M::value_type to be a pair<..., ptr_to_type>, or it won't compile.\n * It first deletes the objects pointed to by ptr_to_type\n * and then clears (calls m.clear()) the container.\n * \\param m an associative container (map,hash_map) whose elements are being deleted.\n */\ntemplate <class M>\nvoid clearMap(M& m){\n  for(typename M::const_iterator it=m.begin();it!=m.end();++it)\n    delete it->second;\n  m.clear();\n}\n\n} // namespace Util\n\n\n#endif // _COLLECTION_UTIL_H_\n"
  },
  {
    "path": "src/c/tests/CppAssertHelper.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef CPPASSERTHELPER_H_\n#define CPPASSERTHELPER_H_\n\n#include <cppunit/TestAssert.h>\n\n// make it possible to specify location of the ASSERT call\n#define CPPUNIT_ASSERT_EQUAL_LOC(expected,actual,file,line) \\\n  ( CPPUNIT_NS::assertEquals( (expected),              \\\n                              (actual),                \\\n                              CPPUNIT_NS::SourceLine(file,line),    \\\n                              \"\" ) )\n\n#define CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(message,expected,actual,file,line) \\\n  ( CPPUNIT_NS::assertEquals( (expected),              \\\n                              (actual),                \\\n                              CPPUNIT_NS::SourceLine(file,line), \\\n                              (message) ) )\n\n#endif /*CPPASSERTHELPER_H_*/\n"
  },
  {
    "path": "src/c/tests/LibCMocks.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cstdlib>\n#include <cstdarg>\n#include <iostream>\n#include <stdarg.h>\n\n#include \"Util.h\"\n#include \"LibCMocks.h\"\n\n#undef USING_DUMA\n\nusing namespace std;\n\n// *****************************************************************************\n// gethostbyname\n\nstruct hostent* gethostbyname(const char *name) {\n    if(!Mock_gethostbyname::mock_)\n        return LIBC_SYMBOLS.gethostbyname(name);\n    return Mock_gethostbyname::mock_->call(name);\n}\n\nMock_gethostbyname* Mock_gethostbyname::mock_=0;\n\nMock_gethostbyname::~Mock_gethostbyname(){\n    mock_=0;\n    for(unsigned int i=0;i<gethostbynameReturns.size();i++)\n        delete gethostbynameReturns[i];\n}\n\nMock_gethostbyname::HostEntry& Mock_gethostbyname::addHostEntry(\n        const char* hostName, short addrtype) {\n    gethostbynameReturns.push_back(new HostEntry(hostName, addrtype));\n    return *gethostbynameReturns.back();\n}\n\nhostent* Mock_gethostbyname::call(const char* name) {\n    assert(\"Must add one or more mock hostent entries first\"&&\n            (gethostbynameReturns.size()!=0));\n    return gethostbynameReturns[current++ % gethostbynameReturns.size()];\n}\n\nstatic char** appendString(char **list,const char* str,int len=0){\n    const int SIZE_INCREMENT=16;\n    if(list==0)\n        list=(char**)LIBC_SYMBOLS.calloc(SIZE_INCREMENT,sizeof(char*));\n    // find the first available slot\n    int count=0;\n    for(char** ptr=list; *ptr!=0; ptr++,count++);\n    if(((count+1)%SIZE_INCREMENT)==0){\n        list=(char**)LIBC_SYMBOLS.realloc(list,(count+1+SIZE_INCREMENT)*sizeof(char*));\n        memset(list+count+1,0,SIZE_INCREMENT*sizeof(char*));\n    }\n    if(len==0){\n        len=strlen(str)+1;\n    }\n    char* ptr=(char*)malloc(len);\n    memcpy(ptr,str,len);\n    list[count]=ptr;\n    return list;\n}\n\nstatic void freeList(char **list){\n    if(list==0) return;\n    for(char** ptr=list; *ptr!=0; ptr++)\n        LIBC_SYMBOLS.free((void*)*ptr);\n    LIBC_SYMBOLS.free((void*)list);\n}\n\nMock_gethostbyname::HostEntry::HostEntry(const char* hostName, short addrtype) {\n    h_name=strdup(hostName);\n    h_addrtype=addrtype;\n    if(addrtype==AF_INET)\n        h_length=4;\n    else{\n#ifdef AF_INET6\n        h_length=6; // TODO: not really sure, verify!\n#else\n        assert(\"AF_INET6 not supported yet\"&&false);\n#endif\n    }\n    h_aliases=h_addr_list=0;\n}\n\nMock_gethostbyname::HostEntry::~HostEntry(){\n    if(h_name) LIBC_SYMBOLS.free((void*)h_name);\n    freeList(h_aliases); h_aliases=0;\n    freeList(h_addr_list); h_addr_list=0;\n}\n\nMock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAlias(\n        const char* alias) {\n    h_aliases=appendString(h_aliases,alias);\n    return *this;\n}\n\nMock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAddress(\n        const char* addr4) {\n    h_addr_list=appendString(h_addr_list,addr4,4);\n    return *this;\n}\n\n\n// *****************************************************************************\n// calloc\n#ifndef USING_DUMA\nDECLARE_WRAPPER(void*,calloc,(size_t p1, size_t p2)){\n    if(!Mock_calloc::mock_)\n        return CALL_REAL(calloc,(p1,p2));\n    return Mock_calloc::mock_->call(p1,p2);\n}\n#endif\n\nvoid* Mock_calloc::call(size_t p1, size_t p2){\n#ifndef USING_DUMA\n    if(counter++ ==callsBeforeFailure){\n        counter=0;\n        errno=errnoOnFailure;\n        return 0;\n    }\n    return CALL_REAL(calloc,(p1,p2));\n#else\n    return 0;\n#endif\n}\n\nMock_calloc* Mock_calloc::mock_=0;\n\n// *****************************************************************************\n// realloc\n\n#ifndef USING_DUMA\nDECLARE_WRAPPER(void*,realloc,(void* p, size_t s)){\n    if(!Mock_realloc::mock_)\n        return LIBC_SYMBOLS.realloc(p,s);\n    return Mock_realloc::mock_->call(p,s);\n}\n#endif\n\nMock_realloc* Mock_realloc::mock_=0;\n\nvoid* Mock_realloc::call(void* p, size_t s){\n    if(counter++ ==callsBeforeFailure){\n        counter=0;\n        errno=errnoOnFailure;\n        return 0;\n    }\n    return LIBC_SYMBOLS.realloc(p,s);\n}\n\n// *****************************************************************************\n// random\nRANDOM_RET_TYPE random(){\n    if(!Mock_random::mock_)\n        return LIBC_SYMBOLS.random();\n    return Mock_random::mock_->call();    \n}\n\nvoid srandom(unsigned long seed){\n    if (!Mock_random::mock_)\n        LIBC_SYMBOLS.srandom(seed);\n    else\n        Mock_random::mock_->setSeed(seed);\n}\n\nMock_random* Mock_random::mock_=0;\n\nint Mock_random::call(){\n    assert(\"Must specify one or more random integers\"&&(randomReturns.size()!=0));\n    return randomReturns[currentIdx++ % randomReturns.size()];\n}\n\n// *****************************************************************************\n// free\n#ifndef USING_DUMA\nDECLARE_WRAPPER(void,free,(void* p)){\n    if(Mock_free_noop::mock_ && !Mock_free_noop::mock_->nested)\n        Mock_free_noop::mock_->call(p);\n    else\n        CALL_REAL(free,(p));\n}\n#endif\n\nvoid Mock_free_noop::call(void* p){\n    // on cygwin libc++ is linked statically\n    // push_back() may call free(), hence the nesting guards\n    synchronized(mx);\n    nested++;\n    callCounter++;\n    requested.push_back(p);\n    nested--;\n}\nvoid Mock_free_noop::freeRequested(){\n#ifndef USING_DUMA\n    synchronized(mx);\n    for(unsigned i=0; i<requested.size();i++)\n        CALL_REAL(free,(requested[i]));\n#endif\n}\n\nint Mock_free_noop::getFreeCount(void* p){\n    int cnt=0;\n    synchronized(mx);\n    for(unsigned i=0;i<requested.size();i++)\n        if(requested[i]==p)cnt++;\n    return cnt;\n}\n\nbool Mock_free_noop::isFreed(void* p){\n    synchronized(mx);\n    for(unsigned i=0;i<requested.size();i++)\n        if(requested[i]==p)return true;\n    return false;\n}\n\nMock_free_noop* Mock_free_noop::mock_=0;\n\n// *****************************************************************************\n// socket\nint socket(int domain, int type, int protocol){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.socket(domain,type,protocol);\n    return Mock_socket::mock_->callSocket(domain,type,protocol);\n}\n\nint close(int fd){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.close(fd);\n    return Mock_socket::mock_->callClose(fd);\n}\n\nint getsockopt(int s,int level,int optname,void *optval,socklen_t *optlen){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.getsockopt(s,level,optname,optval,optlen);\n    return Mock_socket::mock_->callGet(s,level,optname,optval,optlen);    \n}\n\nint setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.setsockopt(s,level,optname,optval,optlen);\n    return Mock_socket::mock_->callSet(s,level,optname,optval,optlen);      \n}\nint connect(int s,const struct sockaddr *addr,socklen_t len){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.connect(s,addr,len);\n    return Mock_socket::mock_->callConnect(s,addr,len);\n}\nssize_t send(int s,const void *buf,size_t len,int flags){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.send(s,buf,len,flags);\n    return Mock_socket::mock_->callSend(s,buf,len,flags);    \n}\n\nssize_t recv(int s,void *buf,size_t len,int flags){\n    if (!Mock_socket::mock_)\n        return LIBC_SYMBOLS.recv(s,buf,len,flags);\n    return Mock_socket::mock_->callRecv(s,buf,len,flags);        \n}\n\nMock_socket* Mock_socket::mock_=0;\n\n// *****************************************************************************\n// fcntl\nextern \"C\" int fcntl(int fd,int cmd,...){\n    va_list va;\n    va_start(va,cmd);\n    void* arg = va_arg(va, void *);\n    va_end (va);\n    if (!Mock_fcntl::mock_)\n        return LIBC_SYMBOLS.fcntl(fd,cmd,arg);\n    return Mock_fcntl::mock_->call(fd,cmd,arg);    \n}\n\nMock_fcntl* Mock_fcntl::mock_=0;\n\n// *****************************************************************************\n// select\nint select(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *timeout){\n    if (!Mock_select::mock_)\n        return LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,timeout);\n    return Mock_select::mock_->call(nfds,rfds,wfds,efds,timeout);        \n}\n\nMock_select* Mock_select::mock_=0;\n\n// *****************************************************************************\n// poll\nMock_poll* Mock_poll::mock_=0;\nint poll(struct pollfd *fds, POLL_NFDS_TYPE nfds, int timeout){\n    if (!Mock_poll::mock_)\n        return LIBC_SYMBOLS.poll(fds,nfds,timeout);\n    return Mock_poll::mock_->call(fds,nfds,timeout);        \n    \n}\n\n/*\n * Recent gcc with -O2 and glibc FORTIFY feature may cause our poll\n * mock to be ignored.\n */\n#if __USE_FORTIFY_LEVEL > 0\nint __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,\n                __SIZE_TYPE__ __fdslen) {\n    return poll(__fds, __nfds, __timeout);\n}\n#endif\n\n// *****************************************************************************\n// gettimeofday\nint gettimeofday(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){\n    if (!Mock_gettimeofday::mock_)\n        return LIBC_SYMBOLS.gettimeofday(tp,tzp);\n    return Mock_gettimeofday::mock_->call(tp,tzp);            \n}\n\nMock_gettimeofday* Mock_gettimeofday::mock_=0;\n\n"
  },
  {
    "path": "src/c/tests/LibCMocks.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef LIBCMOCKS_H_\n#define LIBCMOCKS_H_\n\n#include <string>\n#include <vector>\n#include <deque>\n\n#include <errno.h>\n#include <string.h>\n\n#include \"MocksBase.h\"\n#include \"LibCSymTable.h\"\n#include \"ThreadingUtil.h\"\n\n// *****************************************************************************\n// gethostbyname\n\nclass Mock_gethostbyname: public Mock\n{\npublic:\n    struct HostEntry: public hostent {\n        HostEntry(const char* hostName,short addrtype);\n        ~HostEntry();\n        HostEntry& addAlias(const char* alias);\n        HostEntry& addAddress(const char* addr4);\n    };\n\n    Mock_gethostbyname():current(0){mock_=this;}\n    virtual ~Mock_gethostbyname();\n    HostEntry& addHostEntry(const char* hostName,short addrtype=AF_INET);\n    virtual hostent* call(const char* name);\n\n    typedef std::vector<HostEntry*> HostEntryCollection;\n    HostEntryCollection gethostbynameReturns;\n    int current;\n    static Mock_gethostbyname* mock_;\n};\n\nclass MockFailed_gethostbyname: public Mock_gethostbyname\n{\npublic:\n    MockFailed_gethostbyname():h_errnoReturn(HOST_NOT_FOUND) {}\n\n    int h_errnoReturn;\n    virtual hostent* call(const char* name) {\n        h_errno=h_errnoReturn;\n        return 0;\n    }\n};\n\n// *****************************************************************************\n// calloc\n\nclass Mock_calloc: public Mock\n{\npublic:\n    Mock_calloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {\n        mock_=this;\n    }\n    virtual ~Mock_calloc() {mock_=0;}\n\n    int errnoOnFailure;\n    int callsBeforeFailure;\n    int counter;\n    virtual void* call(size_t p1, size_t p2);\n\n    static Mock_calloc* mock_;\n};\n\n// *****************************************************************************\n// realloc\n\nclass Mock_realloc: public Mock\n{\npublic:\n    Mock_realloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {\n        mock_=this;\n    }\n    virtual ~Mock_realloc() {mock_=0;}\n\n    int errnoOnFailure;\n    int callsBeforeFailure;\n    int counter;\n    virtual void* call(void* p, size_t s);\n\n    static Mock_realloc* mock_;\n};\n\n// *****************************************************************************\n// random\n\nclass Mock_random: public Mock\n{\npublic:\n    Mock_random():currentIdx(0) {mock_=this;}\n    virtual ~Mock_random() {mock_=0;}\n\n    int currentIdx;\n    std::vector<int> randomReturns;\n    virtual int call();\n    void setSeed(unsigned long){currentIdx=0;}\n\n    static Mock_random* mock_;\n};\n\n// *****************************************************************************\n// no-op free; keeps track of all deallocation requests\nclass Mock_free_noop: public Mock\n{\n    Mutex mx;\n    std::vector<void*> requested;\npublic:\n    Mock_free_noop():nested(0),callCounter(0){mock_=this;}\n    virtual ~Mock_free_noop(){\n        mock_=0;\n        freeRequested();\n    }\n    \n    int nested;\n    int callCounter;\n    virtual void call(void* p);\n    void freeRequested();\n    void disable(){mock_=0;}\n    // returns number of times the pointer was freed\n    int getFreeCount(void*);\n    bool isFreed(void*);\n    \n    static Mock_free_noop* mock_;\n};\n\n// *****************************************************************************\n// socket and related system calls\n\nclass Mock_socket: public Mock\n{\npublic:\n    static const int FD=63;\n    Mock_socket():socketReturns(FD),closeReturns(0),getsocketoptReturns(0),\n        optvalSO_ERROR(0),\n        setsockoptReturns(0),connectReturns(0),connectErrno(0),\n        sendErrno(0),recvErrno(0)\n    {\n        mock_=this;\n    }\n    virtual ~Mock_socket(){mock_=0;}\n\n    int socketReturns;\n    virtual int callSocket(int domain, int type, int protocol){\n        return socketReturns;\n    }\n    int closeReturns;\n    virtual int callClose(int fd){\n        return closeReturns;\n    }\n    int getsocketoptReturns;\n    int optvalSO_ERROR;\n    virtual int callGet(int s,int level,int optname,void *optval,socklen_t *len){\n        if(level==SOL_SOCKET && optname==SO_ERROR){\n            setSO_ERROR(optval,*len);\n        }\n        return getsocketoptReturns;\n    }\n    virtual void setSO_ERROR(void *optval,socklen_t len){\n        memcpy(optval,&optvalSO_ERROR,len);\n    }\n    \n    int setsockoptReturns;\n    virtual int callSet(int s,int level,int optname,const void *optval,socklen_t len){\n        return setsockoptReturns;\n    }\n    int connectReturns;\n    int connectErrno;\n    virtual int callConnect(int s,const struct sockaddr *addr,socklen_t len){\n        errno=connectErrno;\n        return connectReturns;\n    }\n    \n    virtual void notifyBufferSent(const std::string& buffer){}\n    \n    int sendErrno;\n    std::string sendBuffer;\n    virtual ssize_t callSend(int s,const void *buf,size_t len,int flags){\n        if(sendErrno!=0){\n            errno=sendErrno;\n            return -1;\n        }\n        // first call to send() is always the length of the buffer to follow\n        bool sendingLength=sendBuffer.size()==0;\n        // overwrite the length bytes\n        sendBuffer.assign((const char*)buf,len);\n        if(!sendingLength){\n            notifyBufferSent(sendBuffer);\n            sendBuffer.erase();\n        }\n        return len;\n    }\n\n    int recvErrno;\n    std::string recvReturnBuffer;\n    virtual ssize_t callRecv(int s,void *buf,size_t len,int flags){\n        if(recvErrno!=0){\n            errno=recvErrno;\n            return -1;\n        }\n        int k=std::min(len,recvReturnBuffer.length());\n        if(k==0)\n            return 0;\n        memcpy(buf,recvReturnBuffer.data(),k);\n        recvReturnBuffer.erase(0,k);\n        return k;\n    }\n    virtual bool hasMoreRecv() const{\n        return recvReturnBuffer.size()!=0;\n    }\n    static Mock_socket* mock_;\n};\n\n// *****************************************************************************\n// fcntl\nclass Mock_fcntl: public Mock\n{\npublic:\n    Mock_fcntl():callReturns(0),trapFD(-1){mock_=this;}\n    ~Mock_fcntl(){mock_=0;}\n    \n    int callReturns;\n    int trapFD;\n    virtual int call(int fd, int cmd, void* arg){\n        if(trapFD==-1)\n            return LIBC_SYMBOLS.fcntl(fd,cmd,arg);\n        return callReturns;\n    }\n\n    static Mock_fcntl* mock_;\n};\n\n// *****************************************************************************\n// select\nclass Mock_select: public Mock\n{\npublic:\n    Mock_select(Mock_socket* s,int fd):sock(s),\n        callReturns(0),myFD(fd),timeout(50)\n    {\n        mock_=this;\n    }\n    ~Mock_select(){mock_=0;}\n    \n    Mock_socket* sock;\n    int callReturns;\n    int myFD;\n    int timeout; //in millis\n    virtual int call(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *tv){\n        bool isWritableRequested=(wfds && FD_ISSET(myFD,wfds));\n        if(rfds) FD_CLR(myFD,rfds);\n        if(wfds) FD_CLR(myFD,wfds);\n        // this timeout is only to prevent a tight loop\n        timeval myTimeout={0,0};\n        if(!isWritableRequested && !isFDReadable()){\n            myTimeout.tv_sec=timeout/1000;\n            myTimeout.tv_usec=(timeout%1000)*1000;\n        }\n        LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,&myTimeout);\n        // myFD is always writable\n        if(isWritableRequested) FD_SET(myFD,wfds);\n        // myFD is only readable if the socket has anything to read\n        if(isFDReadable() && rfds) FD_SET(myFD,rfds);\n        return callReturns;\n    }\n\n    virtual bool isFDReadable() const {\n        return sock->hasMoreRecv();\n    }\n    \n    static Mock_select* mock_;\n};\n\n// *****************************************************************************\n// poll\n// the last element of the pollfd array is expected to be test FD\nclass Mock_poll: public Mock\n{\npublic:\n    Mock_poll(Mock_socket* s,int fd):sock(s),\n        callReturns(1),myFD(fd),timeout(50)\n    {\n        mock_=this;\n    }\n    ~Mock_poll(){mock_=0;}\n    \n    Mock_socket* sock;\n    int callReturns;\n    int myFD;\n    int timeout; //in millis\n    virtual int call(struct pollfd *fds, POLL_NFDS_TYPE nfds, int to) {\n        pollfd* myPoll=0;\n        if(fds[nfds-1].fd==myFD)\n            myPoll=&fds[nfds-1];\n        bool isWritableRequested=false;\n        if(myPoll!=0){\n            isWritableRequested=myPoll->events&POLLOUT;\n            nfds--;\n        }\n        LIBC_SYMBOLS.poll(fds,nfds,(!isWritableRequested&&!isFDReadable())?timeout:0);\n        if(myPoll!=0){\n            // myFD is always writable if requested\n            myPoll->revents=isWritableRequested?POLLOUT:0;\n            // myFD is only readable if the socket has anything to read\n            myPoll->revents|=isFDReadable()?POLLIN:0;\n        }\n        return callReturns;\n    }\n\n    virtual bool isFDReadable() const {\n        return sock->hasMoreRecv();\n    }\n    \n    static Mock_poll* mock_;\n};\n\n// *****************************************************************************\n// gettimeofday\nclass Mock_gettimeofday: public Mock\n{\npublic:\n    Mock_gettimeofday(){\n        LIBC_SYMBOLS.gettimeofday(&tv,0);\n        mock_=this;\n    }\n    Mock_gettimeofday(const Mock_gettimeofday& other):tv(other.tv){}\n    Mock_gettimeofday(int32_t sec,int32_t usec){\n        tv.tv_sec=sec;\n        tv.tv_usec=usec;\n    }\n    ~Mock_gettimeofday(){mock_=0;}\n    \n    timeval tv;\n    virtual int call(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){\n        *tp=tv;\n        return 0;\n    }\n    operator timeval() const{\n        return tv;\n    }\n    // advance secs\n    virtual void tick(int howmuch=1){tv.tv_sec+=howmuch;}\n    // advance milliseconds\n    // can move the clock forward as well as backward by providing a negative\n    // number\n    virtual void millitick(int howmuch=1){\n        int ms=tv.tv_usec/1000+howmuch;\n        tv.tv_sec+=ms/1000;\n        // going backward?\n        if(ms<0){\n            ms=1000-(-ms%1000); //wrap millis around\n        }\n        tv.tv_usec=(ms%1000)*1000;\n    }\n    virtual void tick(const timeval& howmuch){\n        // add milliseconds (discarding microsecond portion)\n        long ms=tv.tv_usec/1000+howmuch.tv_usec/1000;\n        tv.tv_sec+=howmuch.tv_sec+ms/1000;\n        tv.tv_usec=(ms%1000)*1000;\n    }\n    static Mock_gettimeofday* mock_;\n};\n\n// discard microseconds!\ninline bool operator==(const timeval& lhs, const timeval& rhs){\n    return rhs.tv_sec==lhs.tv_sec && rhs.tv_usec/1000==lhs.tv_usec/1000;\n}\n\n// simplistic implementation: no normalization, assume lhs >= rhs,\n// discarding microseconds\ninline timeval operator-(const timeval& lhs, const timeval& rhs){\n    timeval res;\n    res.tv_sec=lhs.tv_sec-rhs.tv_sec;\n    res.tv_usec=(lhs.tv_usec/1000-rhs.tv_usec/1000)*1000;\n    if(res.tv_usec<0){\n        res.tv_sec--;\n        res.tv_usec=1000000+res.tv_usec%1000000; // wrap the millis around\n    }\n    return res;\n}\n\ninline int32_t toMilliseconds(const timeval& tv){\n    return tv.tv_sec*1000+tv.tv_usec/1000;    \n}\n\n#endif /*LIBCMOCKS_H_*/\n"
  },
  {
    "path": "src/c/tests/LibCSymTable.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"LibCSymTable.h\" \n\n#define LOAD_SYM(sym) \\\n    sym=(sym##_sig)dlsym(handle,#sym); \\\n    assert(\"Unable to load \"#sym\" from libc\"&&sym)      \n    \n\nLibCSymTable& LibCSymTable::instance(){\n    static LibCSymTable tbl;\n    return tbl;\n}\n\n//******************************************************************************\n// preload original libc symbols\nLibCSymTable::LibCSymTable()\n{\n    void* handle=getHandle();\n    LOAD_SYM(gethostbyname);\n    LOAD_SYM(calloc);\n    LOAD_SYM(realloc);\n    LOAD_SYM(free);\n    LOAD_SYM(random);\n    LOAD_SYM(srandom);\n    LOAD_SYM(printf);\n    LOAD_SYM(socket);\n    LOAD_SYM(close);\n    LOAD_SYM(getsockopt);\n    LOAD_SYM(setsockopt);\n    LOAD_SYM(fcntl);\n    LOAD_SYM(connect);\n    LOAD_SYM(send);\n    LOAD_SYM(recv);\n    LOAD_SYM(select);\n    LOAD_SYM(poll);\n    LOAD_SYM(gettimeofday);\n#ifdef THREADED\n    LOAD_SYM(pthread_create);\n    LOAD_SYM(pthread_detach);\n    LOAD_SYM(pthread_cond_broadcast);\n    LOAD_SYM(pthread_cond_destroy);\n    LOAD_SYM(pthread_cond_init);\n    LOAD_SYM(pthread_cond_signal);\n    LOAD_SYM(pthread_cond_timedwait);\n    LOAD_SYM(pthread_cond_wait);\n    LOAD_SYM(pthread_join);\n    LOAD_SYM(pthread_mutex_destroy);\n    LOAD_SYM(pthread_mutex_init);\n    LOAD_SYM(pthread_mutex_lock);\n    LOAD_SYM(pthread_mutex_trylock);\n    LOAD_SYM(pthread_mutex_unlock);\n#endif\n}\n\nvoid* LibCSymTable::getHandle(){\n    static void* handle=0;\n    if(!handle){\n#ifdef __CYGWIN__\n        handle=dlopen(\"cygwin1.dll\",RTLD_LAZY);\n        assert(\"Unable to dlopen global sym table\"&&handle);\n#else\n        handle=RTLD_NEXT;\n#endif\n    }\n    return handle;\n}\n"
  },
  {
    "path": "src/c/tests/LibCSymTable.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef LIBCSYMTABLE_H_\n#define LIBCSYMTABLE_H_\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#include <stddef.h>\n#include <dlfcn.h>\n#include <cassert>\n#include <poll.h>\n\n#ifdef THREADED\n#include <pthread.h>\n#endif\n\n#include \"config.h\"\n\n// TODO: move all these macros to config.h (generated by autoconf) \n#ifdef __CYGWIN__\n#if (CYGWIN_VERSION_DLL_MAJOR < 1007)\n#define RANDOM_RET_TYPE int\n#else\n#define RANDOM_RET_TYPE long int\n#endif\n#define GETTIMEOFDAY_ARG2_TYPE void*\n#else\n#define RANDOM_RET_TYPE long int\n#define GETTIMEOFDAY_ARG2_TYPE struct timezone*\n#endif\n\n#define DECLARE_SYM(ret,sym,sig) \\\n    typedef ret (*sym##_sig)sig; \\\n    static sym##_sig preload_##sym () { \\\n        static sym##_sig ptr=0;\\\n        if(!ptr){ void* h=getHandle(); ptr=(sym##_sig)dlsym(h,#sym); } \\\n        assert(\"Unable to load \"#sym\" from libc\"&&ptr); \\\n        return ptr; \\\n    } \\\n    sym##_sig sym\n\n#define LIBC_SYMBOLS LibCSymTable::instance()\n\n//******************************************************************************\n// preload original libc symbols\nstruct LibCSymTable\n{\n    DECLARE_SYM(hostent*,gethostbyname,(const char*));\n    DECLARE_SYM(void*,calloc,(size_t, size_t));\n    DECLARE_SYM(void*,realloc,(void*, size_t));\n    DECLARE_SYM(void,free,(void*));\n    DECLARE_SYM(RANDOM_RET_TYPE,random,(void));\n    DECLARE_SYM(void,srandom,(unsigned long));\n    DECLARE_SYM(int,printf,(const char*, ...));\n    DECLARE_SYM(int,socket,(int,int,int));\n    DECLARE_SYM(int,close,(int));\n    DECLARE_SYM(int,getsockopt,(int,int,int,void*,socklen_t*));\n    DECLARE_SYM(int,setsockopt,(int,int,int,const void*,socklen_t));\n    DECLARE_SYM(int,fcntl,(int,int,...));\n    DECLARE_SYM(int,connect,(int,const struct sockaddr*,socklen_t));\n    DECLARE_SYM(ssize_t,send,(int,const void*,size_t,int));\n    DECLARE_SYM(ssize_t,recv,(int,const void*,size_t,int));\n    DECLARE_SYM(int,select,(int,fd_set*,fd_set*,fd_set*,struct timeval*));\n    DECLARE_SYM(int,poll,(struct pollfd*,POLL_NFDS_TYPE,int));\n    DECLARE_SYM(int,gettimeofday,(struct timeval*,GETTIMEOFDAY_ARG2_TYPE));\n#ifdef THREADED\n    DECLARE_SYM(int,pthread_create,(pthread_t *, const pthread_attr_t *,\n                void *(*)(void *), void *));\n    DECLARE_SYM(int,pthread_detach,(pthread_t));\n    DECLARE_SYM(int,pthread_cond_broadcast,(pthread_cond_t *));\n    DECLARE_SYM(int,pthread_cond_destroy,(pthread_cond_t *));\n    DECLARE_SYM(int,pthread_cond_init,(pthread_cond_t *, const pthread_condattr_t *));\n    DECLARE_SYM(int,pthread_cond_signal,(pthread_cond_t *));\n    DECLARE_SYM(int,pthread_cond_timedwait,(pthread_cond_t *,\n                    pthread_mutex_t *, const struct timespec *));\n    DECLARE_SYM(int,pthread_cond_wait,(pthread_cond_t *, pthread_mutex_t *));\n    DECLARE_SYM(int,pthread_join,(pthread_t, void **));\n    DECLARE_SYM(int,pthread_mutex_destroy,(pthread_mutex_t *));\n    DECLARE_SYM(int,pthread_mutex_init,(pthread_mutex_t *, const pthread_mutexattr_t *));\n    DECLARE_SYM(int,pthread_mutex_lock,(pthread_mutex_t *));\n    DECLARE_SYM(int,pthread_mutex_trylock,(pthread_mutex_t *));\n    DECLARE_SYM(int,pthread_mutex_unlock,(pthread_mutex_t *));\n#endif\n    LibCSymTable();\n    \n    static void* getHandle();\n    static LibCSymTable& instance();\n};\n\n#endif /*LIBCSYMTABLE_H_*/\n"
  },
  {
    "path": "src/c/tests/MocksBase.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cstdlib>\n#include <new>\n\n#include \"MocksBase.h\"\n#include \"LibCSymTable.h\"\n\n// *****************************************************************************\n// Mock base\nvoid* Mock::operator new(std::size_t s){\n    void* p=malloc(s);\n    if(!p)\n        throw std::bad_alloc();\n    return p;\n}\n\nvoid Mock::operator delete(void* p){\n    LIBC_SYMBOLS.free(p);\n}\n"
  },
  {
    "path": "src/c/tests/MocksBase.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef MOCKSBASE_H_\n#define MOCKSBASE_H_\n\n#include <cstddef>\n\n// *****************************************************************************\n// Mock base\n\nclass Mock\n{\npublic:\n    virtual ~Mock(){}\n\n    static void* operator new(std::size_t s);\n    static void operator delete(void* p);\n};\n\n#endif /*MOCKSBASE_H_*/\n"
  },
  {
    "path": "src/c/tests/PthreadMocks.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"PthreadMocks.h\"\n\nMockPthreadsBase* MockPthreadsBase::mock_=0;\n\n#undef USING_DUMA\n\n#ifndef USING_DUMA\nint pthread_cond_broadcast (pthread_cond_t *c){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_broadcast(c);\n    return MockPthreadsBase::mock_->pthread_cond_broadcast(c);\n}\nint pthread_cond_destroy (pthread_cond_t *c){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_destroy(c);\n    return MockPthreadsBase::mock_->pthread_cond_destroy(c);\n}\nint pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_init(c,a);\n    return MockPthreadsBase::mock_->pthread_cond_init(c,a);\n}\nint pthread_cond_signal (pthread_cond_t *c){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_signal(c);\n    return MockPthreadsBase::mock_->pthread_cond_signal(c);\n}\nint pthread_cond_timedwait (pthread_cond_t *c,\n                pthread_mutex_t *m, const struct timespec *t){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);\n    return MockPthreadsBase::mock_->pthread_cond_timedwait(c,m,t);\n}\nint pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *m){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_cond_wait(c,m);\n    return MockPthreadsBase::mock_->pthread_cond_wait(c,m);\n}\nint pthread_create (pthread_t *t, const pthread_attr_t *a,\n            void *(*f)(void *), void *d){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_create(t,a,f,d);\n    return MockPthreadsBase::mock_->pthread_create(t,a,f,d);\n}\nint pthread_detach(pthread_t t){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_detach(t);\n    return MockPthreadsBase::mock_->pthread_detach(t);    \n}\nint pthread_join (pthread_t t, void **r){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_join(t,r);\n    return MockPthreadsBase::mock_->pthread_join(t,r);\n}\nint pthread_mutex_destroy (pthread_mutex_t *m){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_mutex_destroy(m);\n    return MockPthreadsBase::mock_->pthread_mutex_destroy(m);\n}\nint pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_mutex_init(m,a);\n    return MockPthreadsBase::mock_->pthread_mutex_init(m,a);\n}\n\nDECLARE_WRAPPER(int,pthread_mutex_lock,(pthread_mutex_t *m)){\n    if(!MockPthreadsBase::mock_)\n        return CALL_REAL(pthread_mutex_lock,(m));\n    return MockPthreadsBase::mock_->pthread_mutex_lock(m);\n}\n\nint pthread_mutex_trylock (pthread_mutex_t *m){\n    if(!MockPthreadsBase::mock_)\n        return LIBC_SYMBOLS.pthread_mutex_trylock(m);\n    return MockPthreadsBase::mock_->pthread_mutex_trylock(m);\n}\n\nDECLARE_WRAPPER(int,pthread_mutex_unlock,(pthread_mutex_t *m)){\n    if(!MockPthreadsBase::mock_)\n        return CALL_REAL(pthread_mutex_unlock,(m));\n    return MockPthreadsBase::mock_->pthread_mutex_unlock(m);\n}\n#endif\n\nCheckedPthread::ThreadMap CheckedPthread::tmap_;\nCheckedPthread::MutexMap CheckedPthread::mmap_;\nCheckedPthread::CVMap CheckedPthread::cvmap_;\nMutex CheckedPthread::mx;\n"
  },
  {
    "path": "src/c/tests/PthreadMocks.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef PTHREADMOCKS_H_\n#define PTHREADMOCKS_H_\n\n#include <pthread.h>\n#include <string.h>\n#include <errno.h>\n\n#include \"src/zk_adaptor.h\"\n\n#include \"Util.h\"\n#include \"MocksBase.h\"\n#include \"LibCSymTable.h\"\n#include \"ThreadingUtil.h\"\n\n// an ABC for pthreads\nclass MockPthreadsBase: public Mock\n{\npublic:\n    MockPthreadsBase(){mock_=this;}\n    virtual ~MockPthreadsBase(){mock_=0;}\n    \n    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,\n            void *(*f)(void *), void *d) =0;\n    virtual int pthread_join(pthread_t t, void ** r) =0;\n    virtual int pthread_detach(pthread_t t) =0;\n    virtual int pthread_cond_broadcast(pthread_cond_t *c) =0;\n    virtual int pthread_cond_destroy(pthread_cond_t *c) =0;\n    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) =0;\n    virtual int pthread_cond_signal(pthread_cond_t *c) =0;\n    virtual int pthread_cond_timedwait(pthread_cond_t *c,\n            pthread_mutex_t *m, const struct timespec *t) =0;\n    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) =0;\n    virtual int pthread_mutex_destroy(pthread_mutex_t *m) =0;\n    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) =0;\n    virtual int pthread_mutex_lock(pthread_mutex_t *m) =0;\n    virtual int pthread_mutex_trylock(pthread_mutex_t *m) =0;\n    virtual int pthread_mutex_unlock(pthread_mutex_t *m) =0;\n    \n    static MockPthreadsBase* mock_;\n};\n\n// all pthread functions simply return an error code\n// and increment their invocation counter. No actual threads are spawned.\nclass MockPthreadsNull: public MockPthreadsBase\n{\npublic:\n    MockPthreadsNull():\n    pthread_createReturns(0),pthread_createCounter(0),\n    pthread_joinReturns(0),pthread_joinCounter(0),pthread_joinResultReturn(0),\n    pthread_detachReturns(0),pthread_detachCounter(0),\n    pthread_cond_broadcastReturns(0),pthread_cond_broadcastCounter(0),\n    pthread_cond_destroyReturns(0),pthread_cond_destroyCounter(0),\n    pthread_cond_initReturns(0),pthread_cond_initCounter(0),\n    pthread_cond_signalReturns(0),pthread_cond_signalCounter(0),\n    pthread_cond_timedwaitReturns(0),pthread_cond_timedwaitCounter(0),\n    pthread_cond_waitReturns(0),pthread_cond_waitCounter(0),\n    pthread_mutex_destroyReturns(0),pthread_mutex_destroyCounter(0),\n    pthread_mutex_initReturns(0),pthread_mutex_initCounter(0),\n    pthread_mutex_lockReturns(0),pthread_mutex_lockCounter(0),\n    pthread_mutex_trylockReturns(0),pthread_mutex_trylockCounter(0),\n    pthread_mutex_unlockReturns(0),pthread_mutex_unlockCounter(0)\n    {\n        memset(threads,0,sizeof(threads));\n    }\n    \n    short threads[512];\n    \n    int pthread_createReturns;\n    int pthread_createCounter;\n    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,\n            void *(*f)(void *), void *d){\n        char* p=(char*)&threads[pthread_createCounter++];\n        p[0]='i'; // mark as created\n        *t=(pthread_t)p;\n        return pthread_createReturns; \n    }\n    int pthread_joinReturns;\n    int pthread_joinCounter;\n    void* pthread_joinResultReturn;\n    virtual int pthread_join(pthread_t t, void ** r){\n        pthread_joinCounter++;\n        if(r!=0)\n            *r=pthread_joinResultReturn;\n        char* p=(char*)t;\n        p[0]='x';p[1]+=1;\n        return pthread_joinReturns; \n    }\n    int pthread_detachReturns;\n    int pthread_detachCounter;        \n    virtual int pthread_detach(pthread_t t){\n        pthread_detachCounter++;\n        char* p=(char*)t;\n        p[0]='x';p[1]+=1;        \n        return pthread_detachReturns;\n    }\n\n    template<class T>\n    static bool isInitialized(const T& t){\n        return ((char*)t)[0]=='i';\n    }\n    template<class T>\n    static bool isDestroyed(const T& t){\n        return ((char*)t)[0]=='x';\n    }\n    template<class T>\n    static int getDestroyCounter(const T& t){\n        return ((char*)t)[1];\n    }\n    template<class T>\n    static int getInvalidAccessCounter(const T& t){\n        return ((char*)t)[2];\n    }\n    int pthread_cond_broadcastReturns;\n    int pthread_cond_broadcastCounter;\n    virtual int pthread_cond_broadcast(pthread_cond_t *c){\n        pthread_cond_broadcastCounter++;\n        if(isDestroyed(c))((char*)c)[2]++;\n        return pthread_cond_broadcastReturns; \n    }\n    int pthread_cond_destroyReturns;\n    int pthread_cond_destroyCounter;\n    virtual int pthread_cond_destroy(pthread_cond_t *c){\n        pthread_cond_destroyCounter++;\n        char* p=(char*)c;\n        p[0]='x';p[1]+=1;\n        return pthread_cond_destroyReturns; \n    }\n    int pthread_cond_initReturns;\n    int pthread_cond_initCounter;\n    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){\n        pthread_cond_initCounter++;\n        char* p=(char*)c;\n        p[0]='i'; // mark as created\n        p[1]=0;   // destruction counter\n        p[2]=0;   // access after destruction counter\n        return pthread_cond_initReturns; \n    }\n    int pthread_cond_signalReturns;\n    int pthread_cond_signalCounter;\n    virtual int pthread_cond_signal(pthread_cond_t *c){\n        pthread_cond_signalCounter++;\n        if(isDestroyed(c))((char*)c)[2]++;\n        return pthread_cond_signalReturns; \n    }\n    int pthread_cond_timedwaitReturns;\n    int pthread_cond_timedwaitCounter;\n    virtual int pthread_cond_timedwait(pthread_cond_t *c,\n            pthread_mutex_t *m, const struct timespec *t){\n        pthread_cond_timedwaitCounter++;\n        if(isDestroyed(c))((char*)c)[2]++;\n        return pthread_cond_timedwaitReturns; \n    }\n    int pthread_cond_waitReturns;\n    int pthread_cond_waitCounter;\n    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){\n        pthread_cond_waitCounter++;\n        if(isDestroyed(c))((char*)c)[2]++;\n        return pthread_cond_waitReturns; \n    }\n    int pthread_mutex_destroyReturns;\n    int pthread_mutex_destroyCounter;\n    virtual int pthread_mutex_destroy(pthread_mutex_t *m){\n        pthread_mutex_destroyCounter++;\n        char* p=(char*)m;\n        p[0]='x';p[1]+=1;\n        return pthread_mutex_destroyReturns; \n    }\n    int pthread_mutex_initReturns;\n    int pthread_mutex_initCounter;\n    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){\n        pthread_mutex_initCounter++;\n        char* p=(char*)m;\n        p[0]='i'; // mark as created\n        p[1]=0;   // destruction counter\n        p[2]=0;   // access after destruction counter\n        return pthread_mutex_initReturns; \n    }\n    int pthread_mutex_lockReturns;\n    int pthread_mutex_lockCounter;\n    virtual int pthread_mutex_lock(pthread_mutex_t *m){\n        pthread_mutex_lockCounter++;\n        if(isDestroyed(m))((char*)m)[2]++;\n        return pthread_mutex_lockReturns; \n    }\n    int pthread_mutex_trylockReturns;\n    int pthread_mutex_trylockCounter;\n    virtual int pthread_mutex_trylock(pthread_mutex_t *m){\n        pthread_mutex_trylockCounter++;\n        if(isDestroyed(m))((char*)m)[2]++;\n        return pthread_mutex_trylockReturns; \n    }\n    int pthread_mutex_unlockReturns;\n    int pthread_mutex_unlockCounter;\n    virtual int pthread_mutex_unlock(pthread_mutex_t *m){\n        pthread_mutex_unlockCounter++;\n        if(isDestroyed(m))((char*)m)[2]++;\n        return pthread_mutex_unlockReturns; \n    }\n};\n\n// simulates the way zookeeper threads make use of api_prolog/epilog and\n// \nclass MockPthreadZKNull: public MockPthreadsNull\n{\n    typedef std::map<pthread_t,zhandle_t*> Map;\n    Map map_;\npublic:\n    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,\n            void *(*f)(void *), void *d){\n        int ret=MockPthreadsNull::pthread_create(t,a,f,d);\n        zhandle_t* zh=(zhandle_t*)d;\n        adaptor_threads* ad=(adaptor_threads*)zh->adaptor_priv;\n        api_prolog(zh);\n        ad->threadsToWait--;\n        putValue(map_,*t,zh);\n        return ret;\n    }\n    virtual int pthread_join(pthread_t t, void ** r){\n        zhandle_t* zh=0;\n        if(getValue(map_,t,zh))\n            api_epilog(zh,0);\n        return MockPthreadsNull::pthread_join(t,r);\n    }\n};\n\nstruct ThreadInfo{\n    typedef enum {RUNNING,TERMINATED} ThreadState;\n    \n    ThreadInfo():\n        destructionCounter_(0),invalidAccessCounter_(0),state_(RUNNING)\n    {\n    }\n    \n    ThreadInfo& incDestroyed() {\n        destructionCounter_++;\n        return *this;\n    }\n    ThreadInfo& incInvalidAccess(){\n        invalidAccessCounter_++;\n        return *this;\n    }\n    ThreadInfo& setTerminated(){\n        state_=TERMINATED;\n        return *this;\n    }\n    int destructionCounter_;\n    int invalidAccessCounter_;\n    ThreadState state_;\n};\n\nclass CheckedPthread: public MockPthreadsBase\n{\n    // first => destruction counter\n    // second => invalid access counter\n    //typedef std::pair<int,int> Entry;\n    typedef ThreadInfo Entry;\n    typedef std::map<pthread_t,Entry> ThreadMap;\n    static ThreadMap tmap_;\n    static ThreadMap& getMap(const TypeOp<pthread_t>::BareT&){return tmap_;}\n    typedef std::map<pthread_mutex_t*,Entry> MutexMap;\n    static MutexMap mmap_;\n    static MutexMap& getMap(const TypeOp<pthread_mutex_t>::BareT&){return mmap_;}\n    typedef std::map<pthread_cond_t*,Entry> CVMap;\n    static CVMap cvmap_;\n    static CVMap& getMap(const TypeOp<pthread_cond_t>::BareT&){return cvmap_;}\n    \n    static Mutex mx;\n    \n    template<class T>\n    static void markDestroyed(T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        if(getValue(getMap(Type()),t,e)){\n            putValue(getMap(Type()),t,Entry(e).incDestroyed());\n        }else{\n            putValue(getMap(Type()),t,Entry().incDestroyed());\n        }\n    }\n    template<class T>\n    static void markCreated(T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        if(!getValue(getMap(Type()),t,e))\n            putValue(getMap(Type()),t,Entry());\n    }\n    template<class T>\n    static void checkAccessed(T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        if(getValue(getMap(Type()),t,e) && e.destructionCounter_>0)\n            putValue(getMap(Type()),t,Entry(e).incInvalidAccess());\n    }\n    static void setTerminated(pthread_t t){\n        Entry e;\n        synchronized(mx);\n        if(getValue(tmap_,t,e))\n            putValue(tmap_,t,Entry(e).setTerminated());\n    }\npublic:\n    bool verbose;\n    CheckedPthread():verbose(false){\n        tmap_.clear();\n        mmap_.clear();\n        cvmap_.clear();\n        mx.release();\n    }\n    template <class T>\n    static bool isInitialized(const T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        return getValue(getMap(Type()),t,e) && e.destructionCounter_==0;\n    }\n    template <class T>\n    static bool isDestroyed(const T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        return getValue(getMap(Type()),t,e) && e.destructionCounter_>0;\n    }\n    static bool isTerminated(pthread_t t){\n        Entry e;\n        synchronized(mx);\n        return getValue(tmap_,t,e) && e.state_==ThreadInfo::TERMINATED;        \n    }\n    template <class T>\n    static int getDestroyCounter(const T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        return getValue(getMap(Type()),t,e)?e.destructionCounter_:-1;\n    }\n    template<class T>\n    static int getInvalidAccessCounter(const T& t){\n        typedef typename TypeOp<T>::BareT Type;\n        Entry e;\n        synchronized(mx);\n        return getValue(getMap(Type()),t,e)?e.invalidAccessCounter_:-1;\n    }\n\n    struct ThreadContext{\n        typedef void *(*ThreadFunc)(void *);\n        \n        ThreadContext(ThreadFunc func,void* param):func_(func),param_(param){}\n        ThreadFunc func_;\n        void* param_;        \n    };\n    static void* threadFuncWrapper(void* v){\n        ThreadContext* ctx=(ThreadContext*)v;\n        pthread_t t=pthread_self();\n        markCreated(t);\n        void* res=ctx->func_(ctx->param_);\n        setTerminated(pthread_self());\n        delete ctx;\n        return res;\n    }\n    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,\n            void *(*f)(void *), void *d)\n    {\n        int ret=LIBC_SYMBOLS.pthread_create(t,a,threadFuncWrapper,\n                new ThreadContext(f,d));\n        if(verbose)\n            TEST_TRACE((\"thread created %p\",*t));\n        return ret;\n    }\n    virtual int pthread_join(pthread_t t, void ** r){\n        if(verbose) TEST_TRACE((\"thread joined %p\",t));\n        int ret=LIBC_SYMBOLS.pthread_join(t,r);\n        if(ret==0)\n            markDestroyed(t);\n        return ret;\n    }\n    virtual int pthread_detach(pthread_t t){\n        if(verbose) TEST_TRACE((\"thread detached %p\",t));\n        int ret=LIBC_SYMBOLS.pthread_detach(t);\n        if(ret==0)\n            markDestroyed(t);\n        return ret;\n    }\n    virtual int pthread_cond_broadcast(pthread_cond_t *c){\n        checkAccessed(c);\n        return LIBC_SYMBOLS.pthread_cond_broadcast(c);\n    }\n    virtual int pthread_cond_destroy(pthread_cond_t *c){\n        markDestroyed(c);\n        return LIBC_SYMBOLS.pthread_cond_destroy(c);\n    }\n    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){\n        markCreated(c);\n        return LIBC_SYMBOLS.pthread_cond_init(c,a);\n    }\n    virtual int pthread_cond_signal(pthread_cond_t *c){\n        checkAccessed(c);\n        return LIBC_SYMBOLS.pthread_cond_signal(c);\n    }\n    virtual int pthread_cond_timedwait(pthread_cond_t *c,\n            pthread_mutex_t *m, const struct timespec *t){\n        checkAccessed(c);\n        return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);\n    }\n    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){\n        checkAccessed(c);\n        return LIBC_SYMBOLS.pthread_cond_wait(c,m);\n    }\n    virtual int pthread_mutex_destroy(pthread_mutex_t *m){\n        markDestroyed(m);\n        return LIBC_SYMBOLS.pthread_mutex_destroy(m);\n    }\n    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){\n        markCreated(m);\n        return LIBC_SYMBOLS.pthread_mutex_init(m,a);\n    }\n    virtual int pthread_mutex_lock(pthread_mutex_t *m){\n        checkAccessed(m);\n        return LIBC_SYMBOLS.pthread_mutex_lock(m);\n    }\n    virtual int pthread_mutex_trylock(pthread_mutex_t *m){\n        checkAccessed(m);\n        return LIBC_SYMBOLS.pthread_mutex_trylock(m);\n    }\n    virtual int pthread_mutex_unlock(pthread_mutex_t *m){\n        checkAccessed(m);\n        return LIBC_SYMBOLS.pthread_mutex_unlock(m);\n    }    \n};\n\n#endif /*PTHREADMOCKS_H_*/\n\n"
  },
  {
    "path": "src/c/tests/TestClient.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include \"CppAssertHelper.h\"\n\n#include <signal.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/select.h>\n\n#include \"CollectionUtil.h\"\n#include \"ThreadingUtil.h\"\n\nusing namespace Util;\n\n#include \"Vector.h\"\nusing namespace std;\n\n#include <cstring>\n#include <list>\n\n#include <zookeeper.h>\n#include <errno.h>\n#include <recordio.h>\n#include \"Util.h\"\n\nstruct buff_struct_2 {\n    int32_t len;\n    int32_t off;\n    char *buffer;\n};\n\nstatic int Stat_eq(struct Stat* a, struct Stat* b)\n{\n    if (a->czxid != b->czxid) return 0;\n    if (a->mzxid != b->mzxid) return 0;\n    if (a->ctime != b->ctime) return 0;\n    if (a->mtime != b->mtime) return 0;\n    if (a->version != b->version) return 0;\n    if (a->cversion != b->cversion) return 0;\n    if (a->aversion != b->aversion) return 0;\n    if (a->ephemeralOwner != b->ephemeralOwner) return 0;\n    if (a->dataLength != b->dataLength) return 0;\n    if (a->numChildren != b->numChildren) return 0;\n    if (a->pzxid != b->pzxid) return 0;\n    return 1;\n}\n#ifdef THREADED\n    static void yield(zhandle_t *zh, int i)\n    {\n        sleep(i);\n    }\n#else\n    static void yield(zhandle_t *zh, int seconds)\n    {\n        int fd;\n        int interest;\n        int events;\n        struct timeval tv;\n        int rc;\n        time_t expires = time(0) + seconds;\n        time_t timeLeft = seconds;\n        fd_set rfds, wfds, efds;\n        FD_ZERO(&rfds);\n        FD_ZERO(&wfds);\n        FD_ZERO(&efds);\n\n        while(timeLeft >= 0) {\n            zookeeper_interest(zh, &fd, &interest, &tv);\n            if (fd != -1) {\n                if (interest&ZOOKEEPER_READ) {\n                    FD_SET(fd, &rfds);\n                } else {\n                    FD_CLR(fd, &rfds);\n                }\n                if (interest&ZOOKEEPER_WRITE) {\n                    FD_SET(fd, &wfds);\n                } else {\n                    FD_CLR(fd, &wfds);\n                }\n            } else {\n                fd = 0;\n            }\n            FD_SET(0, &rfds);\n            if (tv.tv_sec > timeLeft) {\n                tv.tv_sec = timeLeft;\n            }\n            rc = select(fd+1, &rfds, &wfds, &efds, &tv);\n            timeLeft = expires - time(0);\n            events = 0;\n            if (FD_ISSET(fd, &rfds)) {\n                events |= ZOOKEEPER_READ;\n            }\n            if (FD_ISSET(fd, &wfds)) {\n                events |= ZOOKEEPER_WRITE;\n            }\n            zookeeper_process(zh, events);\n        }\n    }\n#endif\n\ntypedef struct evt {\n    string path;\n    int type;\n} evt_t;\n\ntypedef struct watchCtx {\nprivate:\n    list<evt_t> events;\n    watchCtx(const watchCtx&);\n    watchCtx& operator=(const watchCtx&);\npublic:\n    bool connected;\n    zhandle_t *zh;\n    Mutex mutex;\n\n    watchCtx() {\n        connected = false;\n        zh = 0;\n    }\n    ~watchCtx() {\n        if (zh) {\n            zookeeper_close(zh);\n            zh = 0;\n        }\n    }\n\n    evt_t getEvent() {\n        evt_t evt;\n        mutex.acquire();\n        CPPUNIT_ASSERT( events.size() > 0);\n        evt = events.front();\n        events.pop_front();\n        mutex.release();\n        return evt;\n    }\n\n    int countEvents() {\n        int count;\n        mutex.acquire();\n        count = events.size();\n        mutex.release();\n        return count;\n    }\n\n    void putEvent(evt_t evt) {\n        mutex.acquire();\n        events.push_back(evt);\n        mutex.release();\n    }\n\n    bool waitForConnected(zhandle_t *zh) {\n        time_t expires = time(0) + 10;\n        while(!connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return connected;\n    }\n    bool waitForDisconnected(zhandle_t *zh) {\n        time_t expires = time(0) + 15;\n        while(connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return !connected;\n    }\n} watchctx_t;\n\nclass Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_simpleSystem);\n    CPPUNIT_TEST(testAsyncWatcherAutoReset);\n    CPPUNIT_TEST(testDeserializeString);\n    CPPUNIT_TEST(testFirstServerDown);\n#ifdef THREADED\n    CPPUNIT_TEST(testNullData);\n#ifdef ZOO_IPV6_ENABLED\n    CPPUNIT_TEST(testIPV6);\n#endif\n    CPPUNIT_TEST(testPath);\n    CPPUNIT_TEST(testPathValidation);\n    CPPUNIT_TEST(testPing);\n    CPPUNIT_TEST(testAcl);\n    CPPUNIT_TEST(testChroot);\n    CPPUNIT_TEST(testAuth);\n    CPPUNIT_TEST(testHangingClient);\n    CPPUNIT_TEST(testWatcherAutoResetWithGlobal);\n    CPPUNIT_TEST(testWatcherAutoResetWithLocal);\n    CPPUNIT_TEST(testGetChildren2);\n#endif\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int type, int state, const char *path,void*v){\n        watchctx_t *ctx = (watchctx_t*)v;\n\n        if (state == ZOO_CONNECTED_STATE) {\n            ctx->connected = true;\n        } else {\n            ctx->connected = false;\n        }\n        if (type != ZOO_SESSION_EVENT) {\n            evt_t evt;\n            evt.path = path;\n            evt.type = type;\n            ctx->putEvent(evt);\n        }\n    }\n\n    static const char hostPorts[];\n\n    const char *getHostPorts() {\n        return hostPorts;\n    }\n    \n    zhandle_t *createClient(watchctx_t *ctx) {\n        return createClient(hostPorts, ctx);\n    }\n\n    zhandle_t *createClient(const char *hp, watchctx_t *ctx) {\n        zhandle_t *zk = zookeeper_init(hp, watcher, 10000, 0, ctx, 0);\n        ctx->zh = zk;\n        sleep(1);\n        return zk;\n    }\n    \n    zhandle_t *createchClient(watchctx_t *ctx, const char* chroot) {\n        zhandle_t *zk = zookeeper_init(chroot, watcher, 10000, 0, ctx, 0);\n        ctx->zh = zk;\n        sleep(1);\n        return zk;\n    }\n        \n    FILE *logfile;\npublic:\n\n    Zookeeper_simpleSystem() {\n      logfile = openlogfile(\"Zookeeper_simpleSystem\");\n    }\n\n    ~Zookeeper_simpleSystem() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n    }\n\n\n    void startServer() {\n        char cmd[1024];\n        sprintf(cmd, \"%s start %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n\n    void stopServer() {\n        char cmd[1024];\n        sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n\n    void tearDown()\n    {\n    }\n    \n    /** have a callback in the default watcher **/\n    static void default_zoo_watcher(zhandle_t *zzh, int type, int state, const char *path, void *context){\n        int zrc = 0;\n        struct String_vector str_vec = {0, NULL};\n        zrc = zoo_wget_children(zzh, \"/mytest\", default_zoo_watcher, NULL, &str_vec);\n    }\n\n    /** ZOOKEEPER-1057 This checks that the client connects to the second server when the first is not reachable **/\n    void testFirstServerDown() {\n        watchctx_t ctx;\n\n        zoo_deterministic_conn_order(true);\n\n        zhandle_t* zk = createClient(\"127.0.0.1:22182,127.0.0.1:22181\", &ctx);\n        CPPUNIT_ASSERT(zk != 0);\n        CPPUNIT_ASSERT(ctx.waitForConnected(zk));\n    }\n    \n    /** this checks for a deadlock in calling zookeeper_close and calls from a default watcher that might get triggered just when zookeeper_close() is in progress **/\n    void testHangingClient() {\n        int zrc = 0;\n        char buff[10] = \"testall\";\n        char path[512];\n        watchctx_t *ctx;\n        struct String_vector str_vec = {0, NULL};\n        zhandle_t *zh = zookeeper_init(hostPorts, NULL, 10000, 0, ctx, 0);\n        sleep(1);\n        zrc = zoo_create(zh, \"/mytest\", buff, 10, &ZOO_OPEN_ACL_UNSAFE, 0, path, 512);\n        zrc = zoo_wget_children(zh, \"/mytest\", default_zoo_watcher, NULL, &str_vec);\n        zrc = zoo_create(zh, \"/mytest/test1\", buff, 10, &ZOO_OPEN_ACL_UNSAFE, 0, path, 512);\n        zrc = zoo_wget_children(zh, \"/mytest\", default_zoo_watcher, NULL, &str_vec);\n        zrc = zoo_delete(zh, \"/mytest/test1\", -1);\n        zookeeper_close(zh);\n    }\n    \n\n    void testPing()\n    {\n        watchctx_t ctxIdle;\n        watchctx_t ctxWC;\n        zhandle_t *zkIdle = createClient(&ctxIdle);\n        zhandle_t *zkWatchCreator = createClient(&ctxWC);\n\n        CPPUNIT_ASSERT(zkIdle);\n        CPPUNIT_ASSERT(zkWatchCreator);\n\n        char path[80];\n        sprintf(path, \"/testping\");\n        int rc = zoo_create(zkWatchCreator, path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        for(int i = 0; i < 30; i++) {\n            sprintf(path, \"/testping/%i\", i);\n            rc = zoo_create(zkWatchCreator, path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        for(int i = 0; i < 30; i++) {\n            sprintf(path, \"/testping/%i\", i);\n            struct Stat stat;\n            rc = zoo_exists(zkIdle, path, 1, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        for(int i = 0; i < 30; i++) {\n            sprintf(path, \"/testping/%i\", i);\n            usleep(500000);\n            rc = zoo_delete(zkWatchCreator, path, -1);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n        struct Stat stat;\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, zoo_exists(zkIdle, \"/testping/0\", 0, &stat));\n    }\n\n    bool waitForEvent(zhandle_t *zh, watchctx_t *ctx, int seconds) {\n        time_t expires = time(0) + seconds;\n        while(ctx->countEvents() == 0 && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return ctx->countEvents() > 0;\n    }\n\n#define COUNT 100\n\n    static zhandle_t *async_zk;\n    static volatile int count;\n    static const char* hp_chroot;\n\n    static void statCompletion(int rc, const struct Stat *stat, const void *data) {\n        int tmp = (int) (long) data;\n        CPPUNIT_ASSERT_EQUAL(tmp, rc);\n    }\n\n    static void stringCompletion(int rc, const char *value, const void *data) {\n        char *path = (char*)data;\n\n        if (rc == ZCONNECTIONLOSS && path) {\n            // Try again\n            rc = zoo_acreate(async_zk, path, \"\", 0,  &ZOO_OPEN_ACL_UNSAFE, 0, stringCompletion, 0);\n        } else if (rc != ZOK) {\n            // fprintf(stderr, \"rc = %d with path = %s\\n\", rc, (path ? path : \"null\"));\n        }\n        if (path) {\n            free(path);\n        }\n    }\n\n    static void create_completion_fn(int rc, const char* value, const void *data) {\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        count++;\n    }\n\n    static void waitForCreateCompletion(int seconds) {\n        time_t expires = time(0) + seconds;\n        while(count == 0 && time(0) < expires) {\n            sleep(1);\n        }\n        count--;\n    }\n\n    static void watcher_chroot_fn(zhandle_t *zh, int type,\n                                    int state, const char *path,void *watcherCtx) {\n        // check for path\n        char *client_path = (char *) watcherCtx;\n        CPPUNIT_ASSERT(strcmp(client_path, path) == 0);\n        count ++;\n    }\n\n    static void waitForChrootWatch(int seconds) {\n        time_t expires = time(0) + seconds;\n        while (count == 0 && time(0) < expires) {\n            sleep(1);\n        }\n        count--;\n    }\n\n    static void waitForVoidCompletion(int seconds) {\n        time_t expires = time(0) + seconds;\n        while(count == 0 && time(0) < expires) {\n            sleep(1);\n        }\n        count--;\n    }\n\n    static void voidCompletion(int rc, const void *data) {\n        int tmp = (int) (long) data;\n        CPPUNIT_ASSERT_EQUAL(tmp, rc);\n        count++;\n    }\n\n    static void verifyCreateFails(const char *path, zhandle_t *zk) {\n      CPPUNIT_ASSERT_EQUAL((int)ZBADARGUMENTS, zoo_create(zk,\n          path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0));\n    }\n\n    static void verifyCreateOk(const char *path, zhandle_t *zk) {\n      CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_create(zk,\n          path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0));\n    }\n\n    static void verifyCreateFailsSeq(const char *path, zhandle_t *zk) {\n      CPPUNIT_ASSERT_EQUAL((int)ZBADARGUMENTS, zoo_create(zk,\n          path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE, 0, 0));\n    }\n\n    static void verifyCreateOkSeq(const char *path, zhandle_t *zk) {\n      CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_create(zk,\n          path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE, 0, 0));\n    }\n\n\n    /**\n       returns false if the vectors dont match\n    **/\n    bool compareAcl(struct ACL_vector acl1, struct ACL_vector acl2) {\n        if (acl1.count != acl2.count) {\n            return false;\n        }\n        struct ACL *aclval1 = acl1.data;\n        struct ACL *aclval2 = acl2.data;\n        if (aclval1->perms != aclval2->perms) {\n            return false;\n        }\n        struct Id id1 = aclval1->id;\n        struct Id id2 = aclval2->id;\n        if (strcmp(id1.scheme, id2.scheme) != 0) {\n            return false;\n        }\n        if (strcmp(id1.id, id2.id) != 0) {\n            return false;\n        }\n        return true;\n    }\n\n    void testDeserializeString() {\n        char *val_str;\n        int rc = 0;\n        int val = -1;\n        struct iarchive *ia;\n        struct buff_struct_2 *b;\n        struct oarchive *oa = create_buffer_oarchive();\n        oa->serialize_Int(oa, \"int\", &val);\n        b = (struct buff_struct_2 *) oa->priv;\n        ia = create_buffer_iarchive(b->buffer, b->len);\n        rc = ia->deserialize_String(ia, \"string\", &val_str);\n        CPPUNIT_ASSERT_EQUAL(-EINVAL, rc);\n    }\n        \n    void testAcl() {\n        int rc;\n        struct ACL_vector aclvec;\n        struct Stat stat;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        rc = zoo_create(zk, \"/acl\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        rc = zoo_get_acl(zk, \"/acl\", &aclvec, &stat  );\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        bool cmp = compareAcl(ZOO_OPEN_ACL_UNSAFE, aclvec);\n        CPPUNIT_ASSERT_EQUAL(true, cmp);\n        rc = zoo_set_acl(zk, \"/acl\", -1, &ZOO_READ_ACL_UNSAFE);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_get_acl(zk, \"/acl\", &aclvec, &stat);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        cmp = compareAcl(ZOO_READ_ACL_UNSAFE, aclvec);\n        CPPUNIT_ASSERT_EQUAL(true, cmp);\n    }\n\n\n    void testAuth() {\n        int rc;\n        count = 0;\n        watchctx_t ctx1, ctx2, ctx3, ctx4, ctx5;\n        zhandle_t *zk = createClient(&ctx1);\n        struct ACL_vector nodeAcl;\n        struct ACL acl_val;\n        rc = zoo_add_auth(0, \"\", 0, 0, voidCompletion, (void*)-1);\n        CPPUNIT_ASSERT_EQUAL((int) ZBADARGUMENTS, rc);\n\n        rc = zoo_add_auth(zk, 0, 0, 0, voidCompletion, (void*)-1);\n        CPPUNIT_ASSERT_EQUAL((int) ZBADARGUMENTS, rc);\n\n        // auth as pat, create /tauth1, close session\n        rc = zoo_add_auth(zk, \"digest\", \"pat:passwd\", 10, voidCompletion,\n                          (void*)ZOK);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        waitForVoidCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n\n        rc = zoo_create(zk, \"/tauth1\", \"\", 0, &ZOO_CREATOR_ALL_ACL, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        {\n            //create a new client\n            zk = createClient(&ctx4);\n            rc = zoo_add_auth(zk, \"digest\", \"\", 0, voidCompletion, (void*)ZOK);\n            CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n            waitForVoidCompletion(3);\n            CPPUNIT_ASSERT(count == 0);\n\n            rc = zoo_add_auth(zk, \"digest\", \"\", 0, voidCompletion, (void*)ZOK);\n            CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n            waitForVoidCompletion(3);\n            CPPUNIT_ASSERT(count == 0);\n        }\n\n        //create a new client\n        zk = createClient(&ctx2);\n\n        rc = zoo_add_auth(zk, \"digest\", \"pat:passwd2\", 11, voidCompletion,\n                          (void*)ZOK);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        waitForVoidCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n\n        char buf[1024];\n        int blen = sizeof(buf);\n        struct Stat stat;\n        rc = zoo_get(zk, \"/tauth1\", 0, buf, &blen, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, rc);\n        // add auth pat w/correct pass verify success\n        rc = zoo_add_auth(zk, \"digest\", \"pat:passwd\", 10, voidCompletion,\n                          (void*)ZOK);\n\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_get(zk, \"/tauth1\", 0, buf, &blen, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        waitForVoidCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n        //create a new client\n        zk = createClient(&ctx3);\n        rc = zoo_add_auth(zk, \"digest\", \"pat:passwd\", 10, voidCompletion, (void*) ZOK);\n        waitForVoidCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n        rc = zoo_add_auth(zk, \"ip\", \"none\", 4, voidCompletion, (void*)ZOK);\n        //make the server forget the auths\n        waitForVoidCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n\n        stopServer();\n        CPPUNIT_ASSERT(ctx3.waitForDisconnected(zk));\n        startServer();\n        CPPUNIT_ASSERT(ctx3.waitForConnected(zk));\n        // now try getting the data\n        rc = zoo_get(zk, \"/tauth1\", 0, buf, &blen, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        // also check for get\n        rc = zoo_get_acl(zk, \"/\", &nodeAcl, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        // check if the acl has all the perms\n        CPPUNIT_ASSERT_EQUAL((int)1, (int)nodeAcl.count);\n        acl_val = *(nodeAcl.data);\n        CPPUNIT_ASSERT_EQUAL((int) acl_val.perms, ZOO_PERM_ALL);\n        // verify on root node\n        rc = zoo_set_acl(zk, \"/\", -1, &ZOO_CREATOR_ALL_ACL);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n\n        rc = zoo_set_acl(zk, \"/\", -1, &ZOO_OPEN_ACL_UNSAFE);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n\n        //[ZOOKEEPER-1108], test that auth info is sent to server, if client is not\n        //connected to server when zoo_add_auth was called.\n        zhandle_t *zk_auth = zookeeper_init(hostPorts, NULL, 10000, 0, NULL, 0);\n        rc = zoo_add_auth(zk_auth, \"digest\", \"pat:passwd\", 10, voidCompletion, (void*)ZOK);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        sleep(2);\n        CPPUNIT_ASSERT(count == 1);\n        count  = 0;\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, zookeeper_close(zk_auth));\n        \n        // [ZOOKEEPER-800] zoo_add_auth should return ZINVALIDSTATE if\n        // the connection is closed. \n        zhandle_t *zk2 = zookeeper_init(hostPorts, NULL, 10000, 0, NULL, 0);\n        sleep(1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, zookeeper_close(zk2));\n        CPPUNIT_ASSERT_EQUAL(0, zoo_state(zk2)); // 0 ==> ZOO_CLOSED_STATE\n        rc = zoo_add_auth(zk2, \"digest\", \"pat:passwd\", 10, voidCompletion, (void*)ZOK);\n        CPPUNIT_ASSERT_EQUAL((int) ZINVALIDSTATE, rc);\n\n        struct sockaddr addr;\n        socklen_t addr_len = sizeof(addr);\n        zk = createClient(&ctx5);\n        stopServer();\n        CPPUNIT_ASSERT(ctx5.waitForDisconnected(zk));\n        CPPUNIT_ASSERT(zookeeper_get_connected_host(zk, &addr, &addr_len) == NULL);\n        addr_len = sizeof(addr);\n        startServer();\n        CPPUNIT_ASSERT(ctx5.waitForConnected(zk));\n        CPPUNIT_ASSERT(zookeeper_get_connected_host(zk, &addr, &addr_len) != NULL);\n    }\n\n    void testGetChildren2() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n\n        rc = zoo_create(zk, \"/parent\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        rc = zoo_create(zk, \"/parent/child_a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        rc = zoo_create(zk, \"/parent/child_b\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        rc = zoo_create(zk, \"/parent/child_c\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        rc = zoo_create(zk, \"/parent/child_d\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        struct String_vector strings;\n        struct Stat stat_a, stat_b;\n\n        rc = zoo_get_children2(zk, \"/parent\", 0, &strings, &stat_a);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        rc = zoo_exists(zk, \"/parent\", 0, &stat_b);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        CPPUNIT_ASSERT(Stat_eq(&stat_a, &stat_b));\n        CPPUNIT_ASSERT(stat_a.numChildren == 4);\n    }\n\n    void testIPV6() {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(\"::1:22181\", &ctx);\n        CPPUNIT_ASSERT(zk);\n        int rc = 0;\n        rc = zoo_create(zk, \"/ipv6\", NULL, -1,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n    }\n\n    void testNullData() {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        CPPUNIT_ASSERT(zk);\n        int rc = 0;\n        rc = zoo_create(zk, \"/mahadev\", NULL, -1,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        char buffer[512];\n        struct Stat stat;\n        int len = 512;\n        rc = zoo_wget(zk, \"/mahadev\", NULL, NULL, buffer, &len, &stat);\n        CPPUNIT_ASSERT_EQUAL( -1, len);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_set(zk, \"/mahadev\", NULL, -1, -1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_wget(zk, \"/mahadev\", NULL, NULL, buffer, &len, &stat);\n        CPPUNIT_ASSERT_EQUAL( -1, len);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n    }\n\n    void testPath() {\n        watchctx_t ctx;\n        char pathbuf[20];\n        zhandle_t *zk = createClient(&ctx);\n        CPPUNIT_ASSERT(zk);\n        int rc = 0;\n\n        memset(pathbuf, 'X', 20);\n        rc = zoo_create(zk, \"/testpathpath0\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL('X', pathbuf[0]);\n\n        rc = zoo_create(zk, \"/testpathpath1\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT(strlen(pathbuf) == 0);\n\n        rc = zoo_create(zk, \"/testpathpath2\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 2);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT(strcmp(pathbuf, \"/\") == 0);\n\n        rc = zoo_create(zk, \"/testpathpath3\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 3);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT(strcmp(pathbuf, \"/t\") == 0);\n\n        rc = zoo_create(zk, \"/testpathpath7\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 15);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT(strcmp(pathbuf, \"/testpathpath7\") == 0);\n\n        rc = zoo_create(zk, \"/testpathpath8\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, 16);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT(strcmp(pathbuf, \"/testpathpath8\") == 0);\n    }\n\n    void testPathValidation() {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        CPPUNIT_ASSERT(zk);\n\n        verifyCreateFails(0, zk);\n        verifyCreateFails(\"\", zk);\n        verifyCreateFails(\"//\", zk);\n        verifyCreateFails(\"///\", zk);\n        verifyCreateFails(\"////\", zk);\n        verifyCreateFails(\"/.\", zk);\n        verifyCreateFails(\"/..\", zk);\n        verifyCreateFails(\"/./\", zk);\n        verifyCreateFails(\"/../\", zk);\n        verifyCreateFails(\"/foo/./\", zk);\n        verifyCreateFails(\"/foo/../\", zk);\n        verifyCreateFails(\"/foo/.\", zk);\n        verifyCreateFails(\"/foo/..\", zk);\n        verifyCreateFails(\"/./.\", zk);\n        verifyCreateFails(\"/../..\", zk);\n        verifyCreateFails(\"/foo/bar/\", zk);\n        verifyCreateFails(\"/foo//bar\", zk);\n        verifyCreateFails(\"/foo/bar//\", zk);\n\n        verifyCreateFails(\"foo\", zk);\n        verifyCreateFails(\"a\", zk);\n\n        // verify that trailing fails, except for seq which adds suffix\n        verifyCreateOk(\"/createseq\", zk);\n        verifyCreateFails(\"/createseq/\", zk);\n        verifyCreateOkSeq(\"/createseq/\", zk);\n        verifyCreateOkSeq(\"/createseq/.\", zk);\n        verifyCreateOkSeq(\"/createseq/..\", zk);\n        verifyCreateFailsSeq(\"/createseq//\", zk);\n        verifyCreateFailsSeq(\"/createseq/./\", zk);\n        verifyCreateFailsSeq(\"/createseq/../\", zk);\n\n        verifyCreateOk(\"/.foo\", zk);\n        verifyCreateOk(\"/.f.\", zk);\n        verifyCreateOk(\"/..f\", zk);\n        verifyCreateOk(\"/..f..\", zk);\n        verifyCreateOk(\"/f.c\", zk);\n        verifyCreateOk(\"/f\", zk);\n        verifyCreateOk(\"/f/.f\", zk);\n        verifyCreateOk(\"/f/f.\", zk);\n        verifyCreateOk(\"/f/..f\", zk);\n        verifyCreateOk(\"/f/f..\", zk);\n        verifyCreateOk(\"/f/.f/f\", zk);\n        verifyCreateOk(\"/f/f./f\", zk);\n    }\n\n    void testChroot() {\n        // the c client async callbacks do\n        // not callback with the path, so\n        // we dont need to test taht for now\n        // we should fix that though soon!\n        watchctx_t ctx, ctx_ch;\n        zhandle_t *zk, *zk_ch;\n        char buf[60];\n        int rc, len;\n        struct Stat stat;\n        const char* data = \"garbage\";\n        const char* retStr = \"/chroot\";\n        const char* root= \"/\";\n        zk_ch = createchClient(&ctx_ch, \"127.0.0.1:22181/testch1/mahadev\");\n        CPPUNIT_ASSERT(zk_ch != NULL);\n        zk = createClient(&ctx);\n        // first test with a NULL zk handle, make sure client library does not\n        // dereference a null pointer, but instead returns ZBADARGUMENTS\n        rc = zoo_create(NULL, \"/testch1\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZBADARGUMENTS, rc);\n        rc = zoo_create(zk, \"/testch1\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_create(zk, \"/testch1/mahadev\", data, 7, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        // try an exists with /\n        len = 60;\n        rc = zoo_get(zk_ch, \"/\", 0, buf, &len, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        //check if the data is the same\n        CPPUNIT_ASSERT(strncmp(buf, data, 7) == 0);\n        //check for watches\n        rc = zoo_wexists(zk_ch, \"/chroot\", watcher_chroot_fn, (void *) retStr, &stat);\n        //now check if we can do create/delete/get/sets/acls/getChildren and others\n        //check create\n        rc = zoo_create(zk_ch, \"/chroot\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0,0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        waitForChrootWatch(3);\n        CPPUNIT_ASSERT(count == 0);\n        rc = zoo_create(zk_ch, \"/chroot/child\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_exists(zk, \"/testch1/mahadev/chroot/child\", 0, &stat);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n\n        rc = zoo_delete(zk_ch, \"/chroot/child\", -1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_exists(zk, \"/testch1/mahadev/chroot/child\", 0, &stat);\n        CPPUNIT_ASSERT_EQUAL((int) ZNONODE, rc);\n        rc = zoo_wget(zk_ch, \"/chroot\", watcher_chroot_fn, (char*) retStr,\n                      buf, &len, &stat);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_set(zk_ch, \"/chroot\",buf, 3, -1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        waitForChrootWatch(3);\n        CPPUNIT_ASSERT(count == 0);\n        // check for getchildren\n        struct String_vector children;\n        rc = zoo_get_children(zk_ch, \"/\", 0, &children);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL((int)1, (int)children.count);\n        //check if te child if chroot\n        CPPUNIT_ASSERT(strcmp((retStr+1), children.data[0]) == 0);\n        // check for get/set acl\n        struct ACL_vector acl;\n        rc = zoo_get_acl(zk_ch, \"/\", &acl, &stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL((int)1, (int)acl.count);\n        CPPUNIT_ASSERT_EQUAL((int)ZOO_PERM_ALL, (int)acl.data->perms);\n        // set acl\n        rc = zoo_set_acl(zk_ch, \"/chroot\", -1,  &ZOO_READ_ACL_UNSAFE);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        // see if you add children\n        rc = zoo_create(zk_ch, \"/chroot/child1\", \"\",0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, rc);\n        //add wget children test\n        rc = zoo_wget_children(zk_ch, \"/\", watcher_chroot_fn, (char*) root, &children);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        //now create a node\n        rc = zoo_create(zk_ch, \"/child2\", \"\",0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        waitForChrootWatch(3);\n        CPPUNIT_ASSERT(count == 0);\n        //check for one async call just to make sure\n        rc = zoo_acreate(zk_ch, \"/child3\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0,\n                         create_completion_fn, 0);\n        waitForCreateCompletion(3);\n        CPPUNIT_ASSERT(count == 0);\n\n        //ZOOKEEPER-1027 correctly return path_buffer without prefixed chroot\n        const char* path = \"/zookeeper1027\";\n        char path_buffer[1024];\n        int path_buffer_len=sizeof(path_buffer);\n        rc = zoo_create(zk_ch, path, \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, path_buffer, path_buffer_len);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL(string(path), string(path_buffer));\n    }\n\n    void testAsyncWatcherAutoReset()\n    {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        watchctx_t lctx[COUNT];\n        int i;\n        char path[80];\n        int rc;\n        evt_t evt;\n\n        async_zk = zk;\n        for(i = 0; i < COUNT; i++) {\n            sprintf(path, \"/awar%d\", i);\n            rc = zoo_awexists(zk, path, watcher, &lctx[i], statCompletion, (void*)ZNONODE);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        yield(zk, 0);\n\n        for(i = 0; i < COUNT/2; i++) {\n            sprintf(path, \"/awar%d\", i);\n            rc = zoo_acreate(zk, path, \"\", 0,  &ZOO_OPEN_ACL_UNSAFE, 0, stringCompletion, strdup(path));\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        yield(zk, 3);\n        for(i = 0; i < COUNT/2; i++) {\n            sprintf(path, \"/awar%d\", i);\n            CPPUNIT_ASSERT_MESSAGE(path, waitForEvent(zk, &lctx[i], 5));\n            evt = lctx[i].getEvent();\n            CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path.c_str(), ZOO_CREATED_EVENT, evt.type);\n            CPPUNIT_ASSERT_EQUAL(string(path), evt.path);\n        }\n\n        for(i = COUNT/2 + 1; i < COUNT*10; i++) {\n            sprintf(path, \"/awar%d\", i);\n            rc = zoo_acreate(zk, path, \"\", 0,  &ZOO_OPEN_ACL_UNSAFE, 0, stringCompletion, strdup(path));\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        yield(zk, 1);\n        stopServer();\n        CPPUNIT_ASSERT(ctx.waitForDisconnected(zk));\n        startServer();\n        CPPUNIT_ASSERT(ctx.waitForConnected(zk));\n        yield(zk, 3);\n        for(i = COUNT/2+1; i < COUNT; i++) {\n            sprintf(path, \"/awar%d\", i);\n            CPPUNIT_ASSERT_MESSAGE(path, waitForEvent(zk, &lctx[i], 5));\n            evt = lctx[i].getEvent();\n            CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_CREATED_EVENT, evt.type);\n            CPPUNIT_ASSERT_EQUAL(string(path), evt.path);\n        }\n    }\n\n    void testWatcherAutoReset(zhandle_t *zk, watchctx_t *ctxGlobal,\n                              watchctx_t *ctxLocal)\n    {\n        bool isGlobal = (ctxGlobal == ctxLocal);\n        int rc;\n        struct Stat stat;\n        char buf[1024];\n        int blen;\n        struct String_vector strings;\n        const char *testName;\n\n        rc = zoo_create(zk, \"/watchtest\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        rc = zoo_create(zk, \"/watchtest/child\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, ZOO_EPHEMERAL, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        if (isGlobal) {\n            testName = \"GlobalTest\";\n            rc = zoo_get_children(zk, \"/watchtest\", 1, &strings);\n            deallocate_String_vector(&strings);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            blen = sizeof(buf);\n            rc = zoo_get(zk, \"/watchtest/child\", 1, buf, &blen, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            rc = zoo_exists(zk, \"/watchtest/child2\", 1, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n        } else {\n            testName = \"LocalTest\";\n            rc = zoo_wget_children(zk, \"/watchtest\", watcher, ctxLocal,\n                                 &strings);\n            deallocate_String_vector(&strings);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            blen = sizeof(buf);\n            rc = zoo_wget(zk, \"/watchtest/child\", watcher, ctxLocal,\n                         buf, &blen, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            rc = zoo_wexists(zk, \"/watchtest/child2\", watcher, ctxLocal,\n                            &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n        }\n\n        CPPUNIT_ASSERT(ctxLocal->countEvents() == 0);\n\n        stopServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxGlobal->waitForDisconnected(zk));\n        startServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxLocal->waitForConnected(zk));\n\n        CPPUNIT_ASSERT(ctxLocal->countEvents() == 0);\n\n        rc = zoo_set(zk, \"/watchtest/child\", \"1\", 1, -1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        struct Stat stat1, stat2;\n        rc = zoo_set2(zk, \"/watchtest/child\", \"1\", 1, -1, &stat1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT(stat1.version >= 0);\n        rc = zoo_set2(zk, \"/watchtest/child\", \"1\", 1, stat1.version, &stat2);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        rc = zoo_set(zk, \"/watchtest/child\", \"1\", 1, stat2.version);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        rc = zoo_create(zk, \"/watchtest/child2\", \"\", 0,\n                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n\n        evt_t evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_CHANGED_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest/child\"), evt.path);\n\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n        // The create will trigget the get children and the\n        // exists watches\n        evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_CREATED_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest/child2\"), evt.path);\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n        evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_CHILD_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest\"), evt.path);\n\n        // Make sure Pings are giving us problems\n        sleep(5);\n\n        CPPUNIT_ASSERT(ctxLocal->countEvents() == 0);\n\n        stopServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxGlobal->waitForDisconnected(zk));\n        startServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxGlobal->waitForConnected(zk));\n\n        if (isGlobal) {\n            testName = \"GlobalTest\";\n            rc = zoo_get_children(zk, \"/watchtest\", 1, &strings);\n            deallocate_String_vector(&strings);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            blen = sizeof(buf);\n            rc = zoo_get(zk, \"/watchtest/child\", 1, buf, &blen, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            rc = zoo_exists(zk, \"/watchtest/child2\", 1, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        } else {\n            testName = \"LocalTest\";\n            rc = zoo_wget_children(zk, \"/watchtest\", watcher, ctxLocal,\n                                 &strings);\n            deallocate_String_vector(&strings);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            blen = sizeof(buf);\n            rc = zoo_wget(zk, \"/watchtest/child\", watcher, ctxLocal,\n                         buf, &blen, &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n            rc = zoo_wexists(zk, \"/watchtest/child2\", watcher, ctxLocal,\n                            &stat);\n            CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        }\n\n        zoo_delete(zk, \"/watchtest/child2\", -1);\n\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n\n        evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_DELETED_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest/child2\"), evt.path);\n\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n        evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_CHILD_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest\"), evt.path);\n\n        stopServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxGlobal->waitForDisconnected(zk));\n        startServer();\n        CPPUNIT_ASSERT_MESSAGE(testName, ctxLocal->waitForConnected(zk));\n\n        zoo_delete(zk, \"/watchtest/child\", -1);\n        zoo_delete(zk, \"/watchtest\", -1);\n\n        CPPUNIT_ASSERT_MESSAGE(testName, waitForEvent(zk, ctxLocal, 5));\n\n        evt = ctxLocal->getEvent();\n        CPPUNIT_ASSERT_EQUAL_MESSAGE(evt.path, ZOO_DELETED_EVENT, evt.type);\n        CPPUNIT_ASSERT_EQUAL(string(\"/watchtest/child\"), evt.path);\n\n        // Make sure nothing is straggling\n        sleep(1);\n        CPPUNIT_ASSERT(ctxLocal->countEvents() == 0);\n    }\n\n    void testWatcherAutoResetWithGlobal()\n    {\n      {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int rc = zoo_create(zk, \"/testarwg\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_create(zk, \"/testarwg/arwg\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n      }\n\n      {\n        watchctx_t ctx;\n        zhandle_t *zk = createchClient(&ctx, \"127.0.0.1:22181/testarwg/arwg\");\n\n        testWatcherAutoReset(zk, &ctx, &ctx);\n      }\n    }\n\n    void testWatcherAutoResetWithLocal()\n    {\n      {\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int rc = zoo_create(zk, \"/testarwl\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        rc = zoo_create(zk, \"/testarwl/arwl\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n      }\n\n      {\n        watchctx_t ctx;\n        watchctx_t lctx;\n        zhandle_t *zk = createchClient(&ctx, \"127.0.0.1:22181/testarwl/arwl\");\n        testWatcherAutoReset(zk, &ctx, &lctx);\n      }\n    }\n};\n\nvolatile int Zookeeper_simpleSystem::count;\nzhandle_t *Zookeeper_simpleSystem::async_zk;\nconst char Zookeeper_simpleSystem::hostPorts[] = \"127.0.0.1:22181\";\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_simpleSystem);\n"
  },
  {
    "path": "src/c/tests/TestClientRetry.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include \"CppAssertHelper.h\"\n\n#include <signal.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/select.h>\n\n#include \"CollectionUtil.h\"\n#include \"ThreadingUtil.h\"\n\nusing namespace Util;\n\n#include \"Vector.h\"\nusing namespace std;\n\n#include <cstring>\n#include <list>\n\n#include <zookeeper.h>\n\n#include \"Util.h\"\n\n#ifdef THREADED\n    static void yield(zhandle_t *zh, int i)\n    {\n        sleep(i);\n    }\n#else\n    static void yield(zhandle_t *zh, int seconds)\n    {\n        int fd;\n        int interest;\n        int events;\n        struct timeval tv;\n        int rc;\n        time_t expires = time(0) + seconds; \n        time_t timeLeft = seconds;\n        fd_set rfds, wfds, efds;\n        FD_ZERO(&rfds);\n        FD_ZERO(&wfds);\n        FD_ZERO(&efds);\n\n        while(timeLeft >= 0) {\n            zookeeper_interest(zh, &fd, &interest, &tv);\n            if (fd != -1) {\n                if (interest&ZOOKEEPER_READ) {\n                    FD_SET(fd, &rfds);\n                } else {\n                    FD_CLR(fd, &rfds);\n                }\n                if (interest&ZOOKEEPER_WRITE) {\n                    FD_SET(fd, &wfds);\n                } else {\n                    FD_CLR(fd, &wfds);\n                }\n            } else {\n                fd = 0;\n            }\n            FD_SET(0, &rfds);\n            if (tv.tv_sec > timeLeft) {\n                tv.tv_sec = timeLeft;\n            }\n            rc = select(fd+1, &rfds, &wfds, &efds, &tv);\n            timeLeft = expires - time(0);\n            events = 0;\n            if (FD_ISSET(fd, &rfds)) {\n                events |= ZOOKEEPER_READ;\n            }\n            if (FD_ISSET(fd, &wfds)) {\n                events |= ZOOKEEPER_WRITE;\n            }\n            zookeeper_process(zh, events);\n        }\n    }\n#endif\n\ntypedef struct evt {\n    string path;\n    int type;\n} evt_t;\n\ntypedef struct watchCtx {\nprivate:\n    list<evt_t> events;\npublic:\n    bool connected;\n    zhandle_t *zh;\n    Mutex mutex;\n\n    watchCtx() {\n        connected = false;\n        zh = 0;\n    }\n    ~watchCtx() {\n        if (zh) {\n            zookeeper_close(zh);\n            zh = 0;\n        }\n    }\n\n    evt_t getEvent() {\n        evt_t evt;\n        mutex.acquire();\n        CPPUNIT_ASSERT( events.size() > 0);\n        evt = events.front();\n        events.pop_front();\n        mutex.release();\n        return evt;\n    }\n\n    int countEvents() {\n        int count;\n        mutex.acquire();\n        count = events.size();\n        mutex.release();\n        return count;\n    }\n\n    void putEvent(evt_t evt) {\n        mutex.acquire();\n        events.push_back(evt);\n        mutex.release();\n    }\n\n    bool waitForConnected(zhandle_t *zh) {\n        time_t expires = time(0) + 10;\n        while(!connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return connected;\n    }\n    bool waitForDisconnected(zhandle_t *zh) {\n        time_t expires = time(0) + 15;\n        while(connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return !connected;\n    }\n} watchctx_t; \n\nclass Zookeeper_clientretry : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_clientretry);\n#ifdef THREADED\n    CPPUNIT_TEST(testRetry);\n#endif\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int type, int state, const char *path,void*v){\n        watchctx_t *ctx = (watchctx_t*)v;\n\n        if (state == ZOO_CONNECTED_STATE) {\n            ctx->connected = true;\n        } else {\n            ctx->connected = false;\n        }\n        if (type != ZOO_SESSION_EVENT) {\n            evt_t evt;\n            evt.path = path;\n            evt.type = type;\n            ctx->putEvent(evt);\n        }\n    }\n\n    static const char hostPorts[];\n\n    const char *getHostPorts() {\n        return hostPorts;\n    }\n\n    zhandle_t *createClient(watchctx_t *ctx) {\n        zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0,\n                                       ctx, 0);\n        ctx->zh = zk;\n        sleep(1);\n        return zk;\n    }\n    \n    FILE *logfile;\npublic:\n\n    Zookeeper_clientretry() {\n      logfile = openlogfile(\"Zookeeper_clientretry\");\n    }\n\n    ~Zookeeper_clientretry() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n\n        char cmd[1024];\n        sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n\n        /* we are testing that if max cnxns is exceeded the server does the right thing */\n        sprintf(cmd, \"export ZKMAXCNXNS=1;%s startClean %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n\n        struct sigaction act;\n        act.sa_handler = SIG_IGN;\n        sigemptyset(&act.sa_mask);\n        act.sa_flags = 0;\n        CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);\n    }\n    \n    void tearDown()\n    {\n        char cmd[1024];\n        sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n\n        /* restart the server in \"normal\" mode */\n        sprintf(cmd, \"%s startClean %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n\n        struct sigaction act;\n        act.sa_handler = SIG_IGN;\n        sigemptyset(&act.sa_mask);\n        act.sa_flags = 0;\n        CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);\n    }\n\n    bool waitForEvent(zhandle_t *zh, watchctx_t *ctx, int seconds) {\n        time_t expires = time(0) + seconds;\n        while(ctx->countEvents() == 0 && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return ctx->countEvents() > 0;\n    }\n\n    static zhandle_t *async_zk;\n\n    void testRetry()\n    {\n      watchctx_t ctx1, ctx2;\n      zhandle_t *zk1 = createClient(&ctx1);\n      CPPUNIT_ASSERT_EQUAL(true, ctx1.waitForConnected(zk1));\n      zhandle_t *zk2 = createClient(&ctx2);\n      zookeeper_close(zk1);\n      CPPUNIT_ASSERT_EQUAL(true, ctx2.waitForConnected(zk2));\n      ctx1.zh = 0;  \n    }\n};\n\nzhandle_t *Zookeeper_clientretry::async_zk;\nconst char Zookeeper_clientretry::hostPorts[] = \"127.0.0.1:22181\";\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_clientretry);\n"
  },
  {
    "path": "src/c/tests/TestDriver.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <string>\n#include <cppunit/TestRunner.h>\n#include <cppunit/CompilerOutputter.h>\n#include <cppunit/TestResult.h>\n#include <cppunit/TestResultCollector.h>\n#include <cppunit/TextTestProgressListener.h>\n#include <cppunit/BriefTestProgressListener.h>\n#include <cppunit/extensions/TestFactoryRegistry.h>\n#include <signal.h>\n#include <stdlib.h>\n#include <stdexcept>\n#include <unistd.h>\n#include <sys/select.h>\n#include <cppunit/Exception.h>\n#include <cppunit/TestFailure.h>\n#include <cppunit/XmlOutputter.h>\n#include <cppunit/TestAssert.h>\n#include <fstream>\n#include <time.h> \n\n#include \"Util.h\"\n#include \"zookeeper_log.h\"\n\nusing namespace std;\n\nCPPUNIT_NS_BEGIN\n\nclass EclipseOutputter: public CompilerOutputter\n{\npublic:\n  EclipseOutputter(TestResultCollector *result,ostream &stream):\n        CompilerOutputter(result,stream,\"%p:%l: \"),stream_(stream)\n    {\n    }\n    virtual void printFailedTestName( TestFailure *failure ){}\n    virtual void printFailureMessage( TestFailure *failure )\n    {\n      stream_<<\": \";\n      Message msg = failure->thrownException()->message();\n      stream_<< msg.shortDescription();\n\n      string text;\n      for(int i=0; i<msg.detailCount();i++){\n          text+=msg.detailAt(i);\n          if(i+1!=msg.detailCount())\n              text+=\", \";\n      }\n      if(text.length()!=0)\n          stream_ <<\" [\"<<text<<\"]\";\n      stream_<<\"\\n\";\n    }\n    ostream& stream_;\n};\n\nCPPUNIT_NS_END\n\nclass TimingListener : public CPPUNIT_NS::BriefTestProgressListener {\n public:\n   void startTest( CPPUNIT_NS::Test *test )\n   {\n     gettimeofday(&_start_time, NULL);\n\n     CPPUNIT_NS::BriefTestProgressListener::startTest(test);\n   }\n  \n   void endTest( CPPUNIT_NS::Test *test )\n   {\n     struct timeval end;\n     gettimeofday(&end, NULL);\n\n     long seconds = end.tv_sec - _start_time.tv_sec;\n     long useconds = end.tv_usec - _start_time.tv_usec;\n\n     long mtime = seconds * 1000 + useconds/1000.0;\n     CPPUNIT_NS::stdCOut()  <<  \" : elapsed \" <<  mtime;\n     CPPUNIT_NS::BriefTestProgressListener::endTest(test);\n   }\n\n private:\n   struct timeval _start_time;\n};\n\nclass ZKServer {\npublic:\n    ZKServer() {\n        char cmd[1024];\n        sprintf(cmd, \"%s startClean %s\", ZKSERVER_CMD, \"127.0.0.1:22181\");\n        CPPUNIT_ASSERT(system(cmd) == 0);\n\n        struct sigaction act;\n        act.sa_handler = SIG_IGN;\n        sigemptyset(&act.sa_mask);\n        act.sa_flags = 0;\n        CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);\n    }\n    virtual ~ZKServer(){\n        char cmd[1024];\n        sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, \"127.0.0.1:22181\");\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n};\n\nint main( int argc, char* argv[] ) { \n   // if command line contains \"-ide\" then this is the post build check\n   // => the output must be in the compiler error format.\n   //bool selfTest = (argc > 1) && (std::string(\"-ide\") == argv[1]);\n   globalTestConfig.addConfigFromCmdLine(argc,argv);\n\n   ZKServer zkserver;\n\n   // Create the event manager and test controller\n   CPPUNIT_NS::TestResult controller;\n   // Add a listener that colllects test result\n   CPPUNIT_NS::TestResultCollector result;\n   controller.addListener( &result );\n   \n   // A listener that print dots as tests run.\n   // CPPUNIT_NS::TextTestProgressListener progress;\n   // CPPUNIT_NS::BriefTestProgressListener progress;\n\n   // brief + elapsed time\n   TimingListener progress;\n   controller.addListener( &progress );\n \n   CPPUNIT_NS::TestRunner runner;\n   runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );\n \n   try {\n     CPPUNIT_NS::stdCOut() << endl << \"Running \" << endl;\n\n     zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);\n     //zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);\n\n     runner.run( controller, globalTestConfig.getTestName());\n\n     // Print test in a compiler compatible format.\n     CPPUNIT_NS::EclipseOutputter outputter( &result,cout);\n     outputter.write(); \n\n // Uncomment this for XML output\n#ifdef ENABLE_XML_OUTPUT\n     std::ofstream file( \"tests.xml\" );\n     CPPUNIT_NS::XmlOutputter xml( &result, file );\n     xml.setStyleSheet( \"report.xsl\" );\n     xml.write();\n     file.close();\n#endif\n   } catch ( std::invalid_argument &e ) {\n     // Test path not resolved\n     cout<<\"\\nERROR: \"<<e.what()<<endl;\n     return 0;\n   }\n\n   return result.wasSuccessful() ? 0 : 1;\n }\n"
  },
  {
    "path": "src/c/tests/TestMulti.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include \"CppAssertHelper.h\"\n\n#include <signal.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/select.h>\n\n#include \"CollectionUtil.h\"\n#include \"ThreadingUtil.h\"\n\nusing namespace Util;\n\n#include \"Vector.h\"\nusing namespace std;\n\n#include <cstring>\n#include <list>\n\n#include <zookeeper.h>\n#include <errno.h>\n#include <recordio.h>\n#include \"Util.h\"\n\n#ifdef THREADED\n    static void yield(zhandle_t *zh, int i)\n    {\n        sleep(i);\n    }\n#else\n    static void yield(zhandle_t *zh, int seconds)\n    {\n        int fd;\n        int interest;\n        int events;\n        struct timeval tv;\n        int rc;\n        time_t expires = time(0) + seconds;\n        time_t timeLeft = seconds;\n        fd_set rfds, wfds, efds;\n        FD_ZERO(&rfds);\n        FD_ZERO(&wfds);\n        FD_ZERO(&efds);\n\n        while(timeLeft >= 0) {\n            zookeeper_interest(zh, &fd, &interest, &tv);\n            if (fd != -1) {\n                if (interest&ZOOKEEPER_READ) {\n                    FD_SET(fd, &rfds);\n                } else {\n                    FD_CLR(fd, &rfds);\n                }\n                if (interest&ZOOKEEPER_WRITE) {\n                    FD_SET(fd, &wfds);\n                } else {\n                    FD_CLR(fd, &wfds);\n                }\n            } else {\n                fd = 0;\n            }\n            FD_SET(0, &rfds);\n            if (tv.tv_sec > timeLeft) {\n                tv.tv_sec = timeLeft;\n            }\n            rc = select(fd+1, &rfds, &wfds, &efds, &tv);\n            timeLeft = expires - time(0);\n            events = 0;\n            if (FD_ISSET(fd, &rfds)) {\n                events |= ZOOKEEPER_READ;\n            }\n            if (FD_ISSET(fd, &wfds)) {\n                events |= ZOOKEEPER_WRITE;\n            }\n            zookeeper_process(zh, events);\n        }\n    }\n#endif\n\ntypedef struct evt {\n    string path;\n    int type;\n} evt_t;\n\ntypedef struct watchCtx {\nprivate:\n    list<evt_t> events;\n    watchCtx(const watchCtx&);\n    watchCtx& operator=(const watchCtx&);\npublic:\n    bool connected;\n    zhandle_t *zh;\n    Mutex mutex;\n\n    watchCtx() {\n        connected = false;\n        zh = 0;\n    }\n    ~watchCtx() {\n        if (zh) {\n            zookeeper_close(zh);\n            zh = 0;\n        }\n    }\n\n    evt_t getEvent() {\n        evt_t evt;\n        mutex.acquire();\n        CPPUNIT_ASSERT( events.size() > 0);\n        evt = events.front();\n        events.pop_front();\n        mutex.release();\n        return evt;\n    }\n\n    int countEvents() {\n        int count;\n        mutex.acquire();\n        count = events.size();\n        mutex.release();\n        return count;\n    }\n\n    void putEvent(evt_t evt) {\n        mutex.acquire();\n        events.push_back(evt);\n        mutex.release();\n    }\n\n    bool waitForConnected(zhandle_t *zh) {\n        time_t expires = time(0) + 10;\n        while(!connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return connected;\n    }\n    bool waitForDisconnected(zhandle_t *zh) {\n        time_t expires = time(0) + 15;\n        while(connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return !connected;\n    }\n} watchctx_t;\n\nclass Zookeeper_multi : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_multi);\n//FIXME: None of these tests pass in single-threaded mode. It seems to be a\n//flaw in the test suite setup.\n#ifdef THREADED\n    CPPUNIT_TEST(testCreate);\n    CPPUNIT_TEST(testCreateDelete);\n    CPPUNIT_TEST(testInvalidVersion);\n    CPPUNIT_TEST(testNestedCreate);\n    CPPUNIT_TEST(testSetData);\n    CPPUNIT_TEST(testUpdateConflict);\n    CPPUNIT_TEST(testDeleteUpdateConflict);\n    CPPUNIT_TEST(testAsyncMulti);\n    CPPUNIT_TEST(testMultiFail);\n    CPPUNIT_TEST(testCheck);\n    CPPUNIT_TEST(testWatch);\n    CPPUNIT_TEST(testSequentialNodeCreateInAsyncMulti);\n#endif\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int type, int state, const char *path,void*v){\n        watchctx_t *ctx = (watchctx_t*)v;\n\n        if (state == ZOO_CONNECTED_STATE) {\n            ctx->connected = true;\n        } else {\n            ctx->connected = false;\n        }\n        if (type != ZOO_SESSION_EVENT) {\n            evt_t evt;\n            evt.path = path;\n            evt.type = type;\n            ctx->putEvent(evt);\n        }\n    }\n\n    static const char hostPorts[];\n\n    const char *getHostPorts() {\n        return hostPorts;\n    }\n    \n    zhandle_t *createClient(watchctx_t *ctx) {\n        return createClient(hostPorts, ctx);\n    }\n\n    zhandle_t *createClient(const char *hp, watchctx_t *ctx) {\n        zhandle_t *zk = zookeeper_init(hp, watcher, 10000, 0, ctx, 0);\n        ctx->zh = zk;\n        CPPUNIT_ASSERT_EQUAL(true, ctx->waitForConnected(zk));\n        return zk;\n    }\n        \n    FILE *logfile;\npublic:\n\n    Zookeeper_multi() {\n      logfile = openlogfile(\"Zookeeper_multi\");\n    }\n\n    ~Zookeeper_multi() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n    }\n\n    void tearDown()\n    {\n    }\n    \n    static volatile int count;\n\n    static void multi_completion_fn(int rc, const void *data) {\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n        count++;\n    }\n\n    static void multi_completion_fn_no_assert(int rc, const void *data) {\n        count++;\n    }\n\n    static void waitForMultiCompletion(int seconds) {\n        time_t expires = time(0) + seconds;\n        while(count == 0 && time(0) < expires) {\n            sleep(1);\n        }\n        count--;\n    }\n\n    static void resetCounter() {\n        count = 0;\n    }\n\n    /**\n     * Test basic multi-op create functionality \n     */\n    void testCreate() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n       \n        int sz = 512;\n        char p1[sz];\n        char p2[sz];\n        char p3[sz];\n        p1[0] = p2[0] = p3[0] = '\\0';\n\n        int nops = 3 ;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi1\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[1], \"/multi1/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);\n        zoo_create_op_init(&ops[2], \"/multi1/b\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        CPPUNIT_ASSERT(strcmp(p1, \"/multi1\") == 0);\n        CPPUNIT_ASSERT(strcmp(p2, \"/multi1/a\") == 0);\n        CPPUNIT_ASSERT(strcmp(p3, \"/multi1/b\") == 0);\n\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2].err);\n    }\n\n    /**\n     * Test create followed by delete \n     */\n    void testCreateDelete() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char p1[sz];\n        p1[0] = '\\0';\n        int nops = 2 ;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi2\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_delete_op_init(&ops[1], \"/multi2\", 0);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        // '/multi2' should have been deleted\n        rc = zoo_exists(zk, \"/multi2\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n    }\n\n    /** \n     * Test invalid versions\n     */\n    void testInvalidVersion() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int nops = 4;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi3\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);\n        zoo_delete_op_init(&ops[1], \"/multi3\", 1);\n        zoo_create_op_init(&ops[2], \"/multi3\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);\n        zoo_create_op_init(&ops[3], \"/multi3/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, results[1].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[2].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[3].err);\n    }\n\n    /**\n     * Test nested creates that rely on state in earlier op in multi\n     */\n    void testNestedCreate() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char p1[sz];\n        p1[0] = '\\0';\n        int nops = 6;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        /* Create */\n        zoo_create_op_init(&ops[0], \"/multi4\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[1], \"/multi4/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[2], \"/multi4/a/1\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n\n        /* Delete */\n        zoo_delete_op_init(&ops[3], \"/multi4/a/1\", 0);\n        zoo_delete_op_init(&ops[4], \"/multi4/a\", 0);\n        zoo_delete_op_init(&ops[5], \"/multi4\", 0);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        // Verify tree deleted\n        rc = zoo_exists(zk, \"/multi4/a/1\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n        \n        rc = zoo_exists(zk, \"/multi4/a\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n  \n        rc = zoo_exists(zk, \"/multi4\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n    }\n\n    /**\n     * Test setdata functionality\n     */\n    void testSetData() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        struct Stat s1;\n\n        char buf[sz];\n        int blen = sz ;\n\n        char p1[sz], p2[sz];\n        \n        int nops = 2;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi5\",   \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[1], \"/multi5/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);\n       \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        \n        yield(zk, 5);\n\n        zoo_op_t setdata_ops[nops];\n        zoo_op_result_t setdata_results[nops];\n\n        zoo_set_op_init(&setdata_ops[0], \"/multi5\",   \"1\", 1, 0, &s1);\n        zoo_set_op_init(&setdata_ops[1], \"/multi5/a\", \"2\", 1, 0, &s1);\n\n        rc = zoo_multi(zk, nops, setdata_ops, setdata_results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);\n        \n        memset(buf, '\\0', blen);\n        rc = zoo_get(zk, \"/multi5\", 0, buf, &blen, &s1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL(1, blen);\n        CPPUNIT_ASSERT(strcmp(\"1\", buf) == 0);\n        \n        memset(buf, '\\0', blen);\n        rc = zoo_get(zk, \"/multi5/a\", 0, buf, &blen, &s1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL(1, blen);\n        CPPUNIT_ASSERT(strcmp(\"2\", buf) == 0);\n    }\n\n    /**\n     * Test update conflicts\n     */\n    void testUpdateConflict() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char buf[sz];\n        int blen = sz;\n        char p1[sz];\n        p1[0] = '\\0';\n        struct Stat s1;\n        int nops = 3;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi6\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_set_op_init(&ops[1], \"/multi6\", \"X\", 1, 0, &s1);\n        zoo_set_op_init(&ops[2], \"/multi6\", \"Y\", 1, 0, &s1);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);\n\n        //Updating version solves conflict -- order matters\n        ops[2].set_op.version = 1;\n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n       \n        memset(buf, 0, sz);\n        rc = zoo_get(zk, \"/multi6\", 0, buf, &blen, &s1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL(blen, 1);\n        CPPUNIT_ASSERT(strncmp(buf, \"Y\", 1) == 0);\n    }\n\n    /**\n     * Test delete-update conflicts\n     */\n    void testDeleteUpdateConflict() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char buf[sz];\n        int blen;\n        char p1[sz];\n        p1[0] = '\\0';\n        struct Stat stat;\n        int nops = 3;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi7\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_delete_op_init(&ops[1], \"/multi7\", 0);\n        zoo_set_op_init(&ops[2], \"/multi7\", \"Y\", 1, 0, &stat);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n\n        // '/multi' should never have been created as entire op should fail\n        rc = zoo_exists(zk, \"/multi7\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n    }\n\n    void testAsyncMulti() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n       \n        int sz = 512;\n        char p1[sz], p2[sz], p3[sz];\n        p1[0] = '\\0';\n        p2[0] = '\\0';\n        p3[0] = '\\0';\n\n        int nops = 3;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi8\",   \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[1], \"/multi8/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);\n        zoo_create_op_init(&ops[2], \"/multi8/b\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);\n \n        rc = zoo_amulti(zk, nops, ops, results, multi_completion_fn, 0);\n        waitForMultiCompletion(10);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        CPPUNIT_ASSERT(strcmp(p1, \"/multi8\") == 0);\n        CPPUNIT_ASSERT(strcmp(p2, \"/multi8/a\") == 0);\n        CPPUNIT_ASSERT(strcmp(p3, \"/multi8/b\") == 0);\n\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2].err);\n    }\n\n    void testMultiFail() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n       \n        int sz = 512;\n        char p1[sz], p2[sz], p3[sz];\n\n        p1[0] = '\\0';\n        p2[0] = '\\0';\n        p3[0] = '\\0';\n\n        int nops = 3;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_create_op_init(&ops[0], \"/multi9\",   \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        zoo_create_op_init(&ops[1], \"/multi9\",   \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);\n        zoo_create_op_init(&ops[2], \"/multi9/b\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, rc);\n    }\n    \n    /**\n     * Test basic multi-op check functionality \n     */\n    void testCheck() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char p1[sz];\n        p1[0] = '\\0';\n        struct Stat s1;\n\n        rc = zoo_create(zk, \"/multi0\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        // Conditionally create /multi0/a' only if '/multi0' at version 0\n        int nops = 2;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_check_op_init(&ops[0], \"/multi0\", 0);\n        zoo_create_op_init(&ops[1], \"/multi0/a\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        \n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);\n\n        // '/multi0/a' should have been created as it passed version check\n        rc = zoo_exists(zk, \"/multi0/a\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n \n        // Only create '/multi0/b' if '/multi0' at version 10 (which it's not)\n        zoo_op_t ops2[nops];\n        zoo_check_op_init(&ops2[0], \"/multi0\", 10);\n        zoo_create_op_init(&ops2[1], \"/multi0/b\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);\n        \n        rc = zoo_multi(zk, nops, ops2, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);\n\n        CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, results[0].err);\n        CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[1].err);\n\n        // '/multi0/b' should NOT have been created\n        rc = zoo_exists(zk, \"/multi0/b\", 0, NULL);\n        CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);\n    }\n\n    /**\n     * Do a multi op inside a watch callback context.\n     */\n    static void doMultiInWatch(zhandle_t *zk, int type, int state, const char *path, void *ctx) {\n        int rc;\n        int sz = 512;\n        char p1[sz];\n        p1[0] = '\\0';\n        struct Stat s1;\n\n        int nops = 1;\n        zoo_op_t ops[nops];\n        zoo_op_result_t results[nops];\n\n        zoo_set_op_init(&ops[0], \"/multiwatch\", \"1\", 1, -1, NULL);\n\n        rc = zoo_multi(zk, nops, ops, results);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);\n\n        memset(p1, '\\0', sz);\n        rc = zoo_get(zk, \"/multiwatch\", 0, p1, &sz, &s1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n        CPPUNIT_ASSERT_EQUAL(1, sz);\n        CPPUNIT_ASSERT(strcmp(\"1\", p1) == 0);\n        count++;\n    }\n\n    /**\n     * Test multi-op called from a watch\n     */\n     void testWatch() {\n        int rc;\n        watchctx_t ctx;\n        zhandle_t *zk = createClient(&ctx);\n        int sz = 512;\n        char p1[sz];\n        p1[0] = '\\0';\n\n        rc = zoo_create(zk, \"/multiwatch\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n\n        // create a watch on node '/multiwatch'\n        rc = zoo_wget(zk, \"/multiwatch\", doMultiInWatch, &ctx, p1, &sz, NULL);\n\n        // setdata on node '/multiwatch' this should trip the watch\n        rc = zoo_set(zk, \"/multiwatch\", NULL, -1, -1);\n        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);\n\n        // wait for multi completion in doMultiInWatch\n        waitForMultiCompletion(5);\n     }\n\n     /**\n      * ZOOKEEPER-1624: PendingChanges of create sequential node request didn't\n      * get rollbacked correctly when multi-op failed. This caused\n      * create sequential node request in subsequent multi-op to failed because\n      * sequential node name generation is incorrect.\n      *\n      * The check is to make sure that each request in multi-op failed with\n      * the correct reason.\n      */\n     void testSequentialNodeCreateInAsyncMulti() {\n         int rc;\n         watchctx_t ctx;\n         zhandle_t *zk = createClient(&ctx);\n\n         int iteration = 4;\n         int nops = 2;\n\n         zoo_op_result_t results[iteration][nops];\n         zoo_op_t ops[nops];\n         zoo_create_op_init(&ops[0], \"/node-\",   \"\", 0, &ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE, NULL, 0);\n         zoo_create_op_init(&ops[1], \"/dup\", \"\", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);\n         for (int i = 0; i < iteration ; ++i) {\n           rc = zoo_amulti(zk, nops, ops, results[i], multi_completion_fn_no_assert, 0);\n           CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);\n         }\n\n         waitForMultiCompletion(10);\n\n         CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0][0].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1][0].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2][0].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZOK, results[3][0].err);\n\n         CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0][1].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[1][1].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[2][1].err);\n         CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[3][1].err);\n\n         resetCounter();\n     }\n};\n\nvolatile int Zookeeper_multi::count;\nconst char Zookeeper_multi::hostPorts[] = \"127.0.0.1:22181\";\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_multi);\n"
  },
  {
    "path": "src/c/tests/TestOperations.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include \"CppAssertHelper.h\"\n\n#include \"ZKMocks.h\"\n#include <proto.h>\n\nusing namespace std;\n\nclass Zookeeper_operations : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_operations);\n#ifndef THREADED\n    CPPUNIT_TEST(testPing);\n    CPPUNIT_TEST(testUnsolicitedPing);\n    CPPUNIT_TEST(testTimeoutCausedByWatches1);\n    CPPUNIT_TEST(testTimeoutCausedByWatches2);\n#else    \n    CPPUNIT_TEST(testAsyncWatcher1);\n    CPPUNIT_TEST(testAsyncGetOperation);\n#endif\n    CPPUNIT_TEST(testOperationsAndDisconnectConcurrently1);\n    CPPUNIT_TEST(testOperationsAndDisconnectConcurrently2);\n    CPPUNIT_TEST(testConcurrentOperations1);\n    CPPUNIT_TEST_SUITE_END();\n    zhandle_t *zh;\n    FILE *logfile;\n\n    static void watcher(zhandle_t *, int, int, const char *,void*){}\npublic: \n    Zookeeper_operations() {\n      logfile = openlogfile(\"Zookeeper_operations\");\n    }\n\n    ~Zookeeper_operations() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n\n        zoo_deterministic_conn_order(0);\n        zh=0;\n    }\n    \n    void tearDown()\n    {\n        zookeeper_close(zh);\n    }\n\n    class AsyncGetOperationCompletion: public AsyncCompletion{\n    public:\n        AsyncGetOperationCompletion():called_(false),rc_(ZAPIERROR){}\n        virtual void dataCompl(int rc, const char *value, int len, const Stat *stat){\n            synchronized(mx_);\n            called_=true;\n            rc_=rc;\n            value_.erase();\n            if(rc!=ZOK) return;\n            value_.assign(value,len);\n            if(stat)\n                stat_=*stat;\n        }\n        bool operator()()const{\n            synchronized(mx_);\n            return called_;\n        }\n        mutable Mutex mx_;\n        bool called_;\n        int rc_;\n        string value_;\n        NodeStat stat_;\n    };\n#ifndef THREADED\n    // send two get data requests; verify that the corresponding completions called\n    void testConcurrentOperations1()\n    {\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // first operation\n        AsyncGetOperationCompletion res1;\n        zkServer.addOperationResponse(new ZooGetResponse(\"1\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // second operation\n        AsyncGetOperationCompletion res2;\n        zkServer.addOperationResponse(new ZooGetResponse(\"2\",1));\n        rc=zoo_aget(zh,\"/x/y/2\",0,asyncCompletion,&res2);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // process the send queue\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        while((rc=zookeeper_process(zh,interest))==ZOK) {\n          millisleep(100);\n          //printf(\"%d\\n\", rc);\n        }\n        //printf(\"RC = %d\", rc);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);\n        CPPUNIT_ASSERT_EQUAL(string(\"1\"),res1.value_);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,res2.rc_);\n        CPPUNIT_ASSERT_EQUAL(string(\"2\"),res2.value_);\n    }\n    // send two getData requests and disconnect while the second request is\n    // outstanding;\n    // verify the completions are called\n    void testOperationsAndDisconnectConcurrently1()\n    {\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // first operation\n        AsyncGetOperationCompletion res1;\n        zkServer.addOperationResponse(new ZooGetResponse(\"1\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // second operation\n        AsyncGetOperationCompletion res2;\n        zkServer.addOperationResponse(new ZooGetResponse(\"2\",1));\n        rc=zoo_aget(zh,\"/x/y/2\",0,asyncCompletion,&res2);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // process the send queue\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // simulate a disconnect\n        zkServer.setConnectionLost();\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,rc);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);\n        CPPUNIT_ASSERT_EQUAL(string(\"1\"),res1.value_);\n        CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,res2.rc_);\n        CPPUNIT_ASSERT_EQUAL(string(\"\"),res2.value_);\n    }\n    // send two getData requests and simulate timeout while the both request\n    // are pending;\n    // verify the completions are called\n    void testOperationsAndDisconnectConcurrently2()\n    {\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // first operation\n        AsyncGetOperationCompletion res1;\n        zkServer.addOperationResponse(new ZooGetResponse(\"1\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // second operation\n        AsyncGetOperationCompletion res2;\n        zkServer.addOperationResponse(new ZooGetResponse(\"2\",1));\n        rc=zoo_aget(zh,\"/x/y/2\",0,asyncCompletion,&res2);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // simulate timeout\n        timeMock.tick(+10); // advance system time by 10 secs\n        // the next call to zookeeper_interest should return ZOPERATIONTIMEOUT\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,rc);\n        // make sure the completions have been called\n        CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,res1.rc_);\n        CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,res2.rc_);\n    }\n\n    class PingCountingServer: public ZookeeperServer{\n    public:\n        PingCountingServer():pingCount_(0){}\n        // called when a client request is received\n        virtual void onMessageReceived(const RequestHeader& rh, iarchive* ia){\n           if(rh.type==ZOO_PING_OP){\n               pingCount_++;\n           }\n        }\n        int pingCount_;\n    };\n\n    // establish a connection; idle for a while\n    // verify ping was sent at least once\n    void testPing()\n    {\n        const int TIMEOUT=9; // timeout in secs\n        Mock_gettimeofday timeMock;\n        PingCountingServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        // receive timeout is in milliseconds\n        zh=zookeeper_init(\"localhost:1234\",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // Round 1.\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // simulate waiting for the select() call to timeout; \n        // advance the system clock accordingly\n        timeMock.tick(tv);  \n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        // verify no ping sent\n        CPPUNIT_ASSERT(zkServer.pingCount_==0);\n        \n        // Round 2.\n        // the client should have the idle threshold exceeded, by now\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // assume the socket is writable, so no idling here; move on to \n        // zookeeper_process immediately\n        rc=zookeeper_process(zh,interest);\n        // ZNOTHING means the client hasn't received a ping response yet\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        // verify a ping is sent\n        CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);\n        \n        // Round 3.\n        // we're going to receive a server PING response and make sure\n        // that the client has updated its last_recv timestamp \n        zkServer.addRecvResponse(new PingResponse);\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // pseudo-sleep for a short while (10 ms)\n        timeMock.millitick(10);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // only one ping so far?\n        CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);\n        CPPUNIT_ASSERT(timeMock==zh->last_recv);\n\n        // Round 4\n        // make sure that a ping is not sent if something is outstanding\n        AsyncGetOperationCompletion res1;\n        rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        timeMock.tick(tv);  \n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // pseudo-sleep for a short while (10 ms)\n        timeMock.millitick(10);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        // only one ping so far?\n        CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);\n    }\n\n    // ZOOKEEPER-2253: Permit unsolicited pings\n    void testUnsolicitedPing()\n    {\n        const int TIMEOUT=9; // timeout in secs\n        Mock_gettimeofday timeMock;\n        PingCountingServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        // receive timeout is in milliseconds\n        zh=zookeeper_init(\"localhost:1234\",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n\n        int fd=0;\n        int interest=0;\n        timeval tv;\n\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        // verify no ping sent\n        CPPUNIT_ASSERT(zkServer.pingCount_==0);\n\n        // we're going to receive a unsolicited PING response; ensure\n        // that the client has updated its last_recv timestamp\n        timeMock.tick(tv);\n        zkServer.addRecvResponse(new PingResponse);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        CPPUNIT_ASSERT(timeMock==zh->last_recv);\n    }\n\n    // simulate a watch arriving right before a ping is due\n    // assert the ping is sent nevertheless\n    void testTimeoutCausedByWatches1()\n    {\n        const int TIMEOUT=9; // timeout in secs\n        Mock_gettimeofday timeMock;\n        PingCountingServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        // receive timeout is in milliseconds\n        zh=zookeeper_init(\"localhost:1234\",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // Round 1.\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // simulate waiting for the select() call to timeout; \n        // advance the system clock accordingly\n        timeMock.tick(tv);\n        timeMock.tick(-1); // set the clock to a millisecond before a ping is due\n        // trigger a watch now\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/x/y/z\"));\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // arrival of a watch sets the last_recv to the current time\n        CPPUNIT_ASSERT(timeMock==zh->last_recv);\n        // spend 1 millisecond by processing the watch\n        timeMock.tick(1);\n        \n        // Round 2.\n        // a ping is due; zookeeper_interest() must send it now\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // no delay here -- as if the socket is immediately writable\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        // verify a ping is sent\n        CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);        \n    }\n\n    // similar to testTimeoutCausedByWatches1, but this time the watch is \n    // triggered while the client has an outstanding request\n    // assert the ping is sent on time\n    void testTimeoutCausedByWatches2()\n    {\n        const int TIMEOUT=9; // timeout in secs\n        Mock_gettimeofday now;\n        PingCountingServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n        \n        // receive timeout is in milliseconds\n        zh=zookeeper_init(\"localhost:1234\",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        // queue up a request; keep it pending (as if the server is busy or has died)\n        AsyncGetOperationCompletion res1;\n        zkServer.addOperationResponse(new ZooGetResponse(\"2\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n\n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // Round 1.\n        // send the queued up zoo_aget() request\n        Mock_gettimeofday beginningOfTimes(now); // remember when we started\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // no delay -- the socket is writable\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc); \n        \n        // Round 2.\n        // what's next?\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // no response from the server yet -- waiting in the select() call\n        now.tick(tv);\n        // a watch has arrived, thus preventing the connection from timing out \n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/x/y/z\"));        \n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc); // read the watch message\n        CPPUNIT_ASSERT_EQUAL(0,zkServer.pingCount_); // not yet!\n        \n        //Round 3.\n        // now is the time to send a ping; make sure it's actually sent\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        // verify a ping is sent\n        CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);\n        // make sure only 1/3 of the timeout has passed\n        CPPUNIT_ASSERT_EQUAL((int32_t)TIMEOUT/3*1000,toMilliseconds(now-beginningOfTimes));\n    }\n\n#else   \n    class TestGetDataJob: public TestJob{\n    public:\n        TestGetDataJob(ZookeeperServer* svr,zhandle_t* zh, int reps=500)\n            :svr_(svr),zh_(zh),rc_(ZAPIERROR),reps_(reps){}\n        virtual void run(){\n            int i;\n            for(i=0;i<reps_;i++){\n                char buf;\n                int size=sizeof(buf);\n\n                if (i % 10 == 0) {\n                    // We need to pause every once in a while so we don't\n                    // get too far ahead and finish before the disconnect\n\t            millisleep(1);\n                }\n                svr_->addOperationResponse(new ZooGetResponse(\"1\",1));\n                rc_=zoo_get(zh_,\"/x/y/z\",0,&buf,&size,0);\n                if(rc_!=ZOK){\n                    break;\n                }\n            }\n        }\n        ZookeeperServer* svr_;\n        zhandle_t* zh_;\n        int rc_;\n        int reps_;\n    };\n    class TestConcurrentOpJob: public TestGetDataJob{\n    public:\n        static const int REPS=500;\n        TestConcurrentOpJob(ZookeeperServer* svr,zhandle_t* zh):\n            TestGetDataJob(svr,zh,REPS){}\n        virtual TestJob* clone() const {\n            return new TestConcurrentOpJob(svr_,zh_);\n        }\n        virtual void validate(const char* file, int line) const{\n            CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(\"ZOK != rc\",(int)ZOK,rc_,file,line);\n        }\n    };\n    void testConcurrentOperations1()\n    {\n        for(int counter=0; counter<50; counter++){\n            // frozen time -- no timeouts and no pings\n            Mock_gettimeofday timeMock;\n            \n            ZookeeperServer zkServer;\n            Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n            // must call zookeeper_close() while all the mocks are in the scope!\n            CloseFinally guard(&zh);\n            \n            zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n            CPPUNIT_ASSERT(zh!=0);\n            // make sure the client has connected\n            CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n            \n            TestJobManager jmgr(TestConcurrentOpJob(&zkServer,zh),10);\n            jmgr.startAllJobs();\n            jmgr.wait();\n            // validate test results\n            VALIDATE_JOBS(jmgr);\n        }\n    }\n    class ZKGetJob: public TestJob{\n    public:\n        static const int REPS=1000;\n        ZKGetJob(zhandle_t* zh)\n            :zh_(zh),rc_(ZAPIERROR){}\n        virtual TestJob* clone() const {\n            return new ZKGetJob(zh_);\n        }\n        virtual void run(){\n            int i;\n            for(i=0;i<REPS;i++){\n                char buf;\n                int size=sizeof(buf);                \n                rc_=zoo_get(zh_,\"/xyz\",0,&buf,&size,0);\n                if(rc_!=ZOK){\n                    break;\n                }\n            }\n            //TEST_TRACE((\"Finished %d iterations\",i));\n        }\n        virtual void validate(const char* file, int line) const{\n            CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(\"ZOK != rc\",(int)ZOK,rc_,file,line);\n        }\n        zhandle_t* zh_;\n        int rc_;\n    };\n\n    // this test connects to a real ZK server and creates the /xyz node and sends\n    // lots of zoo_get requests.\n    // to run this test use the following command:\n    // zktest-mt Zookeeper_operations::testOperationsAndDisconnectConcurrently2 localhost:3181\n    // where the second parameter is the server host and port\n    void testOperationsAndDisconnectConcurrently2()\n    {\n        if(globalTestConfig.getTestName().find(__func__)==string::npos || \n                globalTestConfig.getExtraOptCount()==0)\n        {\n            // only run this test when specifically asked so\n            return;\n        }\n        string host(*(globalTestConfig.getExtraOptBegin()));\n        zhandle_t* lzh=zookeeper_init(host.c_str(),watcher,10000,0,0,0);\n        CPPUNIT_ASSERT(lzh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT_MESSAGE(\"Unable to connect to the host\",\n                ensureCondition(ClientConnected(zh),5000)<5000);\n        \n        char realpath[1024];\n        int rc=zoo_create(lzh,\"/xyz\",\"1\",1,&ZOO_OPEN_ACL_UNSAFE,0,realpath,sizeof(realpath)-1);\n        CPPUNIT_ASSERT(rc==ZOK || rc==ZNODEEXISTS);\n        zookeeper_close(lzh); \n  \n        for(int counter=0; counter<200; counter++){\n            TEST_TRACE((\"Loop count %d\",counter));\n            \n            CloseFinally guard(&zh);\n\n            zh=zookeeper_init(host.c_str(),watcher,10000,0,0,0);\n            CPPUNIT_ASSERT(zh!=0);\n            // make sure the client has connected\n            CPPUNIT_ASSERT_MESSAGE(\"Unable to connect to the host\",\n                    ensureCondition(ClientConnected(zh),5000)<5000);\n            \n            TestJobManager jmgr(ZKGetJob(zh),10);\n            jmgr.startJobsImmediately();\n            jmgr.wait();\n            VALIDATE_JOBS(jmgr);\n            TEST_TRACE((\"run %d finished\",counter));\n        }\n\n    }\n\n    class TestConcurrentOpWithDisconnectJob: public TestGetDataJob{\n    public:\n        static const int REPS=1000;\n        TestConcurrentOpWithDisconnectJob(ZookeeperServer* svr,zhandle_t* zh):\n            TestGetDataJob(svr,zh,REPS){}\n        virtual TestJob* clone() const {\n            return new TestConcurrentOpWithDisconnectJob(svr_,zh_);\n        }\n        virtual void validate(const char* file, int line) const{\n            CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(\"ZCONNECTIONLOSS != rc\",(int)ZCONNECTIONLOSS,rc_,file,line);\n        }\n    };\n\n    // this test is not 100% accurate in a sense it may not detect all error cases.\n    // TODO: I can't think of a test that is 100% accurate and doesn't interfere\n    //       with the code being tested (in terms of introducing additional \n    //       implicit synchronization points)\n    void testOperationsAndDisconnectConcurrently1()\n    {\n        for(int counter=0; counter<50; counter++){\n            //TEST_TRACE((\"Loop count %d\",counter));\n            // frozen time -- no timeouts and no pings\n            Mock_gettimeofday timeMock;\n            \n            ZookeeperServer zkServer;\n            Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n            // must call zookeeper_close() while all the mocks are in the scope!\n            CloseFinally guard(&zh);\n            \n            zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n            CPPUNIT_ASSERT(zh!=0);\n            // make sure the client has connected\n            CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n            \n            TestJobManager jmgr(TestConcurrentOpWithDisconnectJob(&zkServer,zh),10);\n            jmgr.startJobsImmediately();\n            // let everything startup before we shutdown the server\n            millisleep(4);\n            // reconnect attempts will start failing immediately \n            zkServer.setServerDown(0);\n            // next recv call will return 0\n            zkServer.setConnectionLost();\n            jmgr.wait();\n            VALIDATE_JOBS(jmgr);\n        }\n        \n    }\n    // call zoo_aget() in the multithreaded mode\n    void testAsyncGetOperation()\n    {\n        Mock_gettimeofday timeMock;\n        \n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n\n        AsyncGetOperationCompletion res1;\n        zkServer.addOperationResponse(new ZooGetResponse(\"1\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&res1);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        CPPUNIT_ASSERT(ensureCondition(res1,1000)<1000);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);\n        CPPUNIT_ASSERT_EQUAL(string(\"1\"),res1.value_);        \n    }\n    class ChangeNodeWatcher: public WatcherAction{\n    public:\n        ChangeNodeWatcher():changed_(false){}\n        virtual void onNodeValueChanged(zhandle_t*,const char* path){\n            synchronized(mx_);\n            changed_=true;\n            if(path!=0) path_=path;\n        }\n        // this predicate checks if CHANGE_EVENT event type was triggered, unlike\n        // the isWatcherTriggered() that returns true whenever a watcher is triggered\n        // regardless of the event type\n        SyncedBoolCondition isNodeChangedTriggered() const{\n            return SyncedBoolCondition(changed_,mx_);\n        }\n        bool changed_;\n        string path_;\n    };\n    \n    class AsyncWatcherCompletion: public AsyncCompletion{\n    public:\n        AsyncWatcherCompletion(ZookeeperServer& zkServer):zkServer_(zkServer){}\n        virtual void statCompl(int rc, const Stat *stat){\n            // we received a server response, now enqueue a watcher event\n            // to trigger the watcher\n            zkServer_.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/x/y/z\"));\n        }\n        ZookeeperServer& zkServer_;\n    };\n    // verify that async watcher is called for znode events (CREATED, DELETED etc.)\n    void testAsyncWatcher1(){\n        Mock_gettimeofday timeMock;\n        \n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        ChangeNodeWatcher action;        \n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,\n                TEST_CLIENT_ID,&action,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n        \n        // set the watcher\n        AsyncWatcherCompletion completion(zkServer);\n        // prepare a response for the zoo_aexists() request\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_aexists(zh,\"/x/y/z\",1,asyncCompletion,&completion);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        CPPUNIT_ASSERT(ensureCondition(action.isNodeChangedTriggered(),1000)<1000);\n        CPPUNIT_ASSERT_EQUAL(string(\"/x/y/z\"),action.path_);                \n    }\n#endif\n};\n\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_operations);\n"
  },
  {
    "path": "src/c/tests/TestWatchers.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include \"CppAssertHelper.h\"\n\n#include \"ZKMocks.h\"\n#include \"CollectionUtil.h\"\n#include \"Util.h\"\n\nclass Zookeeper_watchers : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_watchers);\n    CPPUNIT_TEST(testDefaultSessionWatcher1);\n    CPPUNIT_TEST(testDefaultSessionWatcher2);\n    CPPUNIT_TEST(testObjectSessionWatcher1);\n    CPPUNIT_TEST(testObjectSessionWatcher2);\n    CPPUNIT_TEST(testNodeWatcher1);\n    CPPUNIT_TEST(testChildWatcher1);\n    CPPUNIT_TEST(testChildWatcher2);\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int, int, const char *,void*){}\n    zhandle_t *zh;\n    FILE *logfile;\n    \npublic:\n\n    Zookeeper_watchers() {\n      logfile = openlogfile(\"Zookeeper_watchers\");\n    }\n\n    ~Zookeeper_watchers() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n\n        zoo_deterministic_conn_order(0);\n        zh=0;\n    }\n    \n    void tearDown()\n    {\n        zookeeper_close(zh);\n    }\n    \n    class ConnectionWatcher: public WatcherAction{\n    public:\n        ConnectionWatcher():connected_(false),counter_(0){}\n        virtual void onConnectionEstablished(zhandle_t*){\n            synchronized(mx_);\n            counter_++;\n            connected_=true;\n        }\n        SyncedBoolCondition isConnectionEstablished() const{\n            return SyncedBoolCondition(connected_,mx_);\n        }\n        bool connected_;\n        int counter_;\n    };\n\n    class DisconnectWatcher: public WatcherAction{\n    public:\n        DisconnectWatcher():disconnected_(false),counter_(0){}\n        virtual void onConnectionLost(zhandle_t*){\n            synchronized(mx_);\n            counter_++;\n            disconnected_=true;\n        }\n        SyncedBoolCondition isDisconnected() const{\n            return SyncedBoolCondition(disconnected_,mx_);\n        }\n        bool disconnected_;\n        int counter_;\n    };\n\n    class CountingDataWatcher: public WatcherAction{\n    public:\n        CountingDataWatcher():disconnected_(false),counter_(0){}\n        virtual void onNodeValueChanged(zhandle_t*,const char* path){\n            synchronized(mx_);\n            counter_++;\n        }\n        virtual void onConnectionLost(zhandle_t*){\n            synchronized(mx_);\n            counter_++;\n            disconnected_=true;\n        }\n        bool disconnected_;\n        int counter_;\n    };\n\n    class DeletionCountingDataWatcher: public WatcherAction{\n    public:\n        DeletionCountingDataWatcher():counter_(0){}\n        virtual void onNodeDeleted(zhandle_t*,const char* path){\n            synchronized(mx_);\n            counter_++;\n        }\n        int counter_;\n    };\n\n    class ChildEventCountingWatcher: public WatcherAction{\n    public:\n        ChildEventCountingWatcher():counter_(0){}\n        virtual void onChildChanged(zhandle_t*,const char* path){\n            synchronized(mx_);\n            counter_++;\n        }\n        int counter_;\n    };\n\n#ifndef THREADED\n    \n    // verify: the default watcher is called once for a session event\n    void testDefaultSessionWatcher1(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        ConnectionWatcher watcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &watcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // open the socket\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);        \n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_CONNECTING_STATE,zoo_state(zh));\n        // send the handshake packet to the server\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_ASSOCIATING_STATE,zoo_state(zh));\n        // receive the server handshake response\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // verify connected\n        CPPUNIT_ASSERT_EQUAL(ZOO_CONNECTED_STATE,zoo_state(zh));\n        CPPUNIT_ASSERT(watcher.connected_);\n        CPPUNIT_ASSERT_EQUAL(1,watcher.counter_);\n    }\n    \n    // test case: connect to server, set a default watcher, disconnect from the server\n    // verify: the default watcher is called once\n    void testDefaultSessionWatcher2(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        DisconnectWatcher watcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &watcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        // first operation\n        AsyncCompletion ignored;\n        zkServer.addOperationResponse(new ZooGetResponse(\"1\",1));\n        int rc=zoo_aget(zh,\"/x/y/1\",0,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // this will process the response and activate the watcher\n        rc=zookeeper_process(zh,ZOOKEEPER_READ);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        // now, disconnect\n        zkServer.setConnectionLost();\n        rc=zookeeper_process(zh,ZOOKEEPER_READ);\n        CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,rc);\n        // verify disconnected\n        CPPUNIT_ASSERT(watcher.disconnected_);\n        CPPUNIT_ASSERT_EQUAL(1,watcher.counter_);\n    }\n    \n    // testcase: connect to the server, set a watcher object on a node, \n    //           disconnect from the server\n    // verify: the watcher object as well as the default watcher are called\n    void testObjectSessionWatcher1(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        DisconnectWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        AsyncCompletion ignored;\n        CountingDataWatcher wobject;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_awexists(zh,\"/x/y/1\",activeWatcher,&wobject,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // this will process the response and activate the watcher\n        rc=zookeeper_process(zh,ZOOKEEPER_READ);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        // now, disconnect\n        zkServer.setConnectionLost();\n        rc=zookeeper_process(zh,ZOOKEEPER_READ);\n        CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,rc);\n\n        // verify the default watcher has been triggered\n        CPPUNIT_ASSERT(defWatcher.disconnected_);\n        // and triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,defWatcher.counter_);\n        \n        // the path-specific watcher has been triggered as well\n        CPPUNIT_ASSERT(wobject.disconnected_);\n        // only once!\n        CPPUNIT_ASSERT_EQUAL(1,wobject.counter_);\n    }\n\n    // testcase: connect to the server, set a watcher object on a node, \n    //           set a def watcher on another node,disconnect from the server\n    // verify: the watcher object as well as the default watcher are called\n    void testObjectSessionWatcher2(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        DisconnectWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        // set the default watcher\n        AsyncCompletion ignored;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_aexists(zh,\"/a/b/c\",1,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        CountingDataWatcher wobject;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        rc=zoo_awexists(zh,\"/x/y/z\",activeWatcher,&wobject,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // this will process the response and activate the watcher\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        // disconnect now\n        zkServer.setConnectionLost();\n        rc=zookeeper_process(zh,ZOOKEEPER_READ);\n        CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,rc);\n\n        // verify the default watcher has been triggered\n        CPPUNIT_ASSERT(defWatcher.disconnected_);\n        // and triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,defWatcher.counter_);\n        \n        // the path-specific watcher has been triggered as well\n        CPPUNIT_ASSERT(wobject.disconnected_);\n        // only once!\n        CPPUNIT_ASSERT_EQUAL(1,wobject.counter_);\n    }\n\n    // testcase: register 2 node watches for different paths, trigger the watches\n    // verify: the data watchers are processed, the default watcher is not called\n    void testNodeWatcher1(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        DisconnectWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        AsyncCompletion ignored;\n        CountingDataWatcher wobject1;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_awexists(zh,\"/a/b/c\",activeWatcher,&wobject1,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        CountingDataWatcher wobject2;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        rc=zoo_awexists(zh,\"/x/y/z\",activeWatcher,&wobject2,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // this will process the response and activate the watcher\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/a/b/c\"));\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/x/y/z\"));\n        // make sure all watchers have been processed\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n        \n        CPPUNIT_ASSERT_EQUAL(1,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n\n    // testcase: set up both a children and a data watchers on the node /a, then\n    //           delete the node by sending a DELETE_EVENT event\n    // verify: both watchers are triggered\n    void testChildWatcher1(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        DeletionCountingDataWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        AsyncCompletion ignored;\n        DeletionCountingDataWatcher wobject1;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_awexists(zh,\"/a\",activeWatcher,&wobject1,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        typedef ZooGetChildrenResponse::StringVector ZooVector;\n        zkServer.addOperationResponse(new ZooGetChildrenResponse(\n                Util::CollectionBuilder<ZooVector>()(\"/a/1\")(\"/a/2\")\n                ));\n        DeletionCountingDataWatcher wobject2;\n        rc=zoo_awget_children(zh,\"/a\",activeWatcher,\n                &wobject2,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // this will process the response and activate the watcher\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_DELETED_EVENT,\"/a\"));\n        // make sure the watchers have been processed\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        CPPUNIT_ASSERT_EQUAL(1,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n\n    // testcase: create both a child and data watch on the node /a, send a ZOO_CHILD_EVENT\n    // verify: only the child watch triggered\n    void testChildWatcher2(){\n        Mock_gettimeofday timeMock;\n        ZookeeperServer zkServer;\n        // must call zookeeper_close() while all the mocks are in scope\n        CloseFinally guard(&zh);\n\n        ChildEventCountingWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state\n        forceConnected(zh);\n        \n        AsyncCompletion ignored;\n        ChildEventCountingWatcher wobject1;\n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_awexists(zh,\"/a\",activeWatcher,&wobject1,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        typedef ZooGetChildrenResponse::StringVector ZooVector;\n        zkServer.addOperationResponse(new ZooGetChildrenResponse(\n                Util::CollectionBuilder<ZooVector>()(\"/a/1\")(\"/a/2\")\n                ));\n        ChildEventCountingWatcher wobject2;\n        rc=zoo_awget_children(zh,\"/a\",activeWatcher,\n                &wobject2,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // this will process the response and activate the watcher\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHILD_EVENT,\"/a\"));\n        // make sure the watchers have been processed\n        while((rc=zookeeper_process(zh,ZOOKEEPER_READ))==ZOK) {\n          millisleep(100);\n        }\n        CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);\n\n        CPPUNIT_ASSERT_EQUAL(0,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n\n#else\n    // verify: the default watcher is called once for a session event\n    void testDefaultSessionWatcher1(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_SESSION_EVENT,ZOO_CONNECTED_STATE);\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        ConnectionWatcher watcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &watcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // wait till watcher proccessing has completed (the connection \n        // established event)\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n        \n        // verify the watcher has been triggered\n        CPPUNIT_ASSERT(ensureCondition(watcher.isConnectionEstablished(),1000)<1000);\n        // triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,watcher.counter_);\n    }\n\n    // test case: connect to server, set a default watcher, disconnect from the server\n    // verify: the default watcher is called once\n    void testDefaultSessionWatcher2(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_SESSION_EVENT,ZOO_CONNECTING_STATE);\n        DisconnectWatcher watcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &watcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n        // set a default watch\n        AsyncCompletion ignored;\n        // a successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        int rc=zoo_aexists(zh,\"/x/y/z\",1,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        // now, initiate a disconnect\n        zkServer.setConnectionLost();\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n        \n        // verify the watcher has been triggered\n        CPPUNIT_ASSERT(watcher.disconnected_);\n        // triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,watcher.counter_);\n    }\n\n    // testcase: connect to the server, set a watcher object on a node, \n    //           disconnect from the server\n    // verify: the watcher object as well as the default watcher are called\n    void testObjectSessionWatcher1(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_SESSION_EVENT,ZOO_CONNECTING_STATE);\n        DisconnectWatcher defWatcher;\n        // use the tracker to find out when the watcher has been activated\n        WatcherActivationTracker activationTracker;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n\n        AsyncCompletion ignored;\n        // this successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        CountingDataWatcher wobject;\n        activationTracker.track(&wobject);\n        // set a path-specific watcher\n        int rc=zoo_awexists(zh,\"/x/y/z\",activeWatcher,&wobject,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // make sure the watcher gets activated before we continue\n        CPPUNIT_ASSERT(ensureCondition(activationTracker.isWatcherActivated(),1000)<1000);\n        \n        // now, initiate a disconnect\n        zkServer.setConnectionLost();\n        // make sure all watchers have been processed\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n        \n        // verify the default watcher has been triggered\n        CPPUNIT_ASSERT(defWatcher.disconnected_);\n        // and triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,defWatcher.counter_);\n        \n        // the path-specific watcher has been triggered as well\n        CPPUNIT_ASSERT(wobject.disconnected_);\n        // only once!\n        CPPUNIT_ASSERT_EQUAL(1,wobject.counter_);\n    }\n\n    // testcase: connect to the server, set a watcher object on a node, \n    //           set a def watcher on another node,disconnect from the server\n    // verify: the watcher object as well as the default watcher are called\n    void testObjectSessionWatcher2(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_SESSION_EVENT,ZOO_CONNECTING_STATE);\n        DisconnectWatcher defWatcher;\n        // use the tracker to find out when the watcher has been activated\n        WatcherActivationTracker activationTracker;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n\n        // set a default watch\n        AsyncCompletion ignored;\n        // a successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        activationTracker.track(&defWatcher);\n        int rc=zoo_aexists(zh,\"/a/b/c\",1,asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // make sure the watcher gets activated before we continue\n        CPPUNIT_ASSERT(ensureCondition(activationTracker.isWatcherActivated(),1000)<1000);\n\n        // this successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        CountingDataWatcher wobject;\n        activationTracker.track(&wobject);\n        // set a path-specific watcher\n        rc=zoo_awexists(zh,\"/x/y/z\",activeWatcher,&wobject,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // make sure the watcher gets activated before we continue\n        CPPUNIT_ASSERT(ensureCondition(activationTracker.isWatcherActivated(),1000)<1000);\n        \n        // now, initiate a disconnect\n        zkServer.setConnectionLost();\n        // make sure all watchers have been processed\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n        \n        // verify the default watcher has been triggered\n        CPPUNIT_ASSERT(defWatcher.disconnected_);\n        // and triggered only once\n        CPPUNIT_ASSERT_EQUAL(1,defWatcher.counter_);\n        \n        // the path-specific watcher has been triggered as well\n        CPPUNIT_ASSERT(wobject.disconnected_);\n        // only once!\n        CPPUNIT_ASSERT_EQUAL(1,wobject.counter_);\n    }\n\n    // testcase: register 2 node watches for different paths, trigger the watches\n    // verify: the data watchers are processed, the default watcher is not called\n    void testNodeWatcher1(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_CHANGED_EVENT,0,false);\n        CountingDataWatcher defWatcher;\n        // use the tracker to find out when the watcher has been activated\n        WatcherActivationTracker activationTracker;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n\n        // don't care about completions\n        AsyncCompletion ignored;\n        // set a one-shot watch\n        // a successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        CountingDataWatcher wobject1;\n        activationTracker.track(&wobject1);\n        int rc=zoo_awexists(zh,\"/a/b/c\",activeWatcher,&wobject1,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // make sure the watcher gets activated before we continue\n        CPPUNIT_ASSERT(ensureCondition(activationTracker.isWatcherActivated(),1000)<1000);\n\n        // this successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        CountingDataWatcher wobject2;\n        activationTracker.track(&wobject2);\n        // set a path-specific watcher\n        rc=zoo_awexists(zh,\"/x/y/z\",activeWatcher,&wobject2,\n                asyncCompletion,&ignored);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // make sure the watcher gets activated before we continue\n        CPPUNIT_ASSERT(ensureCondition(activationTracker.isWatcherActivated(),1000)<1000);\n\n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/a/b/c\"));\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,\"/x/y/z\"));\n        // make sure all watchers have been processed\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.deliveryCounterEquals(2),1000)<1000);\n        \n        CPPUNIT_ASSERT_EQUAL(1,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n\n    // testcase: set up both a children and a data watchers on the node /a, then\n    //           delete the node (that is, send a DELETE_EVENT)\n    // verify: both watchers are triggered\n    void testChildWatcher1(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_DELETED_EVENT,0);\n        DeletionCountingDataWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n        \n        // a successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        DeletionCountingDataWatcher wobject1;\n        Stat stat;\n        // add a node watch\n        int rc=zoo_wexists(zh,\"/a\",activeWatcher,&wobject1,&stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        typedef ZooGetChildrenResponse::StringVector ZooVector;\n        zkServer.addOperationResponse(new ZooGetChildrenResponse(\n                Util::CollectionBuilder<ZooVector>()(\"/a/1\")(\"/a/2\")\n                ));\n        DeletionCountingDataWatcher wobject2;\n        String_vector children;\n        rc=zoo_wget_children(zh,\"/a\",activeWatcher,&wobject2,&children);\n        deallocate_String_vector(&children);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_DELETED_EVENT,\"/a\"));\n        // make sure the watchers have been processed\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n\n        CPPUNIT_ASSERT_EQUAL(1,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n    \n    // testcase: create both a child and data watch on the node /a, send a ZOO_CHILD_EVENT\n    // verify: only the child watch triggered\n    void testChildWatcher2(){\n        Mock_gettimeofday timeMock;\n        // zookeeper simulator\n        ZookeeperServer zkServer;\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n        // must call zookeeper_close() while all the mocks are in the scope!\n        CloseFinally guard(&zh);\n        \n        // detects when all watchers have been delivered\n        WatcherDeliveryTracker deliveryTracker(ZOO_CHILD_EVENT,0);\n        ChildEventCountingWatcher defWatcher;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,TEST_CLIENT_ID,\n                &defWatcher,0);\n        CPPUNIT_ASSERT(zh!=0);\n        // make sure the client has connected\n        CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n        // a successful server response will activate the watcher \n        zkServer.addOperationResponse(new ZooStatResponse);\n        ChildEventCountingWatcher wobject1;\n        Stat stat;\n        // add a node watch\n        int rc=zoo_wexists(zh,\"/a\",activeWatcher,&wobject1,&stat);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        typedef ZooGetChildrenResponse::StringVector ZooVector;\n        zkServer.addOperationResponse(new ZooGetChildrenResponse(\n                Util::CollectionBuilder<ZooVector>()(\"/a/1\")(\"/a/2\")\n                ));\n        ChildEventCountingWatcher wobject2;\n        String_vector children;\n        rc=zoo_wget_children(zh,\"/a\",activeWatcher,&wobject2,&children);\n        deallocate_String_vector(&children);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n\n        // we are all set now; let's trigger the watches\n        zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHILD_EVENT,\"/a\"));\n        // make sure the watchers have been processed\n        CPPUNIT_ASSERT(ensureCondition(\n                deliveryTracker.isWatcherProcessingCompleted(),1000)<1000);\n\n        CPPUNIT_ASSERT_EQUAL(0,wobject1.counter_);\n        CPPUNIT_ASSERT_EQUAL(1,wobject2.counter_);        \n        CPPUNIT_ASSERT_EQUAL(0,defWatcher.counter_);\n    }\n\n#endif //THREADED\n};\n\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_watchers);\n"
  },
  {
    "path": "src/c/tests/TestZookeeperClose.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n\n#include \"ZKMocks.h\"\n\n#ifdef THREADED\n#include \"PthreadMocks.h\"\n#endif\n\nusing namespace std;\n\nclass Zookeeper_close : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_close);\n#ifdef THREADED\n    CPPUNIT_TEST(testIOThreadStoppedOnExpire);\n#endif\n    CPPUNIT_TEST(testCloseUnconnected);\n    CPPUNIT_TEST(testCloseUnconnected1);\n    CPPUNIT_TEST(testCloseConnected1);\n    CPPUNIT_TEST(testCloseFromWatcher1);\n    CPPUNIT_TEST_SUITE_END();\n    zhandle_t *zh;\n    static void watcher(zhandle_t *, int, int, const char *,void*){}\n    FILE *logfile;\npublic: \n\n    Zookeeper_close() {\n      logfile = openlogfile(\"Zookeeper_close\");\n    }\n\n    ~Zookeeper_close() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n\n        zoo_deterministic_conn_order(0);\n        zh=0;\n    }\n    \n    void tearDown()\n    {\n        zookeeper_close(zh);\n    }\n\n    class CloseOnSessionExpired: public WatcherAction{\n    public:\n        CloseOnSessionExpired(bool callClose=true):\n            callClose_(callClose),rc(ZOK){}\n        virtual void onSessionExpired(zhandle_t* zh){\n            memcpy(&lzh,zh,sizeof(lzh));\n            if(callClose_)\n                rc=zookeeper_close(zh);\n        }\n        zhandle_t lzh;\n        bool callClose_;\n        int rc;\n    };\n    \n#ifndef THREADED\n    void testCloseUnconnected()\n    {       \n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,0,0,0);       \n        CPPUNIT_ASSERT(zh!=0);\n        \n        // do not actually free the memory while in zookeeper_close()\n        Mock_free_noop freeMock;\n        // make a copy of zhandle before close() overwrites some of \n        // it members with NULLs\n        zhandle_t lzh;\n        memcpy(&lzh,zh,sizeof(lzh));\n        int rc=zookeeper_close(zh);\n        zhandle_t* savezh=zh; zh=0;\n        freeMock.disable(); // disable mock's fake free()- use libc's free() instead\n        \n        // verify that zookeeper_close has done its job\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // memory\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.hostname));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.addrs));\n        // This cannot be maintained properly CPPUNIT_ASSERT_EQUAL(9,freeMock.callCounter);\n    }\n    void testCloseUnconnected1()\n    {\n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,0,0,0);       \n        CPPUNIT_ASSERT(zh!=0);\n        // simulate connected state \n        zh->fd=ZookeeperServer::FD;\n        zh->state=ZOO_CONNECTED_STATE;\n        Mock_flush_send_queue zkMock;\n        // do not actually free the memory while in zookeeper_close()\n        Mock_free_noop freeMock;\n        // make a copy of zhandle before close() overwrites some of \n        // it members with NULLs\n        zhandle_t lzh;\n        memcpy(&lzh,zh,sizeof(lzh));\n        int rc=zookeeper_close(zh);\n        zhandle_t* savezh=zh; zh=0;\n        freeMock.disable(); // disable mock's fake free()- use libc's free() instead\n\n        // verify that zookeeper_close has done its job\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // memory\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.hostname));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.addrs));\n        // the close request sent?\n        CPPUNIT_ASSERT_EQUAL(1,zkMock.counter);\n    }\n    void testCloseConnected1()\n    {\n        ZookeeperServer zkServer;\n        // poll() will called from zookeeper_close()\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n\n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0);\n        CPPUNIT_ASSERT(zh!=0);\n\n        Mock_gettimeofday timeMock;\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        \n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_CONNECTING_STATE,zoo_state(zh));\n        CPPUNIT_ASSERT_EQUAL(ZOOKEEPER_READ|ZOOKEEPER_WRITE,interest);\n        \n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_ASSOCIATING_STATE,zoo_state(zh));\n        \n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        rc=zookeeper_process(zh,interest);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_CONNECTED_STATE,zoo_state(zh));\n        // do not actually free the memory while in zookeeper_close()\n        Mock_free_noop freeMock;\n        // make a copy of zhandle before close() overwrites some of \n        // it members with NULLs\n        zhandle_t lzh;\n        memcpy(&lzh,zh,sizeof(lzh));\n        zookeeper_close(zh);\n        zhandle_t* savezh=zh; zh=0;\n        freeMock.disable(); // disable mock's fake free()- use libc's free() instead\n        // memory\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.hostname));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.addrs));\n        // the close request sent?\n        CPPUNIT_ASSERT_EQUAL(1,(int)zkServer.closeSent);\n    }\n    void testCloseFromWatcher1()\n    {\n        Mock_gettimeofday timeMock;\n\n        ZookeeperServer zkServer;\n        // make the server return a non-matching session id\n        zkServer.returnSessionExpired();\n        // poll() will called from zookeeper_close()\n        Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n\n        CloseOnSessionExpired closeAction;\n        zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,\n                TEST_CLIENT_ID,&closeAction,0);\n        CPPUNIT_ASSERT(zh!=0);\n        \n        int fd=0;\n        int interest=0;\n        timeval tv;\n        // initiate connection\n        int rc=zookeeper_interest(zh,&fd,&interest,&tv);        \n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_CONNECTING_STATE,zoo_state(zh));\n        CPPUNIT_ASSERT_EQUAL(ZOOKEEPER_READ|ZOOKEEPER_WRITE,interest);\n        rc=zookeeper_process(zh,interest);\n        // make sure the handshake in progress \n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);        \n        CPPUNIT_ASSERT_EQUAL(ZOO_ASSOCIATING_STATE,zoo_state(zh));\n        rc=zookeeper_interest(zh,&fd,&interest,&tv);\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        \n        // do not actually free the memory while in zookeeper_close()\n        Mock_free_noop freeMock;\n        // should call the watcher with ZOO_EXPIRED_SESSION_STATE state\n        rc=zookeeper_process(zh,interest);\n        zhandle_t* savezh=zh; zh=0;\n        freeMock.disable(); // disable mock's fake free()- use libc's free() instead\n        \n        CPPUNIT_ASSERT_EQUAL(ZOO_EXPIRED_SESSION_STATE,zoo_state(savezh));\n        // memory\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.hostname));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.addrs));\n        // make sure the close request NOT sent\n        CPPUNIT_ASSERT_EQUAL(0,(int)zkServer.closeSent);\n    }\n#else\n    void testCloseUnconnected()\n    {\n        // disable threading\n        MockPthreadZKNull pthreadMock;\n        zh=zookeeper_init(\"localhost:2121\",watcher,10000,0,0,0); \n        \n        CPPUNIT_ASSERT(zh!=0);\n        adaptor_threads* adaptor=(adaptor_threads*)zh->adaptor_priv;\n        CPPUNIT_ASSERT(adaptor!=0);\n\n        // do not actually free the memory while in zookeeper_close()\n        Mock_free_noop freeMock;\n        // make a copy of zhandle before close() overwrites some of \n        // it members with NULLs\n        zhandle_t lzh;\n        memcpy(&lzh,zh,sizeof(lzh));\n        int rc=zookeeper_close(zh);\n        zhandle_t* savezh=zh; zh=0;\n        // we're done, disable mock's fake free(), use libc's free() instead\n        freeMock.disable();\n        \n        // verify that zookeeper_close has done its job\n        CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        // memory\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.hostname));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.addrs));\n        CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(adaptor));\n        // Cannot be maintained accurately: CPPUNIT_ASSERT_EQUAL(10,freeMock.callCounter);\n        // threads\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(adaptor->io));\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(adaptor->completion));\n        // mutexes\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->to_process.lock));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->to_process.lock));\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->to_send.lock));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->to_send.lock));\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->sent_requests.lock));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->sent_requests.lock));\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->completions_to_process.lock));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->completions_to_process.lock));\n        // conditionals\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->sent_requests.cond));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->sent_requests.cond));\n        CPPUNIT_ASSERT_EQUAL(1,MockPthreadsNull::getDestroyCounter(&savezh->completions_to_process.cond));\n        CPPUNIT_ASSERT_EQUAL(0,MockPthreadsNull::getInvalidAccessCounter(&savezh->completions_to_process.cond));\n    }\n    void testCloseUnconnected1()\n    {\n        for(int i=0; i<100;i++){\n            zh=zookeeper_init(\"localhost:2121\",watcher,10000,0,0,0); \n            CPPUNIT_ASSERT(zh!=0);\n            adaptor_threads* adaptor=(adaptor_threads*)zh->adaptor_priv;\n            CPPUNIT_ASSERT(adaptor!=0);\n            int rc=zookeeper_close(zh);\n            zh=0;\n            CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);\n        }\n    }\n    void testCloseConnected1()\n    {\n        // frozen time -- no timeouts and no pings\n        Mock_gettimeofday timeMock;\n\n        for(int i=0;i<100;i++){\n            ZookeeperServer zkServer;\n            Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n            // use a checked version of pthread calls\n            CheckedPthread threadMock;\n            // do not actually free the memory while in zookeeper_close()\n            Mock_free_noop freeMock;\n            \n            zh=zookeeper_init(\"localhost:2121\",watcher,10000,TEST_CLIENT_ID,0,0); \n            CPPUNIT_ASSERT(zh!=0);\n            // make sure the client has connected\n            CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);\n            // make a copy of zhandle before close() overwrites some of \n            // its members with NULLs\n            zhandle_t lzh;\n            memcpy(&lzh,zh,sizeof(lzh));\n            int rc=zookeeper_close(zh);\n            zhandle_t* savezh=zh; zh=0;\n            // we're done, disable mock's fake free(), use libc's free() instead\n            freeMock.disable();\n            \n            CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);            \n            adaptor_threads* adaptor=(adaptor_threads*)lzh.adaptor_priv;\n            // memory\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.hostname));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh.addrs));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(adaptor));\n            // threads\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->io));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->completion));\n            // mutexes\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->completions_to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->completions_to_process.lock));\n            // conditionals\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&savezh->completions_to_process.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&savezh->completions_to_process.cond));\n        }\n    }\n    \n    struct PointerFreed{\n        PointerFreed(Mock_free_noop& freeMock,void* ptr):\n            freeMock_(freeMock),ptr_(ptr){}\n        bool operator()() const{return freeMock_.isFreed(ptr_); }\n        Mock_free_noop& freeMock_;\n        void* ptr_;\n    };\n    // test if zookeeper_close may be called from a watcher callback on\n    // SESSION_EXPIRED event\n    void testCloseFromWatcher1()\n    {\n        // frozen time -- no timeouts and no pings\n        Mock_gettimeofday timeMock;\n        \n        for(int i=0;i<100;i++){\n            ZookeeperServer zkServer;\n            // make the server return a non-matching session id\n            zkServer.returnSessionExpired();\n            \n            Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n            // use a checked version of pthread calls\n            CheckedPthread threadMock;\n            // do not actually free the memory while in zookeeper_close()\n            Mock_free_noop freeMock;\n\n            CloseOnSessionExpired closeAction;\n            zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,\n                    TEST_CLIENT_ID,&closeAction,0);\n            \n            CPPUNIT_ASSERT(zh!=0);\n            // we rely on the fact that zh is freed the last right before\n            // zookeeper_close() returns...\n            CPPUNIT_ASSERT(ensureCondition(PointerFreed(freeMock,zh),1000)<1000);\n            zhandle_t* lzh=zh;\n            zh=0;\n            // we're done, disable mock's fake free(), use libc's free() instead\n            freeMock.disable();\n            \n            CPPUNIT_ASSERT_EQUAL((int)ZOK,closeAction.rc);          \n            adaptor_threads* adaptor=(adaptor_threads*)closeAction.lzh.adaptor_priv;\n            // memory\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.hostname));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.addrs));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(adaptor));\n            // threads\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->io));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->completion));\n            // mutexes\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->completions_to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->completions_to_process.lock));\n            // conditionals\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->completions_to_process.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->completions_to_process.cond));\n        }\n    }\n\n    void testIOThreadStoppedOnExpire()\n    {\n        // frozen time -- no timeouts and no pings\n        Mock_gettimeofday timeMock;\n        \n        for(int i=0;i<100;i++){\n            ZookeeperServer zkServer;\n            // make the server return a non-matching session id\n            zkServer.returnSessionExpired();\n            \n            Mock_poll pollMock(&zkServer,ZookeeperServer::FD);\n            // use a checked version of pthread calls\n            CheckedPthread threadMock;\n            // do not call zookeeper_close() from the watcher\n            CloseOnSessionExpired closeAction(false);\n            zh=zookeeper_init(\"localhost:2121\",activeWatcher,10000,\n                    &testClientId,&closeAction,0);\n            \n            // this is to ensure that if any assert fires, zookeeper_close() \n            // will still be called while all the mocks are in the scope!\n            CloseFinally guard(&zh);\n\n            CPPUNIT_ASSERT(zh!=0);\n            CPPUNIT_ASSERT(ensureCondition(SessionExpired(zh),1000)<1000);\n            CPPUNIT_ASSERT(ensureCondition(IOThreadStopped(zh),1000)<1000);\n            // make sure the watcher has been processed\n            CPPUNIT_ASSERT(ensureCondition(closeAction.isWatcherTriggered(),1000)<1000);\n            // make sure the threads have not been destroyed yet\n            adaptor_threads* adaptor=(adaptor_threads*)zh->adaptor_priv;\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getDestroyCounter(adaptor->io));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getDestroyCounter(adaptor->completion));\n            // about to call zookeeper_close() -- no longer need the guard\n            guard.disarm();\n            \n            // do not actually free the memory while in zookeeper_close()\n            Mock_free_noop freeMock;\n            zookeeper_close(zh);\n            zhandle_t* lzh=zh; zh=0;\n            // we're done, disable mock's fake free(), use libc's free() instead\n            freeMock.disable();\n            \n            // memory\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(lzh));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.hostname));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(closeAction.lzh.addrs));\n            CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(adaptor));\n            // threads\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->io));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(adaptor->completion));\n            // mutexes\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->to_send.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->sent_requests.lock));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->completions_to_process.lock));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->completions_to_process.lock));\n            // conditionals\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->sent_requests.cond));\n            CPPUNIT_ASSERT_EQUAL(1,CheckedPthread::getDestroyCounter(&lzh->completions_to_process.cond));\n            CPPUNIT_ASSERT_EQUAL(0,CheckedPthread::getInvalidAccessCounter(&lzh->completions_to_process.cond));\n        }\n    }\n\n#endif\n};\n\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_close);\n"
  },
  {
    "path": "src/c/tests/TestZookeeperInit.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n#include <sys/types.h>\n#include <netinet/in.h>\n#include <errno.h>\n\n#include \"Util.h\"\n#include \"LibCMocks.h\"\n#include \"ZKMocks.h\"\n\n#ifdef THREADED\n#include \"PthreadMocks.h\"\n#else\nclass MockPthreadsNull;\n#endif\n\nusing namespace std;\n\nclass Zookeeper_init : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_init);\n    CPPUNIT_TEST(testBasic);\n    CPPUNIT_TEST(testAddressResolution);\n    CPPUNIT_TEST(testMultipleAddressResolution);\n    CPPUNIT_TEST(testNullAddressString);\n    CPPUNIT_TEST(testEmptyAddressString);\n    CPPUNIT_TEST(testOneSpaceAddressString);\n    CPPUNIT_TEST(testTwoSpacesAddressString);\n    CPPUNIT_TEST(testInvalidAddressString1);\n    CPPUNIT_TEST(testInvalidAddressString2);\n    CPPUNIT_TEST(testNonexistentHost);\n    CPPUNIT_TEST(testOutOfMemory_init);\n    CPPUNIT_TEST(testOutOfMemory_getaddrs1);\n#if !defined(__CYGWIN__) // not valid for cygwin\n    CPPUNIT_TEST(testOutOfMemory_getaddrs2);\n#endif\n    CPPUNIT_TEST(testPermuteAddrsList);\n    CPPUNIT_TEST_SUITE_END();\n    zhandle_t *zh;\n    MockPthreadsNull* pthreadMock;\n    static void watcher(zhandle_t *, int , int , const char *,void*){}\n    FILE *logfile;\npublic:\n    Zookeeper_init():zh(0),pthreadMock(0){\n      logfile = openlogfile(\"Zookeeper_init\");\n    }\n\n    ~Zookeeper_init() {\n      if (logfile) {\n        fflush(logfile);\n        fclose(logfile);\n        logfile = 0;\n      }\n    }\n\n    void setUp()\n    {\n        zoo_set_log_stream(logfile);\n\n        zoo_deterministic_conn_order(0);\n#ifdef THREADED\n        // disable threading\n        pthreadMock=new MockPthreadZKNull;\n#endif\n        zh=0;\n    }\n\n    void tearDown()\n    {\n        zookeeper_close(zh);\n#ifdef THREADED\n        delete pthreadMock;\n#endif\n    }\n\n    void testBasic()\n    {\n        const string EXPECTED_HOST(\"127.0.0.1:2121\");\n        const int EXPECTED_ADDRS_COUNT =1;\n        const int EXPECTED_RECV_TIMEOUT=10000;\n        clientid_t cid;\n        memset(&cid,0xFE,sizeof(cid));\n\n        zh=zookeeper_init(EXPECTED_HOST.c_str(),watcher,EXPECTED_RECV_TIMEOUT,\n                &cid,(void*)1,0);\n\n        CPPUNIT_ASSERT(zh!=0);\n        CPPUNIT_ASSERT(zh->fd == -1);\n        CPPUNIT_ASSERT(zh->hostname!=0);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_ADDRS_COUNT,zh->addrs_count);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_HOST,string(zh->hostname));\n        CPPUNIT_ASSERT(zh->state == NOTCONNECTED_STATE_DEF);\n        CPPUNIT_ASSERT(zh->context == (void*)1);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_RECV_TIMEOUT,zh->recv_timeout);\n        CPPUNIT_ASSERT(zh->watcher == watcher);\n        CPPUNIT_ASSERT(zh->connect_index==0);\n        CPPUNIT_ASSERT(zh->primer_buffer.buffer==zh->primer_storage_buffer);\n        CPPUNIT_ASSERT(zh->primer_buffer.curr_offset ==0);\n        CPPUNIT_ASSERT(zh->primer_buffer.len == sizeof(zh->primer_storage_buffer));\n        CPPUNIT_ASSERT(zh->primer_buffer.next == 0);\n        CPPUNIT_ASSERT(zh->last_zxid ==0);\n        CPPUNIT_ASSERT(memcmp(&zh->client_id,&cid,sizeof(cid))==0);\n\n#ifdef THREADED\n        // thread specific checks\n        adaptor_threads* adaptor=(adaptor_threads*)zh->adaptor_priv;\n        CPPUNIT_ASSERT(adaptor!=0);\n        CPPUNIT_ASSERT(pthreadMock->pthread_createCounter==2);\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(adaptor->io));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(adaptor->completion));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->to_process.lock));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->to_send.lock));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->sent_requests.lock));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->completions_to_process.lock));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->sent_requests.cond));\n        CPPUNIT_ASSERT(MockPthreadsNull::isInitialized(&zh->completions_to_process.cond));\n#endif\n    }\n    void testAddressResolution()\n    {\n        const char EXPECTED_IPS[][4]={{127,0,0,1}};\n        const int EXPECTED_ADDRS_COUNT =COUNTOF(EXPECTED_IPS);\n\n        zoo_deterministic_conn_order(1);\n        zh=zookeeper_init(\"127.0.0.1:2121\",0,10000,0,0,0);\n\n        CPPUNIT_ASSERT(zh!=0);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_ADDRS_COUNT,zh->addrs_count);\n        for(int i=0;i<zh->addrs_count;i++){\n            sockaddr_in* addr=(struct sockaddr_in*)&zh->addrs[i];\n            CPPUNIT_ASSERT(memcmp(EXPECTED_IPS[i],&addr->sin_addr,sizeof(addr->sin_addr))==0);\n            CPPUNIT_ASSERT_EQUAL(2121,(int)ntohs(addr->sin_port));\n        }\n    }\n    void testMultipleAddressResolution()\n    {\n        const string EXPECTED_HOST(\"127.0.0.1:2121,127.0.0.2:3434\");\n        const char EXPECTED_IPS[][4]={{127,0,0,1},{127,0,0,2}};\n        const int EXPECTED_ADDRS_COUNT =COUNTOF(EXPECTED_IPS);\n\n        zoo_deterministic_conn_order(1);\n        zh=zookeeper_init(EXPECTED_HOST.c_str(),0,1000,0,0,0);\n\n        CPPUNIT_ASSERT(zh!=0);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_ADDRS_COUNT,zh->addrs_count);\n\n        for(int i=0;i<zh->addrs_count;i++){\n            sockaddr_in* addr=(struct sockaddr_in*)&zh->addrs[i];\n            CPPUNIT_ASSERT(memcmp(EXPECTED_IPS[i],&addr->sin_addr,sizeof(addr->sin_addr))==0);\n            if(i<1)\n                CPPUNIT_ASSERT_EQUAL(2121,(int)ntohs(addr->sin_port));\n            else\n                CPPUNIT_ASSERT_EQUAL(3434,(int)ntohs(addr->sin_port));\n        }\n    }\n    void testMultipleAddressWithSpace()\n    { \n        const string EXPECTED_HOST(\"127.0.0.1:2121,  127.0.0.2:3434\");\n        const char EXPECTED_IPS[][4]={{127,0,0,1},{127,0,0,2}};\n        const int EXPECTED_ADDRS_COUNT =COUNTOF(EXPECTED_IPS);\n\n        zoo_deterministic_conn_order(1);\n        zh=zookeeper_init(EXPECTED_HOST.c_str(),0,1000,0,0,0);\n\n        CPPUNIT_ASSERT(zh!=0);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_ADDRS_COUNT,zh->addrs_count);\n\n        for(int i=0;i<zh->addrs_count;i++){\n            sockaddr_in* addr=(struct sockaddr_in*)&zh->addrs[i];\n            CPPUNIT_ASSERT(memcmp(EXPECTED_IPS[i],&addr->sin_addr,sizeof(addr->sin_addr))==0);\n            if(i<1)\n                CPPUNIT_ASSERT_EQUAL(2121,(int)ntohs(addr->sin_port));\n            else\n                CPPUNIT_ASSERT_EQUAL(3434,(int)ntohs(addr->sin_port));\n        }\n    }\n    void testNullAddressString()\n    {\n        zh=zookeeper_init(NULL,0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n    }\n    void testEmptyAddressString()\n    {\n        const string INVALID_HOST(\"\");\n        zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n    }\n    void testOneSpaceAddressString()\n    {\n        const string INVALID_HOST(\" \");\n        zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n    }\n    void testTwoSpacesAddressString()\n    {\n        const string INVALID_HOST(\"  \");\n        zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n    }\n    void testInvalidAddressString1()\n    {\n        const string INVALID_HOST(\"host1\");\n        zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n    }\n    void testInvalidAddressString2()\n    {\n        const string INVALID_HOST(\"host1:1111+host:123\");\n        zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT((ENOENT|EINVAL) & errno);\n    }\n    void testNonexistentHost()\n    {\n        const string EXPECTED_HOST(\"host1.blabadibla.bla.:1111\");\n\n        zh=zookeeper_init(EXPECTED_HOST.c_str(),0,0,0,0,0);\n\n        CPPUNIT_ASSERT(zh==0);\n        //With the switch to thread safe getaddrinfo, we don't get\n        //these global variables\n        //CPPUNIT_ASSERT_EQUAL(EINVAL,errno);\n        //CPPUNIT_ASSERT_EQUAL(HOST_NOT_FOUND,h_errno);\n    }\n    void testOutOfMemory_init()\n    {\n        Mock_calloc mock;\n        mock.callsBeforeFailure=0; // fail first calloc in init()\n\n        zh=zookeeper_init(\"ahost:123\",watcher,10000,0,0,0);\n\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(ENOMEM,errno);\n    }\n    void testOutOfMemory_getaddrs1()\n    {\n        Mock_realloc reallocMock;\n        reallocMock.callsBeforeFailure=0; // fail on first call to realloc\n\n        zh=zookeeper_init(\"127.0.0.1:123\",0,0,0,0,0);\n\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(ENOMEM,errno);\n    }\n    void testOutOfMemory_getaddrs2()\n    {\n        Mock_realloc reallocMock;\n        reallocMock.callsBeforeFailure=1; // fail on the second call to realloc\n\n        zh=zookeeper_init(\"127.0.0.1:123,127.0.0.2:123,127.0.0.3:123,127.0.0.4:123,127.0.0.5:123,127.0.0.6:123,127.0.0.7:123,127.0.0.8:123,127.0.0.9:123,127.0.0.10:123,127.0.0.11:123,127.0.0.12:123,127.0.0.13:123,127.0.0.14:123,127.0.0.15:123,127.0.0.16:123,127.0.0.17:123\",0,0,0,0,0);\n\n        CPPUNIT_ASSERT(zh==0);\n        CPPUNIT_ASSERT_EQUAL(ENOMEM,errno);\n    }\n    void testPermuteAddrsList()\n    {\n        const char EXPECTED[][5]={\"\\0\\0\\0\\0\",\"\\1\\1\\1\\1\",\"\\2\\2\\2\\2\",\"\\3\\3\\3\\3\"};\n        const int EXPECTED_ADDR_COUNT=COUNTOF(EXPECTED);\n\n        const int RAND_SEQ[]={0,1,1,-1};\n        const int RAND_SIZE=COUNTOF(RAND_SEQ);\n        Mock_random randomMock;\n        randomMock.randomReturns.assign(RAND_SEQ,RAND_SEQ+RAND_SIZE-1);\n        zh=zookeeper_init(\"0.0.0.0:123,1.1.1.1:123,2.2.2.2:123,3.3.3.3:123\",0,1000,0,0,0);\n\n        CPPUNIT_ASSERT(zh!=0);\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_ADDR_COUNT,zh->addrs_count);\n        const string EXPECTED_SEQ(\"3210\");\n        char ACTUAL_SEQ[EXPECTED_ADDR_COUNT+1]; ACTUAL_SEQ[EXPECTED_ADDR_COUNT]=0;\n        for(int i=0;i<zh->addrs_count;i++){\n            sockaddr_in* addr=(struct sockaddr_in*)&zh->addrs[i];\n            // match the first byte of the EXPECTED and of the actual address\n            ACTUAL_SEQ[i]=((char*)&addr->sin_addr)[0]+'0';\n        }\n        CPPUNIT_ASSERT_EQUAL(EXPECTED_SEQ,string(ACTUAL_SEQ));\n    }\n};\n\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_init);\n"
  },
  {
    "path": "src/c/tests/ThreadingUtil.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <sys/types.h>\n#include \"ThreadingUtil.h\"\n#include \"LibCSymTable.h\"\n\n#ifdef THREADED\n\n// ****************************************************************************\n// Mutex wrapper\nstruct Mutex::Impl{\n    Impl(){\n        LIBC_SYMBOLS.pthread_mutex_init(&mut_, 0);        \n    }\n    ~Impl(){\n        LIBC_SYMBOLS.pthread_mutex_destroy(&mut_);        \n    }\n    pthread_mutex_t mut_;\n};\n\nMutex::Mutex():impl_(new Impl) {}\nMutex::~Mutex() { delete impl_;}\nvoid Mutex::acquire() {\n    LIBC_SYMBOLS.pthread_mutex_lock(&impl_->mut_);\n}\nvoid Mutex::release() {\n    LIBC_SYMBOLS.pthread_mutex_unlock(&impl_->mut_);\n}\n\n// ****************************************************************************\n// Atomics\nint32_t atomic_post_incr(volatile int32_t* operand, int32_t incr)\n{\n#if defined(__GNUC__)\n    return __sync_fetch_and_add(operand,incr);\n#else\n    int32_t result;\n    __asm__ __volatile__(\n         \"lock xaddl %0,%1\\n\"\n         : \"=r\"(result), \"=m\"(*operand)\n         : \"0\"(incr)\n         : \"memory\");\n   return result;\n#endif\n}\nint32_t atomic_fetch_store(volatile int32_t *ptr, int32_t value)\n{\n#if defined(__GNUC__)\n    return __sync_lock_test_and_set(ptr,value);\n#else\n    int32_t result;\n    __asm__ __volatile__(\"lock xchgl %0,%1\\n\"\n                          : \"=r\"(result), \"=m\"(*ptr)\n                          : \"0\"(value)\n                          : \"memory\");\n   return result; \n#endif\n}\n#else\nint32_t atomic_post_incr(volatile int32_t* operand, int32_t incr){\n    int32_t v=*operand;\n    *operand+=incr;\n    return v;\n}\nint32_t atomic_fetch_store(volatile int32_t *ptr, int32_t value)\n{\n    int32_t result=*ptr;\n    *ptr=value;\n    return result;\n}\n#endif // THREADED\n"
  },
  {
    "path": "src/c/tests/ThreadingUtil.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef THREADINGUTIL_H_\n#define THREADINGUTIL_H_\n\n#include <vector>\n\n#ifdef THREADED\n#include \"pthread.h\"\n#endif\n\n// *****************************************************************************\n// Threading primitives\n\n// atomic post-increment; returns the previous value of the operand\nint32_t atomic_post_incr(volatile int32_t* operand, int32_t incr);\n// atomic fetch&store; returns the previous value of the operand\nint32_t atomic_fetch_store(volatile int32_t *operand, int32_t value);\n\n// a partial implementation of an atomic integer type\nclass AtomicInt{\npublic:\n    explicit AtomicInt(int32_t init=0):v_(init){}\n    AtomicInt(const AtomicInt& other):v_(other){}\n    // assigment\n    AtomicInt& operator=(const AtomicInt& lhs){\n        atomic_fetch_store(&v_,lhs);\n        return *this;\n    }\n    AtomicInt& operator=(int32_t i){\n        atomic_fetch_store(&v_,i);\n        return *this;\n    }\n    // pre-increment\n    AtomicInt& operator++() {\n        atomic_post_incr(&v_,1);\n        return *this;\n    }\n    // pre-decrement\n    AtomicInt& operator--() {\n        atomic_post_incr(&v_,-1);\n        return *this;\n    }\n    // post-increment\n    AtomicInt operator++(int){\n        return AtomicInt(atomic_post_incr(&v_,1));\n    }\n    // post-decrement\n    AtomicInt operator--(int){\n        return AtomicInt(atomic_post_incr(&v_,-1));\n    }\n    \n    operator int() const{\n        return atomic_post_incr(&v_,0);\n    }\n    int get() const{\n        return atomic_post_incr(&v_,0);\n    }\nprivate:\n    mutable int32_t v_;\n};\n\n#ifdef THREADED\n// ****************************************************************************\n#define VALIDATE_JOBS(jm) jm.validateJobs(__FILE__,__LINE__)\n#define VALIDATE_JOB(j) j.validate(__FILE__,__LINE__)\n\nclass Mutex{\npublic:\n    Mutex();\n    ~Mutex();\n    void acquire();\n    void release();\nprivate:\n    Mutex(const Mutex&);\n    Mutex& operator=(const Mutex&);\n    struct Impl;\n    Impl* impl_;\n};\n\nclass MTLock{\npublic:\n    MTLock(Mutex& m):m_(m){m.acquire();}\n    ~MTLock(){m_.release();}\n    Mutex& m_;\n};\n\n#define synchronized(m) MTLock __lock(m)\n\n// ****************************************************************************\nclass Latch {\npublic:\n    virtual ~Latch() {}\n    virtual void await() const =0;\n    virtual void signalAndWait() =0;\n    virtual void signal() =0;\n};\n\nclass CountDownLatch: public Latch {\npublic:\n    CountDownLatch(int count):count_(count) {\n        pthread_cond_init(&cond_,0);\n        pthread_mutex_init(&mut_,0);\n    }\n    virtual ~CountDownLatch() {\n        pthread_mutex_lock(&mut_);\n        if(count_!=0) {\n            count_=0;\n            pthread_cond_broadcast(&cond_);\n        }\n        pthread_mutex_unlock(&mut_);\n\n        pthread_cond_destroy(&cond_);\n        pthread_mutex_destroy(&mut_);\n    }\n\n    virtual void await() const {\n        pthread_mutex_lock(&mut_);\n        awaitImpl();\n        pthread_mutex_unlock(&mut_);\n    }\n    virtual void signalAndWait() {\n        pthread_mutex_lock(&mut_);\n        signalImpl();\n        awaitImpl();\n        pthread_mutex_unlock(&mut_);\n    }\n    virtual void signal() {\n        pthread_mutex_lock(&mut_);\n        signalImpl();\n        pthread_mutex_unlock(&mut_);\n    }\nprivate:\n    void awaitImpl() const{\n        while(count_!=0)\n        pthread_cond_wait(&cond_,&mut_);\n    }\n    void signalImpl() {\n        if(count_>0) {\n            count_--;\n            pthread_cond_broadcast(&cond_);\n        }\n    }\n    int count_;\n    mutable pthread_mutex_t mut_;\n    mutable pthread_cond_t cond_;\n};\n\nclass TestJob {\npublic:\n    typedef long JobId;\n    TestJob():hasRun_(false),startLatch_(0),endLatch_(0) {}\n    virtual ~TestJob() {\n        join();\n    }\n    virtual TestJob* clone() const =0;\n\n    virtual void run() =0;\n    virtual void validate(const char* file, int line) const =0;\n\n    virtual void start(Latch* startLatch=0,Latch* endLatch=0) {\n        startLatch_=startLatch;endLatch_=endLatch;\n        hasRun_=true;\n        pthread_create(&thread_, 0, thread, this);\n    }\n    virtual JobId getJobId() const {\n        return (JobId)thread_;\n    }\n    virtual void join() {\n        if(!hasRun_)\n        return;\n        if(!pthread_equal(thread_,pthread_self()))\n        pthread_join(thread_,0);\n        else\n        pthread_detach(thread_);\n    }\nprivate:\n    void awaitStart() {\n        if(startLatch_==0) return;\n        startLatch_->signalAndWait();\n    }\n    void signalFinished() {\n        if(endLatch_==0) return;\n        endLatch_->signal();\n    }\n    static void* thread(void* p) {\n        TestJob* j=(TestJob*)p;\n        j->awaitStart(); // wait for the start command\n        j->run();\n        j->signalFinished();\n        return 0;\n    }\n    bool hasRun_;\n    Latch* startLatch_;\n    Latch* endLatch_;\n    pthread_t thread_;\n};\n\nclass TestJobManager {\n    typedef std::vector<TestJob*> JobList;\npublic:\n    TestJobManager(const TestJob& tj,int threadCount=1):\n        startLatch_(threadCount),endLatch_(threadCount)\n    {\n        for(int i=0;i<threadCount;++i)\n            jobs_.push_back(tj.clone());\n    }\n    virtual ~TestJobManager(){\n        for(unsigned  i=0;i<jobs_.size();++i)\n            delete jobs_[i];\n    }\n    \n    virtual void startAllJobs() {\n        for(unsigned i=0;i<jobs_.size();++i)\n            jobs_[i]->start(&startLatch_,&endLatch_);\n    }\n    virtual void startJobsImmediately() {\n        for(unsigned i=0;i<jobs_.size();++i)\n            jobs_[i]->start(0,&endLatch_);\n    }\n    virtual void wait() const {\n        endLatch_.await();\n    }\n    virtual void validateJobs(const char* file, int line) const{\n        for(unsigned i=0;i<jobs_.size();++i)\n            jobs_[i]->validate(file,line);        \n    }\nprivate:\n    JobList jobs_;\n    CountDownLatch startLatch_;\n    CountDownLatch endLatch_;\n};\n\n#else // THREADED\n// single THREADED\nclass Mutex{\npublic:\n    void acquire(){}\n    void release(){}\n};\n#define synchronized(m)\n\n#endif // THREADED\n\n#endif /*THREADINGUTIL_H_*/\n"
  },
  {
    "path": "src/c/tests/Util.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"Util.h\"\n#include \"string.h\"\n\nconst std::string EMPTY_STRING;\n\nTestConfig globalTestConfig;\n\nvoid millisleep(int ms){\n    timespec ts;\n    ts.tv_sec=ms/1000;\n    ts.tv_nsec=(ms%1000)*1000000; // to nanoseconds\n    nanosleep(&ts,0);\n}\n\nFILE *openlogfile(const char* testname) {\n  char name[1024];\n  strcpy(name, \"TEST-\");\n  strncpy(name + 5, testname, sizeof(name) - 5);\n#ifdef THREADED\n  strcpy(name + strlen(name), \"-mt.txt\");\n#else\n  strcpy(name + strlen(name), \"-st.txt\");\n#endif\n\n  FILE *logfile = fopen(name, \"a\");\n\n  if (logfile == 0) {\n    fprintf(stderr, \"Can't open log file %s!\\n\", name);\n    return 0;\n  }\n\n  return logfile;\n}\n"
  },
  {
    "path": "src/c/tests/Util.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UTIL_H_\n#define UTIL_H_\n\n#include <map>\n#include <vector>\n#include <string>\n\n#include \"zookeeper_log.h\"\n\n// number of elements in array\n#define COUNTOF(array) sizeof(array)/sizeof(array[0])\n\n#define DECLARE_WRAPPER(ret,sym,sig) \\\n    extern \"C\" ret __real_##sym sig; \\\n    extern \"C\" ret __wrap_##sym sig\n\n#define CALL_REAL(sym,params) \\\n    __real_##sym params\n\n// must include \"src/zookeeper_log.h\" to be able to use this macro\n#define TEST_TRACE(x) \\\n    log_message(ZOO_LOG_LEVEL_DEBUG,__LINE__,__func__,format_log_message x)\n\nextern const std::string EMPTY_STRING;\n\n// *****************************************************************************\n// A bit of wizardry to get to the bare type from a reference or a pointer \n// to the type\ntemplate <class T>\nstruct TypeOp {\n    typedef T BareT;\n    typedef T ArgT;\n};\n\n// partial specialization for reference types\ntemplate <class T>\nstruct TypeOp<T&>{\n    typedef T& ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// partial specialization for pointers\ntemplate <class T>\nstruct TypeOp<T*>{\n    typedef T* ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// *****************************************************************************\n// Container utilities\n\ntemplate <class K, class V>\nvoid putValue(std::map<K,V>& map,const K& k, const V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        map.insert(typename Map::value_type(k,v));\n    else\n        map[k]=v;\n}\n\ntemplate <class K, class V>\nbool getValue(const std::map<K,V>& map,const K& k,V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        return false;\n    v=it->second;\n    return true;\n}\n\n// *****************************************************************************\n// misc utils\n\n// millisecond sleep\nvoid millisleep(int ms);\nFILE *openlogfile(const char* name);\n// evaluate given predicate until it returns true or the timeout \n// (in millis) has expired\ntemplate<class Predicate>\nint ensureCondition(const Predicate& p,int timeout){\n    int elapsed=0;\n    while(!p() && elapsed<timeout){\n        millisleep(2);\n        elapsed+=2;\n    }\n    return elapsed;\n};\n\n// *****************************************************************************\n// test global configuration data \nclass TestConfig{\n    typedef std::vector<std::string> CmdLineOptList;\npublic:\n    typedef CmdLineOptList::const_iterator const_iterator;\n    TestConfig(){}\n    ~TestConfig(){}\n    void addConfigFromCmdLine(int argc, char* argv[]){\n        if(argc>=2)\n            testName_=argv[1];\n        for(int i=2; i<argc;++i)\n            cmdOpts_.push_back(argv[i]);\n    }\n    const_iterator getExtraOptBegin() const {return cmdOpts_.begin();}\n    const_iterator getExtraOptEnd() const {return cmdOpts_.end();}\n    size_t getExtraOptCount() const {\n        return cmdOpts_.size();\n    }\n    const std::string& getTestName() const {\n        return testName_==\"all\"?EMPTY_STRING:testName_;\n    }\nprivate:\n    CmdLineOptList cmdOpts_;\n    std::string testName_;\n};\n\nextern TestConfig globalTestConfig;\n\n#endif /*UTIL_H_*/\n"
  },
  {
    "path": "src/c/tests/Vector.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef _VECTOR_UTIL_H\n#define _VECTOR_UTIL_H\n\n#include <vector>\n\n// function to conveniently stream vectors\ntemplate <class U>\nstd::ostream& operator<<(std::ostream& os,const std::vector<U>& c){\n  typedef std::vector<U> V;\n  os<<\"[\";\n  if(c.size()>0){\n      for(typename V::const_iterator it=c.begin();it!=c.end();++it)\n          os<<*it<<\",\";\n      os.seekp(-1,std::ios::cur);\n  }\n  os<<\"]\";\n  return os;\n}\n\n#endif // _VECTOR_UTIL_H\n"
  },
  {
    "path": "src/c/tests/ZKMocks.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <arpa/inet.h>  // for htonl\n#include <memory>\n\n#include <zookeeper.h>\n#include <proto.h>\n\n#ifdef THREADED\n#include \"PthreadMocks.h\"\n#endif\n#include \"ZKMocks.h\"\n\nusing namespace std;\n\nTestClientId testClientId;\nconst char* TestClientId::PASSWD=\"1234567890123456\";\n\nHandshakeRequest* HandshakeRequest::parse(const std::string& buf){\n    auto_ptr<HandshakeRequest> req(new HandshakeRequest);\n\n    memcpy(&req->protocolVersion,buf.data(), sizeof(req->protocolVersion));\n    req->protocolVersion = htonl(req->protocolVersion);\n    \n    int offset=sizeof(req->protocolVersion);\n    \n    memcpy(&req->lastZxidSeen,buf.data()+offset,sizeof(req->lastZxidSeen));\n    req->lastZxidSeen = zoo_htonll(req->lastZxidSeen);\n    offset+=sizeof(req->lastZxidSeen);\n    \n    memcpy(&req->timeOut,buf.data()+offset,sizeof(req->timeOut));\n    req->timeOut = htonl(req->timeOut);\n    offset+=sizeof(req->timeOut);\n    \n    memcpy(&req->sessionId,buf.data()+offset,sizeof(req->sessionId));\n    req->sessionId = zoo_htonll(req->sessionId);\n    offset+=sizeof(req->sessionId);\n    \n    memcpy(&req->passwd_len,buf.data()+offset,sizeof(req->passwd_len));\n    req->passwd_len = htonl(req->passwd_len);\n    offset+=sizeof(req->passwd_len);\n    \n    memcpy(req->passwd,buf.data()+offset,sizeof(req->passwd));\n    if(testClientId.client_id==req->sessionId &&\n            !memcmp(testClientId.passwd,req->passwd,sizeof(req->passwd)))\n        return req.release();\n    // the request didn't match -- may not be a handshake request after all\n    return 0;\n}\n\n// *****************************************************************************\n// watcher action implementation\nvoid activeWatcher(zhandle_t *zh, int type, int state, const char *path,void* ctx){\n    if(zh==0 || ctx==0) return;\n    WatcherAction* action=(WatcherAction*)ctx;\n    \n    if(type==ZOO_SESSION_EVENT){\n        if(state==ZOO_EXPIRED_SESSION_STATE)\n            action->onSessionExpired(zh);\n        else if(state==ZOO_CONNECTING_STATE)\n            action->onConnectionLost(zh);\n        else if(state==ZOO_CONNECTED_STATE)\n            action->onConnectionEstablished(zh);\n    }else if(type==ZOO_CHANGED_EVENT)\n        action->onNodeValueChanged(zh,path);\n    else if(type==ZOO_DELETED_EVENT)\n        action->onNodeDeleted(zh,path);\n    else if(type==ZOO_CHILD_EVENT)\n        action->onChildChanged(zh,path);\n    // TODO: implement for the rest of the event types\n    // ...\n    action->setWatcherTriggered();    \n}\nSyncedBoolCondition WatcherAction::isWatcherTriggered() const{\n    return SyncedBoolCondition(triggered_,mx_);\n}\n\n// *****************************************************************************\n// a set of async completion signatures\nvoid asyncCompletion(int rc, ACL_vector *acl,Stat *stat, const void *data){\n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->aclCompl(rc,acl,stat);\n}\nvoid asyncCompletion(int rc, const char *value, int len, const Stat *stat, \n        const void *data){    \n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->dataCompl(rc,value,len,stat);    \n}\nvoid asyncCompletion(int rc, const Stat *stat, const void *data){    \n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->statCompl(rc,stat);\n}\nvoid asyncCompletion(int rc, const char *value, const void *data){\n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->stringCompl(rc,value);\n}\nvoid asyncCompletion(int rc,const String_vector *strings, const void *data){    \n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->stringsCompl(rc,strings);\n}\nvoid asyncCompletion(int rc, const void *data){    \n    assert(\"Completion data is NULL\"&&data);\n    static_cast<AsyncCompletion*>((void*)data)->voidCompl(rc);\n}\n\n// *****************************************************************************\n// a predicate implementation\nbool IOThreadStopped::operator()() const{\n#ifdef THREADED\n    adaptor_threads* adaptor=(adaptor_threads*)zh_->adaptor_priv;\n    return CheckedPthread::isTerminated(adaptor->io);\n#else\n    assert(\"IOThreadStopped predicate is only for use with THREADED client\"&& false);\n    return false;\n#endif\n}\n\n//******************************************************************************\n//\nDECLARE_WRAPPER(int,flush_send_queue,(zhandle_t*zh, int timeout))\n{\n    if(!Mock_flush_send_queue::mock_)\n        return CALL_REAL(flush_send_queue,(zh,timeout));\n    return Mock_flush_send_queue::mock_->call(zh,timeout);\n}\n\nMock_flush_send_queue* Mock_flush_send_queue::mock_=0;\n\n//******************************************************************************\n//\nDECLARE_WRAPPER(int32_t,get_xid,())\n{\n    if(!Mock_get_xid::mock_)\n        return CALL_REAL(get_xid,());\n    return Mock_get_xid::mock_->call();\n}\n\nMock_get_xid* Mock_get_xid::mock_=0;\n\n//******************************************************************************\n// activateWatcher mock\n\nDECLARE_WRAPPER(void,activateWatcher,(zhandle_t *zh, watcher_registration_t* reg, int rc))\n{\n    if(!Mock_activateWatcher::mock_){\n        CALL_REAL(activateWatcher,(zh, reg,rc));\n    }else{\n        Mock_activateWatcher::mock_->call(zh, reg,rc);\n    }\n}\nMock_activateWatcher* Mock_activateWatcher::mock_=0;\n\nclass ActivateWatcherWrapper: public Mock_activateWatcher{\npublic:\n    ActivateWatcherWrapper():ctx_(0),activated_(false){}\n    \n    virtual void call(zhandle_t *zh, watcher_registration_t* reg, int rc){\n        CALL_REAL(activateWatcher,(zh, reg,rc));\n        synchronized(mx_);\n        if(reg->context==ctx_){\n            activated_=true;\n            ctx_=0;\n        }\n    }\n    \n    void setContext(void* ctx){\n        synchronized(mx_);\n        ctx_=ctx;\n        activated_=false;\n    }\n    \n    SyncedBoolCondition isActivated() const{\n        return SyncedBoolCondition(activated_,mx_);\n    }\n    mutable Mutex mx_;\n    void* ctx_;\n    bool activated_;\n};\n\nWatcherActivationTracker::WatcherActivationTracker():\n    wrapper_(new ActivateWatcherWrapper)\n{    \n}\n\nWatcherActivationTracker::~WatcherActivationTracker(){\n    delete wrapper_;\n}\n\nvoid WatcherActivationTracker::track(void* ctx){\n    wrapper_->setContext(ctx);\n}\n\nSyncedBoolCondition WatcherActivationTracker::isWatcherActivated() const{\n    return wrapper_->isActivated();\n}\n\n//******************************************************************************\n//\nDECLARE_WRAPPER(void,deliverWatchers,(zhandle_t* zh,int type,int state, const char* path, watcher_object_list_t **list))\n{\n    if(!Mock_deliverWatchers::mock_){\n        CALL_REAL(deliverWatchers,(zh,type,state,path, list));\n    }else{\n        Mock_deliverWatchers::mock_->call(zh,type,state,path, list);\n    }\n}\n\nMock_deliverWatchers* Mock_deliverWatchers::mock_=0;\n\nstruct RefCounterValue{\n    RefCounterValue(zhandle_t* const& zh,int32_t expectedCounter,Mutex& mx):\n        zh_(zh),expectedCounter_(expectedCounter),mx_(mx){}\n    bool operator()() const{\n        {\n            synchronized(mx_);\n            if(zh_==0)\n                return false;\n        }\n        return inc_ref_counter(zh_,0)==expectedCounter_;\n    }\n    zhandle_t* const& zh_;\n    int32_t expectedCounter_;\n    Mutex& mx_;\n};\n\n\nclass DeliverWatchersWrapper: public Mock_deliverWatchers{\npublic:\n    DeliverWatchersWrapper(int type,int state,bool terminate):\n        type_(type),state_(state),\n        allDelivered_(false),terminate_(terminate),zh_(0),deliveryCounter_(0){}\n    virtual void call(zhandle_t* zh,int type,int state, const char* path, watcher_object_list **list){\n        {\n            synchronized(mx_);\n            zh_=zh;\n            allDelivered_=false;\n        }\n        CALL_REAL(deliverWatchers,(zh,type,state,path, list));\n        if(type_==type && state_==state){\n            if(terminate_){\n                // prevent zhandle_t from being prematurely distroyed;\n                // this will also ensure that zookeeper_close() cleanups the thread\n                // resources by calling finish_adaptor()\n                inc_ref_counter(zh,1);\n                terminateZookeeperThreads(zh);\n            }\n            synchronized(mx_);\n            allDelivered_=true;\n            deliveryCounter_++;\n        }\n    }\n    SyncedBoolCondition isDelivered() const{\n        if(terminate_){\n            int i=ensureCondition(RefCounterValue(zh_,1,mx_),1000);\n            assert(i<1000);\n        }\n        return SyncedBoolCondition(allDelivered_,mx_);\n    }\n    void resetDeliveryCounter(){\n        synchronized(mx_);\n        deliveryCounter_=0;\n    }\n    SyncedIntegerEqual deliveryCounterEquals(int expected) const{\n        if(terminate_){\n            int i=ensureCondition(RefCounterValue(zh_,1,mx_),1000);\n            assert(i<1000);\n        }\n        return SyncedIntegerEqual(deliveryCounter_,expected,mx_);\n    }\n    int type_;\n    int state_;\n    mutable Mutex mx_;\n    bool allDelivered_;\n    bool terminate_;\n    zhandle_t* zh_;\n    int deliveryCounter_;\n};\n\nWatcherDeliveryTracker::WatcherDeliveryTracker(\n        int type,int state,bool terminateCompletionThread):\n    deliveryWrapper_(new DeliverWatchersWrapper(\n            type,state,terminateCompletionThread)){\n}\n\nWatcherDeliveryTracker::~WatcherDeliveryTracker(){\n    delete deliveryWrapper_;\n}\n\nSyncedBoolCondition WatcherDeliveryTracker::isWatcherProcessingCompleted() const{\n    return deliveryWrapper_->isDelivered();\n}\n\nvoid WatcherDeliveryTracker::resetDeliveryCounter(){\n    deliveryWrapper_->resetDeliveryCounter();\n}\n\nSyncedIntegerEqual WatcherDeliveryTracker::deliveryCounterEquals(int expected) const{\n    return deliveryWrapper_->deliveryCounterEquals(expected);\n}\n\n//******************************************************************************\n//\nstring HandshakeResponse::toString() const {\n    string buf;\n    int32_t tmp=htonl(protocolVersion);\n    buf.append((char*)&tmp,sizeof(tmp));\n    tmp=htonl(timeOut);\n    buf.append((char*)&tmp,sizeof(tmp));\n    int64_t tmp64=zoo_htonll(sessionId);\n    buf.append((char*)&tmp64,sizeof(sessionId));\n    tmp=htonl(passwd_len);\n    buf.append((char*)&tmp,sizeof(tmp));\n    buf.append(passwd,sizeof(passwd));\n    // finally set the buffer length\n    tmp=htonl(buf.size()+sizeof(tmp));\n    buf.insert(0,(char*)&tmp, sizeof(tmp));\n    return buf;\n}\n\nstring ZooGetResponse::toString() const{\n    oarchive* oa=create_buffer_oarchive();\n    \n    ReplyHeader h = {xid_,1,ZOK};\n    serialize_ReplyHeader(oa, \"hdr\", &h);\n    \n    GetDataResponse resp;\n\tchar buf[1024];\n    assert(\"GetDataResponse is too long\"&&data_.size()<=sizeof(buf));\n    resp.data.len=data_.size();\n    resp.data.buff=buf;\n    data_.copy(resp.data.buff, data_.size());\n    resp.stat=stat_;\n    serialize_GetDataResponse(oa, \"reply\", &resp);\n    int32_t len=htonl(get_buffer_len(oa));\n    string res((char*)&len,sizeof(len));\n    res.append(get_buffer(oa),get_buffer_len(oa));\n    \n    close_buffer_oarchive(&oa,1);\n    return res;\n}\n\nstring ZooStatResponse::toString() const{\n    oarchive* oa=create_buffer_oarchive();\n    \n    ReplyHeader h = {xid_,1,rc_};\n    serialize_ReplyHeader(oa, \"hdr\", &h);\n    \n    SetDataResponse resp;\n    resp.stat=stat_;\n    serialize_SetDataResponse(oa, \"reply\", &resp);\n    int32_t len=htonl(get_buffer_len(oa));\n    string res((char*)&len,sizeof(len));\n    res.append(get_buffer(oa),get_buffer_len(oa));\n    \n    close_buffer_oarchive(&oa,1);\n    return res;\n}\n\nstring ZooGetChildrenResponse::toString() const{\n    oarchive* oa=create_buffer_oarchive();\n    \n    ReplyHeader h = {xid_,1,rc_};\n    serialize_ReplyHeader(oa, \"hdr\", &h);\n \n    GetChildrenResponse resp;\n    // populate the string vector\n    allocate_String_vector(&resp.children,strings_.size());\n    for(int i=0;i<(int)strings_.size();++i)\n        resp.children.data[i]=strdup(strings_[i].c_str());\n    serialize_GetChildrenResponse(oa, \"reply\", &resp);\n    deallocate_GetChildrenResponse(&resp);\n    \n    int32_t len=htonl(get_buffer_len(oa));\n    string res((char*)&len,sizeof(len));\n    res.append(get_buffer(oa),get_buffer_len(oa));\n    \n    close_buffer_oarchive(&oa,1);\n    return res;\n}\n\nstring ZNodeEvent::toString() const{\n    oarchive* oa=create_buffer_oarchive();\n    struct WatcherEvent evt = {type_,0,(char*)path_.c_str()};\n    struct ReplyHeader h = {WATCHER_EVENT_XID,0,ZOK };\n    \n    serialize_ReplyHeader(oa, \"hdr\", &h);\n    serialize_WatcherEvent(oa, \"event\", &evt);\n    \n    int32_t len=htonl(get_buffer_len(oa));\n    string res((char*)&len,sizeof(len));\n    res.append(get_buffer(oa),get_buffer_len(oa));\n    \n    close_buffer_oarchive(&oa,1);\n    return res;\n}\n\nstring PingResponse::toString() const{\n    oarchive* oa=create_buffer_oarchive();\n    \n    ReplyHeader h = {PING_XID,1,ZOK};\n    serialize_ReplyHeader(oa, \"hdr\", &h);\n    \n    int32_t len=htonl(get_buffer_len(oa));\n    string res((char*)&len,sizeof(len));\n    res.append(get_buffer(oa),get_buffer_len(oa));\n    \n    close_buffer_oarchive(&oa,1);\n    return res;\n}\n\n//******************************************************************************\n// Zookeeper server simulator\n// \nbool ZookeeperServer::hasMoreRecv() const{\n  return recvHasMore.get()!=0  || connectionLost;\n}\n\nssize_t ZookeeperServer::callRecv(int s,void *buf,size_t len,int flags){\n    if(connectionLost){\n        recvReturnBuffer.erase();\n        return 0;\n    }\n    // done transmitting the current buffer?\n    if(recvReturnBuffer.size()==0){\n        synchronized(recvQMx);\n        if(recvQueue.empty()){\n            recvErrno=EAGAIN;\n            return Mock_socket::callRecv(s,buf,len,flags);\n        }\n        --recvHasMore;\n        Element& el=recvQueue.front();\n        if(el.first!=0){\n            recvReturnBuffer=el.first->toString();\n            delete el.first;\n        }\n        recvErrno=el.second;\n        recvQueue.pop_front();\n    }\n    return Mock_socket::callRecv(s,buf,len,flags);\n}\n\nvoid ZookeeperServer::onMessageReceived(const RequestHeader& rh, iarchive* ia){\n    // no-op by default\n}\n\nvoid ZookeeperServer::notifyBufferSent(const std::string& buffer){\n    if(HandshakeRequest::isValid(buffer)){\n        // could be a connect request\n        auto_ptr<HandshakeRequest> req(HandshakeRequest::parse(buffer));\n        if(req.get()!=0){\n            // handle the handshake\n            int64_t sessId=sessionExpired?req->sessionId+1:req->sessionId;\n            sessionExpired=false;\n            addRecvResponse(new HandshakeResponse(sessId));            \n            return;\n        }\n        // not a connect request -- fall thru\n    }\n    // parse the buffer to extract the request type and its xid\n    iarchive *ia=create_buffer_iarchive((char*)buffer.data(), buffer.size());\n    RequestHeader rh;\n    deserialize_RequestHeader(ia,\"hdr\",&rh);\n    // notify the \"server\" a client request has arrived\n    if (rh.xid == -8) {\n        Element e = Element(new ZooStatResponse,0);\n        e.first->setXID(-8);\n        addRecvResponse(e);\n        close_buffer_iarchive(&ia);\n        return;\n    } else {\n        onMessageReceived(rh,ia);\n    }\n    close_buffer_iarchive(&ia);\n    if(rh.type==ZOO_CLOSE_OP){\n        ++closeSent;\n        return; // no reply for close requests\n    }\n    // get the next response from the response queue and append it to the receive list\n    Element e;\n    {\n        synchronized(respQMx);\n        if(respQueue.empty())\n            return;\n        e=respQueue.front();\n        respQueue.pop_front();\n    }\n    e.first->setXID(rh.xid);\n    addRecvResponse(e);\n}\n\nvoid forceConnected(zhandle_t* zh){\n    // simulate connected state\n    zh->state=ZOO_CONNECTED_STATE;\n    zh->fd=ZookeeperServer::FD;\n    zh->input_buffer=0;\n    gettimeofday(&zh->last_recv,0);    \n    gettimeofday(&zh->last_send,0);    \n}\n\nvoid terminateZookeeperThreads(zhandle_t* zh){\n    // this will cause the zookeeper threads to terminate\n    zh->close_requested=1;\n}\n"
  },
  {
    "path": "src/c/tests/ZKMocks.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZKMOCKS_H_\n#define ZKMOCKS_H_\n\n#include <zookeeper.h>\n#include \"src/zk_adaptor.h\"\n\n#include \"Util.h\"\n#include \"LibCMocks.h\"\n#include \"MocksBase.h\"\n\n// *****************************************************************************\n// sets internal zhandle_t members to certain values to simulate the client \n// connected state. This function should only be used with the single-threaded\n// Async API tests!\nvoid forceConnected(zhandle_t* zh); \n\n/**\n * Gracefully terminates zookeeper I/O and completion threads. \n */\nvoid terminateZookeeperThreads(zhandle_t* zh);\n\n// *****************************************************************************\n// Abstract watcher action\nstruct SyncedBoolCondition;\n\nclass WatcherAction{\npublic:\n    WatcherAction():triggered_(false){}\n    virtual ~WatcherAction(){}\n    \n    virtual void onSessionExpired(zhandle_t*){}\n    virtual void onConnectionEstablished(zhandle_t*){}\n    virtual void onConnectionLost(zhandle_t*){}\n    virtual void onNodeValueChanged(zhandle_t*,const char* path){}\n    virtual void onNodeDeleted(zhandle_t*,const char* path){}\n    virtual void onChildChanged(zhandle_t*,const char* path){}\n    \n    SyncedBoolCondition isWatcherTriggered() const;\n    void setWatcherTriggered(){\n        synchronized(mx_);\n        triggered_=true;\n    }\n\nprotected:\n    mutable Mutex mx_;\n    bool triggered_;\n};\n// zh->context is a pointer to a WatcherAction instance\n// based on the event type and state, the watcher calls a specific watcher \n// action method\nvoid activeWatcher(zhandle_t *zh, int type, int state, const char *path,void* ctx);\n\n// *****************************************************************************\n// a set of async completion signatures\nclass AsyncCompletion{\npublic:\n    virtual ~AsyncCompletion(){}\n    virtual void aclCompl(int rc, ACL_vector *acl,Stat *stat){}\n    virtual void dataCompl(int rc, const char *value, int len, const Stat *stat){}\n    virtual void statCompl(int rc, const Stat *stat){}\n    virtual void stringCompl(int rc, const char *value){}\n    virtual void stringsCompl(int rc,const String_vector *strings){}\n    virtual void voidCompl(int rc){}\n};\nvoid asyncCompletion(int rc, ACL_vector *acl,Stat *stat, const void *data);\nvoid asyncCompletion(int rc, const char *value, int len, const Stat *stat, \n        const void *data);\nvoid asyncCompletion(int rc, const Stat *stat, const void *data);\nvoid asyncCompletion(int rc, const char *value, const void *data);\nvoid asyncCompletion(int rc,const String_vector *strings, const void *data);\nvoid asyncCompletion(int rc, const void *data);\n\n// *****************************************************************************\n// some common predicates to use with ensureCondition():\n// checks if the connection is established\nstruct ClientConnected{\n    ClientConnected(zhandle_t* zh):zh_(zh){}\n    bool operator()() const{\n        return zoo_state(zh_)==ZOO_CONNECTED_STATE;\n    }\n    zhandle_t* zh_;\n};\n// check in the session expired\nstruct SessionExpired{\n    SessionExpired(zhandle_t* zh):zh_(zh){}\n    bool operator()() const{\n        return zoo_state(zh_)==ZOO_EXPIRED_SESSION_STATE;\n    }\n    zhandle_t* zh_;\n};\n// checks if the IO thread has stopped; CheckedPthread must be active\nstruct IOThreadStopped{\n    IOThreadStopped(zhandle_t* zh):zh_(zh){}\n    bool operator()() const;\n    zhandle_t* zh_;\n};\n\n// a synchronized boolean condition\nstruct SyncedBoolCondition{\n    SyncedBoolCondition(const bool& cond,Mutex& mx):cond_(cond),mx_(mx){}\n    bool operator()() const{\n        synchronized(mx_);\n        return cond_;\n    }\n    const bool& cond_;\n    Mutex& mx_;\n};\n\n// a synchronized integer comparison\nstruct SyncedIntegerEqual{\n    SyncedIntegerEqual(const int& cond,int expected,Mutex& mx):\n        cond_(cond),expected_(expected),mx_(mx){}\n    bool operator()() const{\n        synchronized(mx_);\n        return cond_==expected_;\n    }\n    const int& cond_;\n    const int expected_;\n    Mutex& mx_;\n};\n\n// *****************************************************************************\n// make sure to call zookeeper_close() even in presence of exceptions \nstruct CloseFinally{\n    CloseFinally(zhandle_t** zh):zh_(zh){}\n    ~CloseFinally(){\n        execute();\n    }\n    int execute(){\n        if(zh_==0)return ZOK;\n        zhandle_t* lzh=*zh_;\n        *zh_=0;\n        disarm();\n        return zookeeper_close(lzh);\n    }\n    void disarm(){zh_=0;}\n    zhandle_t ** zh_;\n};\n\nstruct TestClientId: clientid_t{\n    static const int SESSION_ID=123456789;\n    static const char* PASSWD;\n    TestClientId(){\n        client_id=SESSION_ID;\n        memcpy(passwd,PASSWD,sizeof(passwd));\n    }\n};\n\n// *****************************************************************************\n// special client id recongnized by the ZK server simulator \nextern TestClientId testClientId;\n#define TEST_CLIENT_ID &testClientId\n\n// *****************************************************************************\n//\nstruct HandshakeRequest: public connect_req\n{\n    static HandshakeRequest* parse(const std::string& buf);\n    static bool isValid(const std::string& buf){\n        // this is just quick and dirty check before we go and parse the request\n        return buf.size()==HANDSHAKE_REQ_SIZE;\n    }\n};\n\n// *****************************************************************************\n// flush_send_queue\nclass Mock_flush_send_queue: public Mock\n{\npublic:\n    Mock_flush_send_queue():counter(0),callReturns(ZOK){mock_=this;}\n    ~Mock_flush_send_queue(){mock_=0;}\n    \n    int counter;\n    int callReturns;\n    virtual int call(zhandle_t* zh, int timeout){\n        counter++;\n        return callReturns;\n    }\n\n    static Mock_flush_send_queue* mock_;\n};\n\n// *****************************************************************************\n// get_xid\nclass Mock_get_xid: public Mock\n{\npublic:\n    static const int32_t XID=123456;\n    Mock_get_xid(int retValue=XID):callReturns(retValue){mock_=this;}\n    ~Mock_get_xid(){mock_=0;}\n    \n    int callReturns;\n    virtual int call(){\n        return callReturns;\n    }\n\n    static Mock_get_xid* mock_;\n};\n\n// *****************************************************************************\n// activateWatcher\nclass Mock_activateWatcher: public Mock{\npublic:\n    Mock_activateWatcher(){mock_=this;}\n    virtual ~Mock_activateWatcher(){mock_=0;}\n    \n    virtual void call(zhandle_t *zh, watcher_registration_t* reg, int rc){}\n    static Mock_activateWatcher* mock_;\n};\n\nclass ActivateWatcherWrapper;\nclass WatcherActivationTracker{\npublic:\n    WatcherActivationTracker();\n    ~WatcherActivationTracker();\n    \n    void track(void* ctx);\n    SyncedBoolCondition isWatcherActivated() const;\nprivate:\n    ActivateWatcherWrapper* wrapper_;\n};\n\n// *****************************************************************************\n// deliverWatchers\nclass Mock_deliverWatchers: public Mock{\npublic:\n    Mock_deliverWatchers(){mock_=this;}\n    virtual ~Mock_deliverWatchers(){mock_=0;}\n    \n    virtual void call(zhandle_t* zh,int type,int state, const char* path, watcher_object_list **){}\n    static Mock_deliverWatchers* mock_;\n};\n\nclass DeliverWatchersWrapper;\nclass WatcherDeliveryTracker{\npublic:\n    // filters deliveries by state and type\n    WatcherDeliveryTracker(int type,int state,bool terminateCompletionThread=true);\n    ~WatcherDeliveryTracker();\n    \n    // if the thread termination requested (see the ctor params)\n    // this function will wait for the I/O and completion threads to \n    // terminate before returning a SyncBoolCondition instance\n    SyncedBoolCondition isWatcherProcessingCompleted() const;\n    void resetDeliveryCounter();\n    SyncedIntegerEqual deliveryCounterEquals(int expected) const;\nprivate:\n    DeliverWatchersWrapper* deliveryWrapper_;\n};\n\n// *****************************************************************************\n// a zookeeper Stat wrapper\nstruct NodeStat: public Stat\n{\n    NodeStat(){\n        czxid=0;\n        mzxid=0;\n        ctime=0;\n        mtime=0;\n        version=1;\n        cversion=0;\n        aversion=0;\n        ephemeralOwner=0;\n    }\n    NodeStat(const Stat& other){\n        memcpy(this,&other,sizeof(*this));\n    }\n};\n\n// *****************************************************************************\n// Abstract server Response\nclass Response\n{\npublic:\n    virtual ~Response(){}\n    \n    virtual void setXID(int32_t xid){}\n    // this method is used by the ZookeeperServer class to serialize \n    // the instance of Response\n    virtual std::string toString() const =0;\n};\n\n// *****************************************************************************\n// Handshake response\nclass HandshakeResponse: public Response\n{\npublic:\n    HandshakeResponse(int64_t sessId=1)\n        :protocolVersion(1),timeOut(10000),sessionId(sessId),passwd_len(sizeof(passwd))\n    {\n        memcpy(passwd,\"1234567890123456\",sizeof(passwd));\n    }\n    int32_t protocolVersion;\n    int32_t timeOut;\n    int64_t sessionId;\n    int32_t passwd_len;\n    char passwd[16];\n    virtual std::string toString() const ;\n};\n\n// zoo_get() response\nclass ZooGetResponse: public Response\n{\npublic:\n    ZooGetResponse(const char* data, int len,int32_t xid=0,int rc=ZOK,const Stat& stat=NodeStat())\n        :xid_(xid),data_(data,len),rc_(rc),stat_(stat)\n    {\n    }\n    virtual std::string toString() const;\n    virtual void setXID(int32_t xid) {xid_=xid;}\n    \nprivate:\n    int32_t xid_;\n    std::string data_;\n    int rc_;\n    Stat stat_;\n};\n\n// zoo_exists(), zoo_set() response\nclass ZooStatResponse: public Response\n{\npublic:\n    ZooStatResponse(int32_t xid=0,int rc=ZOK,const Stat& stat=NodeStat())\n        :xid_(xid),rc_(rc),stat_(stat)\n    {\n    }\n    virtual std::string toString() const;\n    virtual void setXID(int32_t xid) {xid_=xid;}\n    \nprivate:\n    int32_t xid_;\n    int rc_;\n    Stat stat_;\n};\n\n// zoo_get_children()\nclass ZooGetChildrenResponse: public Response\n{\npublic:\n    typedef std::vector<std::string> StringVector;\n    ZooGetChildrenResponse(const StringVector& v,int rc=ZOK):\n        xid_(0),strings_(v),rc_(rc)\n    {\n    }\n    \n    virtual std::string toString() const;\n    virtual void setXID(int32_t xid) {xid_=xid;}\n\n    int32_t xid_;\n    StringVector strings_;\n    int rc_;\n};\n\n// PING response\nclass PingResponse: public Response\n{\npublic:\n    virtual std::string toString() const;    \n};\n\n// watcher znode event\nclass ZNodeEvent: public Response\n{\npublic:\n    ZNodeEvent(int type,const char* path):type_(type),path_(path){}\n    \n    virtual std::string toString() const;\n    \nprivate:\n    int type_;\n    std::string path_;\n};\n\n// ****************************************************************************\n// Zookeeper server simulator\n\nclass ZookeeperServer: public Mock_socket\n{\npublic:\n    ZookeeperServer():\n        serverDownSkipCount_(-1),sessionExpired(false),connectionLost(false)\n    {\n        connectReturns=-1;\n        connectErrno=EWOULDBLOCK;        \n    }\n    virtual ~ZookeeperServer(){\n        clearRecvQueue();\n        clearRespQueue();\n    }\n    virtual int callClose(int fd){\n        if(fd!=FD)\n            return LIBC_SYMBOLS.close(fd);\n        clearRecvQueue();\n        clearRespQueue();\n        return Mock_socket::callClose(fd);\n    }\n    // connection handling\n    // what to do when the handshake request comes in?\n    int serverDownSkipCount_;\n    // this will cause getsockopt(zh->fd,SOL_SOCKET,SO_ERROR,&error,&len) return \n    // a failure after skipCount dropped to zero, thus simulating a server down \n    // condition\n    // passing skipCount==-1 will make every connect attempt succeed\n    void setServerDown(int skipCount=0){ \n        serverDownSkipCount_=skipCount;\n        optvalSO_ERROR=0;            \n    }\n    virtual void setSO_ERROR(void *optval,socklen_t len){\n        if(serverDownSkipCount_!=-1){\n            if(serverDownSkipCount_==0)\n                optvalSO_ERROR=ECONNREFUSED;\n            else\n                serverDownSkipCount_--;\n        }\n        Mock_socket::setSO_ERROR(optval,len);\n    }\n\n    // this is a trigger that gets reset back to false\n    // a connect request will return a non-matching session id thus causing \n    // the client throw SESSION_EXPIRED\n    volatile bool sessionExpired;\n    void returnSessionExpired(){ sessionExpired=true; }\n    \n    // this is a one shot trigger that gets reset back to false\n    // next recv call will return 0 length, thus simulating a connecton loss\n    volatile bool connectionLost;\n    void setConnectionLost() {connectionLost=true;}\n    \n    // recv\n    // this queue is used for server responses: client's recv() system call \n    // returns next available message from this queue\n    typedef std::pair<Response*,int> Element;\n    typedef std::deque<Element> ResponseList;\n    ResponseList recvQueue;\n    mutable Mutex recvQMx;\n    AtomicInt recvHasMore;\n    ZookeeperServer& addRecvResponse(Response* resp, int errnum=0){\n        synchronized(recvQMx);\n        recvQueue.push_back(Element(resp,errnum));\n        ++recvHasMore;\n        return *this;\n    }\n    ZookeeperServer& addRecvResponse(int errnum){\n        synchronized(recvQMx);\n        recvQueue.push_back(Element(0,errnum));\n        ++recvHasMore;\n        return *this;\n    }\n    ZookeeperServer& addRecvResponse(const Element& e){\n        synchronized(recvQMx);\n        recvQueue.push_back(e);\n        ++recvHasMore;\n        return *this;\n    }\n    void clearRecvQueue(){\n        synchronized(recvQMx);\n        recvHasMore=0;\n        for(unsigned i=0; i<recvQueue.size();i++)\n            delete recvQueue[i].first;\n        recvQueue.clear();\n    }\n\n    virtual ssize_t callRecv(int s,void *buf,size_t len,int flags);\n    virtual bool hasMoreRecv() const;\n    \n    // the operation response queue holds zookeeper operation responses till the\n    // operation request has been sent to the server. After that, the operation\n    // response gets moved on to the recv queue (see above) ready to be read by \n    // the next recv() system call\n    // send operation doesn't try to match request to the response\n    ResponseList respQueue;\n    mutable Mutex respQMx;\n    ZookeeperServer& addOperationResponse(Response* resp, int errnum=0){\n        synchronized(respQMx);\n        respQueue.push_back(Element(resp,errnum));\n        return *this;\n    }\n    void clearRespQueue(){\n        synchronized(respQMx);\n        for(unsigned i=0; i<respQueue.size();i++)\n            delete respQueue[i].first;\n        respQueue.clear();\n    }\n    AtomicInt closeSent;\n    virtual void notifyBufferSent(const std::string& buffer);\n    // simulates an arrival of a client request\n    // a callback to be implemented by subclasses (no-op by default)\n    virtual void onMessageReceived(const RequestHeader& rh, iarchive* ia);\n};\n\n#endif /*ZKMOCKS_H_*/\n"
  },
  {
    "path": "src/c/tests/wrappers-mt.opt",
    "content": "-Wl,--wrap -Wl,pthread_mutex_lock\n-Wl,--wrap -Wl,pthread_mutex_trylock\n-Wl,--wrap -Wl,pthread_mutex_unlock\n"
  },
  {
    "path": "src/c/tests/wrappers.opt",
    "content": "-Wl,--wrap -Wl,calloc\n-Wl,--wrap -Wl,free\n-Wl,--wrap -Wl,flush_send_queue\n-Wl,--wrap -Wl,get_xid\n-Wl,--wrap -Wl,deliverWatchers\n-Wl,--wrap -Wl,activateWatcher\n-Wl,--wrap -Wl,realloc\n"
  },
  {
    "path": "src/c/tests/zkServer.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This is the port where zookeeper server runs on.\nZOOPORT=22181\n\nif [ \"x$1\" == \"x\" ]\nthen\n    echo \"USAGE: $0 startClean|start|stop hostPorts\"\n    exit 2\nfi\n\ncase \"`uname`\" in\n    CYGWIN*) cygwin=true ;;\n    *) cygwin=false ;;\nesac\n\nif [ \"x$1\" == \"xstartClean\" ]\nthen\n    if [ \"x${base_dir}\" == \"x\" ]\n    then\n    rm -rf /tmp/zkdata\n    else\n    rm -rf \"${base_dir}/build/tmp\"\n    fi\nfi\n\nif $cygwin\nthen\n    # cygwin has a \"kill\" in the shell itself, gets confused\n    KILL=/bin/kill\nelse\n    KILL=kill\nfi\n\n# Make sure nothing is left over from before\nif [ -r \"/tmp/zk.pid\" ]\nthen\npid=`cat /tmp/zk.pid`\n$KILL -9 $pid\nrm -f /tmp/zk.pid\nfi\n\nif [ -r \"${base_dir}/build/tmp/zk.pid\" ]\nthen\npid=`cat \"${base_dir}/build/tmp/zk.pid\"`\n$KILL -9 $pid\nrm -f \"${base_dir}/build/tmp/zk.pid\"\nfi\n\n# [ZOOKEEPER-820] If lsof command is present, look for a process listening\n# on ZOOPORT and kill it. \nwhich lsof &> /dev/null\nif [ $? -eq 0  ]\nthen\n    pid=`lsof -i :$ZOOPORT | grep LISTEN | awk '{print $2}'`\n    if [ -n \"$pid\" ]\n    then\n        $KILL -9 $pid\n    fi\nfi\n\nif [ \"x${base_dir}\" == \"x\" ]\nthen\nzk_base=\"../../\"\nelse\nzk_base=\"${base_dir}\"\nfi\n\nCLASSPATH=\"$CLASSPATH:${zk_base}/build/classes\"\nCLASSPATH=\"$CLASSPATH:${zk_base}/conf\"\n\nfor i in \"${zk_base}\"/build/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nfor i in \"${zk_base}\"/src/java/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nCLASSPATH=\"$CLASSPATH:${CLOVER_HOME}/lib/clover.jar\"\n\nif $cygwin\nthen\n    CLASSPATH=`cygpath -wp \"$CLASSPATH\"`\nfi\n\ncase $1 in\nstart|startClean)\n    if [ \"x${base_dir}\" == \"x\" ]\n    then\n        mkdir -p /tmp/zkdata\n        java -cp \"$CLASSPATH\" org.apache.zookeeper.server.ZooKeeperServerMain $ZOOPORT /tmp/zkdata 3000 $ZKMAXCNXNS &> /tmp/zk.log &\n        pid=$!\n        echo -n $! > /tmp/zk.pid\n    else\n        mkdir -p \"${base_dir}/build/tmp/zkdata\"\n        java -cp \"$CLASSPATH\" org.apache.zookeeper.server.ZooKeeperServerMain $ZOOPORT \"${base_dir}/build/tmp/zkdata\" 3000 $ZKMAXCNXNS &> \"${base_dir}/build/tmp/zk.log\" &\n        pid=$!\n        echo -n $pid > \"${base_dir}/build/tmp/zk.pid\"\n    fi\n\n    # wait max 120 seconds for server to be ready to server clients\n    # this handles testing on slow hosts\n    success=false\n    for i in {1..120}\n    do\n        if ps -p $pid > /dev/null\n        then\n            java -cp \"$CLASSPATH\" org.apache.zookeeper.ZooKeeperMain -server localhost:$ZOOPORT ls / > /dev/null 2>&1\n            if [ $? -ne 0  ]\n            then\n                # server not up yet - wait\n                sleep 1\n            else\n                # server is up and serving client connections\n                success=true\n                break\n            fi\n        else\n            # server died - exit now\n            echo -n \" ZooKeeper server process failed\"\n            break\n        fi\n    done\n\n    if $success\n    then\n        ## in case for debug, but generally don't use as it messes up the\n        ## console test output\n        echo -n \" ZooKeeper server started\"\n    else\n        echo -n \" ZooKeeper server NOT started\"\n    fi\n\n    ;;\nstop)\n    # Already killed above\n    ;;\n*)\n    echo \"Unknown command \" + $1\n    exit 2\nesac\n\n"
  },
  {
    "path": "src/contrib/build-contrib.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<!-- Imported by contrib/*/build.xml files to share generic targets. -->\n\n<project name=\"zookeeperbuildcontrib\" xmlns:ivy=\"antlib:org.apache.ivy.ant\">\n\n  <property name=\"name\" value=\"${ant.project.name}\"/>\n  <property name=\"version\" value=\"dev\"/>\n  <property name=\"root\" value=\"${basedir}\"/>\n\n  <property name=\"zk.root\" location=\"${root}/../../../\"/>\n\n  <property name=\"src.dir\"  location=\"${root}/src/java\"/>\n  <property name=\"src.test\" location=\"${root}/src/test\"/>\n\n  <property name=\"lib.dir\"  location=\"${zk.root}/src/java/lib\"/>\n\n  <property name=\"build.dir\" location=\"${zk.root}/build/contrib/${name}\"/>\n  <property name=\"build.classes\" location=\"${build.dir}/classes\"/>\n  <property name=\"build.test\" location=\"${build.dir}/test\"/>\n\n  <property name=\"javac.deprecation\" value=\"on\"/>\n  <property name=\"javac.debug\" value=\"on\"/>\n\n  <property name=\"build.encoding\" value=\"ISO-8859-1\"/>\n\n  <property name=\"ivy.version\" value=\"2.4.0\"/>\n  <property name=\"ivy.url\"\n            value=\"https://repo1.maven.org/maven2/org/apache/ivy/ivy\" />\n  <property name=\"ivy.home\" value=\"${user.home}/.ant\" />\n  <property name=\"ivy.lib\" value=\"${build.dir}/lib\"/>\n  <property name=\"ivy.test.lib\" value=\"${build.test}/lib\"/>\n  <property name=\"ivysettings.xml\" value=\"${zk.root}/ivysettings.xml\"/>\n\n  <!-- to be overridden by sub-projects -->\n  <target name=\"check-contrib\"/>\n  <target name=\"init-contrib\"/>\n\n  <property name=\"lib.jars.includes\" value=\"lib/*.jar\" />\n  <property name=\"lib.jars.excludes\" value=\"\" />\n\n  <!-- prior to ant 1.7.1 fileset always fails if dir doesn't exist\n       so just point to bin directory and provide settings that exclude\n       everything - user can change as appropriate -->\n  <property name=\"additional.lib.dir\" value=\"${zk.root}/bin\" />\n  <property name=\"additional.lib.dir.includes\" value=\"**/*.jar\" />\n  <property name=\"additional.lib.dir.excludes\" value=\"**/*.jar\" />\n\n  <fileset id=\"lib.jars\" dir=\"${root}\">\n    <include name=\"${lib.jars.includes}\" />\n    <exclude name=\"${lib.jars.excludes}\" />\n  </fileset>\n\n  <path id=\"classpath\">\n    <pathelement location=\"${build.classes}\"/>\n    <!-- allow the user to override (e.g. if there are local versions) -->\n    <fileset dir=\"${additional.lib.dir}\">\n      <include name=\"${additional.lib.dir.includes}\" />\n      <exclude name=\"${additional.lib.dir.excludes}\" />\n    </fileset>\n    <fileset refid=\"lib.jars\"/>\n    <pathelement location=\"${zk.root}/build/classes\"/>\n    <fileset dir=\"${ivy.lib}\">\n      <include name=\"**/*.jar\" />\n    </fileset>\n    <fileset dir=\"${ivy.test.lib}\">\n      <include name=\"**/*.jar\" />\n    </fileset>\n    <fileset dir=\"${zk.root}/src/java/lib\">\n      <include name=\"**/*.jar\" />\n    </fileset>\n    <fileset dir=\"${ant.home}/lib\">\n      <include name=\"ant.jar\" />\n    </fileset>\n  </path>\n\n  <!-- ====================================================== -->\n  <!-- Stuff needed by all targets                            -->\n  <!-- ====================================================== -->\n  <target name=\"init\" depends=\"check-contrib\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <mkdir dir=\"${build.classes}\"/>\n    <mkdir dir=\"${build.test}\"/>\n\n    <mkdir dir=\"${ivy.lib}\"/>\n    <mkdir dir=\"${ivy.test.lib}\"/>\n    <condition property=\"ivy.jar.exists\">\n      <available file=\"${lib.dir}/ivy-${ivy.version}.jar\"/>\n    </condition>\n\n    <antcall target=\"init-contrib\"/>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Compile a contrib's files                              -->\n  <!-- ====================================================== -->\n  <target name=\"compile\" depends=\"init\"\n          unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <javac\n     encoding=\"${build.encoding}\"\n     srcdir=\"${src.dir}\"\n     includes=\"**/*.java\"\n     destdir=\"${build.classes}\"\n     debug=\"${javac.debug}\"\n     deprecation=\"${javac.deprecation}\">\n      <classpath refid=\"classpath\"/>\n    </javac>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Make a contrib's jar                                   -->\n  <!-- ====================================================== -->\n  <target name=\"jar\" depends=\"compile\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <jar\n      jarfile=\"${build.dir}/zookeeper-${version}-${name}.jar\"\n      basedir=\"${build.classes}\"      \n    />\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Package a contrib's files                              -->\n  <!-- ====================================================== -->\n  <target name=\"package\" depends=\"jar\" unless=\"skip.contrib\"> \n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${dist.dir}${package.share}/contrib/${name}\"/>\n    <copy todir=\"${dist.dir}${package.share}/contrib/${name}\" includeEmptyDirs=\"false\"\n          flatten=\"true\">\n      <fileset dir=\"${build.dir}\">\n        <include name=\"zookeeper-${version}-${name}.jar\" />\n      </fileset>\n    </copy>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Package a contrib's files                              -->\n  <!-- ====================================================== -->\n  <target name=\"package-native\" depends=\"jar\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- rpm a contrib's files                                  -->\n  <!-- ====================================================== -->\n  <target name=\"rpm\" depends=\"jar\" unless=\"skip.contrib\"> \n    <echo message=\"contrib: ${name}\"/>\n\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- deb a contrib's files                                  -->\n  <!-- ====================================================== -->\n  <target name=\"deb\" depends=\"jar\" unless=\"skip.contrib\"> \n    <echo message=\"contrib: ${name}\"/>\n\n  </target>\n  <!-- ================================================================== -->\n  <!-- Clean.  Delete the build files, and their directories              -->\n  <!-- ================================================================== -->\n  <target name=\"clean\">\n    <echo message=\"contrib: ${name}\"/>\n    <delete dir=\"${build.dir}\"/>\n  </target>\n\n\n  <!-- ================================================================== -->\n  <!-- Utility features                                                   -->\n  <!-- ================================================================== -->\n\n  <target name=\"checkMainIsAvailable\">\n    <available classname=\"org.apache.zookeeper.ZooKeeperMain\"\n               property=\"mainIsCompiled\">\n      <!-- we can't use id=classpath, because available fails if fileset directory\n           doesn't exist -->\n      <classpath>\n        <pathelement location=\"${zk.root}/build/classes\"/>\n      </classpath>\n    </available>\n  </target>\n\n  <target name=\"checkMainCompiled\" unless=\"mainIsCompiled\" depends=\"checkMainIsAvailable\">\n    <fail message=\"ZooKeeper main must first be compiled (toplevel build.xml)\"/>\n  </target>\n\n\n  <target name=\"checkMainTestIsAvailable\">\n    <available file=\"${zk.root}/build/test/classes/org/apache/zookeeper/test/ClientBase.class\"\n               property=\"mainTestIsCompiled\">\n    </available>\n  </target>\n\n  <target name=\"checkMainTestCompiled\" unless=\"mainTestIsCompiled\" depends=\"checkMainTestIsAvailable\">\n    <fail message=\"ZooKeeper test must first be compiled (toplevel build.xml) using 'ant compile-test'\"/>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Ivy                                                    -->\n  <!-- ====================================================== -->\n  <target name=\"ivy-download\" unless=\"ivy.jar.exists\" depends=\"init\">\n    <delete dir=\"${lib.dir}\"\n            includes=\"ivy-*.jar\" excludes=\"ivy-${ivy.version}.jar\"/>\n    <get src=\"${ivy.url}/${ivy.version}/ivy-${ivy.version}.jar\"\n         dest=\"${lib.dir}/ivy-${ivy.version}.jar\" usetimestamp=\"true\"/>\n  </target>\n\n  <target name=\"ivy-init\" depends=\"ivy-download\" unless=\"ivy.initialized\">\n    <taskdef resource=\"org/apache/ivy/ant/antlib.xml\"\n             uri=\"antlib:org.apache.ivy.ant\" classpathref=\"classpath\"/>\n    <!-- ensure that ivy taskdef is only run once, otw ant will error -->\n    <property name=\"ivy.initialized\" value=\"true\"/>\n    <ivy:settings id=\"${ant.project.name}\" file=\"${ivysettings.xml}\"/> \n  </target>\n\n  <target name=\"ivy-retrieve\" depends=\"init,ivy-init\">\n    <ivy:retrieve settingsRef=\"${ant.project.name}\" type=\"jar\" conf=\"default\"\n                  pattern=\"${ivy.lib}/[artifact]-[revision].[ext]\"/>\n    <ivy:retrieve settingsRef=\"${ant.project.name}\" type=\"bundle\" conf=\"default\"\n  \t\t\t\t  pattern=\"${ivy.lib}/[artifact]-[revision].[ext]\"/>\n  </target>\n\n  <target name=\"ivy-retrieve-test\" depends=\"init,ivy-init\">\n    <ivy:retrieve settingsRef=\"${ant.project.name}\" type=\"jar\" conf=\"test\"\n                  pattern=\"${ivy.test.lib}/[artifact]-[revision].[ext]\"/>\n  </target>\n\n\n</project>\n"
  },
  {
    "path": "src/contrib/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zookeepercontrib\" default=\"compile\" basedir=\".\">\n\n  <property name=\"contribfilesetincludes\" value=\"*/build.xml\" />\n  <property name=\"contribfilesetexcludes\" value=\"\" />\n\n  <fileset id=\"contribfileset\" dir=\".\">\n    <include name=\"${contribfilesetincludes}\"/>\n    <exclude name=\"${contribfilesetexcludes}\"/>\n  </fileset>\n\n  <!-- In case one of the contrib subdirectories -->\n  <!-- fails the build or test targets and you cannot fix it: -->\n  <!-- Then add to fileset: excludes=\"badcontrib/build.xml\" -->\n\n  <!-- ====================================================== -->\n  <!-- Compile contribs.                                      -->\n  <!-- ====================================================== -->\n  <target name=\"compile\">\n    <subant target=\"jar\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n  \n  <!-- ====================================================== -->\n  <!-- Package contrib jars.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"package\">\n    <subant target=\"package\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Test all the contribs.                               -->\n  <!-- ====================================================== -->\n  <target name=\"test\">\n    <subant target=\"test\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n  \n  \n  <!-- ====================================================== -->\n  <!-- Clean all the contribs.                              -->\n  <!-- ====================================================== -->\n  <target name=\"clean\">\n    <subant target=\"clean\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- rpm all the contribs.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"rpm\">\n    <subant target=\"rpm\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- deb all the contribs.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"deb\">\n    <subant target=\"deb\">\n      <fileset refid=\"contribfileset\" />\n    </subant>\n  </target>\n</project>\n"
  },
  {
    "path": "src/contrib/fatjar/README.txt",
    "content": "This package contains build to create a fat zookeeper jar. You need to run ant to create the fat jar.\nTo run the fatjar you can use. java -jar zoookeeper-*fatjar.jar \n"
  },
  {
    "path": "src/contrib/fatjar/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"fatjar\" default=\"jar\">\n  <import file=\"../build-contrib.xml\"/>\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\"\n              value=\"${build.dir}/zookeeper-${version}-${name}.jar\"/>\n  </target>\n\n  <!-- Override jar target to specify main class -->\n  <target name=\"jar\" depends=\"checkMainCompiled, setjarname, compile\">\n    <echo message=\"contrib: ${name}\"/>\n    <jar jarfile=\"${jarname}\">\n      <manifest>\n        <attribute name=\"Main-Class\" value=\"org.apache.zookeeper.util.FatJarMain\" />\n        <attribute name=\"Built-By\" value=\"${user.name}\"/>\n        <attribute name=\"Built-At\" value=\"${build.time}\"/>\n        <attribute name=\"Built-On\" value=\"${host.name}\" />\n        <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\"/>\n        <attribute name=\"Implementation-Version\" value=\"${revision}\"/>\n        <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n      </manifest>\n      <fileset file=\"${basedir}/conf/mainClasses\" />\n      <fileset dir=\"${build.classes}\"/>\n      <fileset dir=\"${build.test}\"/>\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset file=\"${zk.root}/conf/log4j.properties\" />\n      <fileset dir=\"${zk.root}/build/classes\" excludes=\"**/.generated\"/>\n      <fileset dir=\"${zk.root}/build/test/classes\"/>\n      <zipgroupfileset dir=\"${zk.root}/build/lib\" includes=\"*.jar\" />\n      <zipgroupfileset dir=\"${zk.root}/build/test/lib\" includes=\"*.jar\" />\n      <zipgroupfileset dir=\"${zk.root}/src/java/lib\" includes=\"*.jar\" />\n    </jar>\n  </target>\n\n  <target name=\"package\" depends=\"jar, zookeeperbuildcontrib.package\"\n          unless=\"skip.contrib\">\n\n    <copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}/contrib/${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}/conf\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}/conf\">\n      <fileset dir=\"${basedir}/conf\"/>\n    </copy>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}/src\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}/src\">\n      <fileset dir=\"${basedir}/src\"/>\n    </copy>\n  </target>\n\n\t<target name=\"test\">\n\t\t<echo message=\"No test target defined for this package\" />\n\t</target>\n</project>\n\n"
  },
  {
    "path": "src/contrib/fatjar/conf/mainClasses",
    "content": "::Client Commands\nclient:org.apache.zookeeper.ZooKeeperMain:Client shell to ZooKeeper\n::Server Commands\nserver:org.apache.zookeeper.server.quorum.QuorumPeerMain:Start ZooKeeper server\n::Test Commands\ngenerateLoad:org.apache.zookeeper.test.system.GenerateLoad:A distributed load generator for testing\nquorumBench:org.apache.zookeeper.server.QuorumBenchmark:A benchmark of just the quorum protocol\nabBench:org.apache.zookeeper.server.quorum.AtomicBroadcastBenchmark:A benchmark of just the atomic broadcast\nic:org.apache.zookeeper.test.system.InstanceContainer:A container that will instantiate classes as directed by an instance manager\nsystest:org.apache.zookeeper.test.system.BaseSysTest:Start system test\n"
  },
  {
    "path": "src/contrib/fatjar/src/java/org/apache/zookeeper/util/FatJarMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\n/**\n * This is a generic Main class that is completely driven by the\n * /mainClasses resource on the class path. This resource has the\n * format:\n * <pre>\n * cmd:mainClass:Description\n * </pre>\n * Any lines starting with # will be skipped\n *\n */\npublic class FatJarMain {\n    static class Cmd {\n        Cmd(String cmd, String clazz, String desc) {\n            this.cmd = cmd;\n            this.clazz = clazz;\n            this.desc = desc;\n        }\n        String cmd;\n        String clazz;\n        String desc;\n    }\n    static HashMap<String, Cmd> cmds = new HashMap<String, Cmd>();\n    static ArrayList<String> order = new ArrayList<String>();\n    \n    /**\n     * @param args the first parameter of args will be used as an\n     * index into the /mainClasses resource. The rest will be passed\n     * to the mainClass to run.\n     * @throws IOException \n     * @throws ClassNotFoundException \n     * @throws NoSuchMethodException \n     * @throws SecurityException \n     * @throws IllegalAccessException \n     * @throws IllegalArgumentException \n     */\n    public static void main(String[] args) throws IOException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException {\n        InputStream is = FatJarMain.class.getResourceAsStream(\"/mainClasses\");\n        if (is == null) {\n            System.err.println(\"Couldn't find /mainClasses in classpath.\");\n            System.exit(3);\n        }\n        BufferedReader br = new BufferedReader(new InputStreamReader(is));\n        String line;\n        while((line = br.readLine()) != null) {\n            String parts[] = line.split(\":\", 3);\n            if (parts.length != 3 || (parts[0].length() > 0 && parts[0].charAt(0) == '#')) {\n                continue;\n            }\n            if (parts[0].length() > 0) {\n                cmds.put(parts[0], new Cmd(parts[0], parts[1], parts[2]));\n                // We use the order array to preserve the order of the commands\n                // for help. The hashmap will not preserver order. (It may be overkill.)\n                order.add(parts[0]);\n            } else {\n                // Just put the description in\n                order.add(parts[2]);\n            }\n        }\n        if (args.length == 0) {\n            doHelp();\n            return;\n        }\n        Cmd cmd = cmds.get(args[0]);\n        if (cmd == null) {\n            doHelp();\n            return;\n        }\n        Class<?> clazz = Class.forName(cmd.clazz);\n        Method main = clazz.getMethod(\"main\", String[].class);\n        String newArgs[] = new String[args.length-1];\n        System.arraycopy(args, 1, newArgs, 0, newArgs.length);\n        try {\n            main.invoke(null, (Object)newArgs);\n        } catch(InvocationTargetException e) {\n            if (e.getCause() != null) {\n                e.getCause().printStackTrace();\n            } else {\n                e.printStackTrace();\n            }\n        }\n    }\n    \n    private static void doHelp() {\n        System.err.println(\"USAGE: FatJarMain cmd args\");\n        System.err.println(\"Available cmds:\");\n        for(String c: order) {\n            Cmd cmd = cmds.get(c);\n            if (cmd != null) {\n                System.err.println(\"  \" + c + \" \" + cmd.desc);\n            } else {\n                System.err.println(c);\n            }\n        }\n        System.exit(2);\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/huebrowser/README",
    "content": "\nZooKeeper Browser - Hue Application\n===================================\n\nThe ZooKeeper Browser application allows you to see how the cluster nodes are working and also allows you to do CRUD operations on the znode hierarchy.\n\nRequirements\n------------\n\nHue-1.0:\n  * http://github.com/downloads/cloudera/hue/hue-1.0.tgz\n  * http://github.com/downloads/cloudera/hue/release-notes-1.0.html\n\nZooKeeper REST gateway:\n  * available as contrib: contrib/rest\n\nHow to install?\n---------------\n\nFirst of all you need to install Hue 1.0 release:\n\n  * http://archive.cloudera.com/cdh/3/hue/sdk/sdk.html\n  * http://github.com/cloudera/hue/tree/release-1.0\n\nAfter you finish the previous step you should copy the zkui/ folder to apps/ and register the new application:\n\n  * $ ./build/env/bin/python tools/app_reg/app_reg.py --install apps/zkui\n  * $ ./build/env/bin/python tools/app_reg/app_reg.py --list 2>&1 | grep zkui\n    zkui           0.1     /Users/philip/src/hue/apps/zkui\n\n\nAnd restart the Hue application server.\n\nConfiguration\n-------------\n\nEdit zkui/src/zkui/settings.py:\n\nCLUSTERS = [{\n        'nice_name': 'Default',\n        'hostport': 'localhost:2181,localhost:2182,localhost:2183',\n        'rest_gateway': 'http://localhost:9998'\n    }, {\n      # ... and more clusters\n    }\n]\n\nWhat is Hue?\n------------\n\nWiki: http://wiki.github.com/cloudera/hue/\nMain Repo: http://github.com/cloudera/hue \n\nHue is both a web UI for Hadoop and a framework to create interactive web applications. It features a FileBrowser for accessing HDFS, JobSub and JobBrowser applications for submitting and viewing MapReduce jobs, a Beeswax application for interacting with Hive. On top of that, the web frontend is mostly built from declarative widgets that require no JavaScript and are easy to learn.\n\nWhat is ZooKeeper?\n------------------\n\nhttp://zookeeper.apache.org/\n\nZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them ,which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/Makefile",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nifeq ($(ROOT),)\n  $(error \"Error: Expect the environment variable $$ROOT to point to the Desktop installation\")\nendif\n\ninclude $(ROOT)/Makefile.sdk\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/setup.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nfrom setuptools import setup, find_packages\nimport os\n\ndef expand_package_data(src_dirs, strip=\"\"):\n  ret = []\n  for src_dir in src_dirs:\n    for path, dnames, fnames in os.walk(src_dir):\n      for fname in fnames:\n        ret.append(os.path.join(path, fname).replace(strip, \"\"))\n  return ret\n\nos.chdir(os.path.dirname(os.path.abspath(__file__)))\nsetup(\n  name = \"zkui\",\n  version = \"0.1\",\n  url = 'http://zookeeper.apache.org/',\n  description = 'ZooKeeper Browser',\n  packages = find_packages('src'),\n  package_dir = {'': 'src'},\n  install_requires = ['setuptools', 'desktop'],\n  entry_points = { 'desktop.sdk.application': 'zkui=zkui' },\n  zip_safe = False,\n  package_data = {\n    # Include static resources.  Package_data doesn't\n    # deal well with directory globs, so we enumerate\n    # the files manually.\n    'zkui': expand_package_data(\n      [\"src/zkui/templates\", \"src/zkui/static\"],\n      \"src/zkui/\")\n  }\n)\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/__init__.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/forms.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom django import forms\nfrom django.forms.widgets import Textarea, HiddenInput\n\nclass CreateZNodeForm(forms.Form):\n  name = forms.CharField(max_length=64)\n  data = forms.CharField(required=False, widget=Textarea)\n  sequence = forms.BooleanField(required=False)\n\nclass EditZNodeForm(forms.Form):\n  data = forms.CharField(required=False, widget=Textarea)\n  version = forms.IntegerField(required=False, widget=HiddenInput)\n  \n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/models.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/rest.py",
    "content": "\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport urllib2\nimport urllib\nimport simplejson\n\nfrom contextlib import contextmanager\n\nclass RequestWithMethod(urllib2.Request):\n    \"\"\" Request class that know how to set the method name \"\"\"\n    def __init__(self, *args, **kwargs):\n        urllib2.Request.__init__(self, *args, **kwargs)\n        self._method = None\n\n    def get_method(self):\n        return self._method or \\\n            urllib2.Request.get_method(self)\n\n    def set_method(self, method):\n        self._method = method\n\nclass ZooKeeper(object):\n\n    class Error(Exception): pass\n\n    class NotFound(Error): pass\n\n    class ZNodeExists(Error): pass\n\n    class InvalidSession(Error): pass\n\n    class WrongVersion(Error): pass\n\n    def __init__(self, uri = 'http://localhost:9998'):\n        self._base = uri\n        self._session = None\n\n    def start_session(self, expire=5, id=None):\n        \"\"\" Create a session and return the ID \"\"\"\n        if id is None:\n            url = \"%s/sessions/v1/?op=create&expire=%d\" % (self._base, expire)\n            self._session = self._do_post(url)['id']\n        else:\n            self._session = id\n        return self._session\n\n    def close_session(self):\n        \"\"\" Close the session on the server \"\"\"\n        if self._session is not None:\n            url = '%s/sessions/v1/%s' % (self._base, self._session)\n            self._do_delete(url)\n            self._session = None\n\n    def heartbeat(self):\n        \"\"\" Send a heartbeat request. This is needed in order to keep a session alive \"\"\"\n        if self._session is not None:\n            url = '%s/sessions/v1/%s' % (self._base, self._session)\n            self._do_put(url, '')\n\n    @contextmanager\n    def session(self, *args, **kwargs):\n        \"\"\" Session handling using a context manager \"\"\"\n        yield self.start_session(*args, **kwargs)\n        self.close_session()\n\n    def get(self, path):\n        \"\"\" Get a node \"\"\"\n        url = \"%s/znodes/v1%s\" % (self._base, path)\n        return self._do_get(url)\n\n    def get_children(self, path):\n        \"\"\" Get all the children for a given path. This function creates a generator \"\"\"\n        for child_path in self.get_children_paths(path, uris=True):\n            try:\n                yield self._do_get(child_path)\n            except ZooKeeper.NotFound:\n                continue\n\n    def get_children_paths(self, path, uris=False):\n        \"\"\" Get the paths for children nodes \"\"\"\n        url = \"%s/znodes/v1%s?view=children\" % (self._base, path)\n        resp = self._do_get(url)\n        for child in resp.get('children', []):\n            yield child if not uris else resp['child_uri_template']\\\n              .replace('{child}', urllib2.quote(child))\n       \n    def create(self, path, data=None, sequence=False, ephemeral=False):\n        \"\"\" Create a new node. By default this call creates a persistent znode.\n\n        You can also create an ephemeral or a sequential znode.\n        \"\"\"\n        ri = path.rindex('/')\n        head, name = path[:ri+1], path[ri+1:]\n        if head != '/': head = head[:-1]\n\n        flags = {\n            'null': 'true' if data is None else 'false',\n            'ephemeral': 'true' if ephemeral else 'false',\n            'sequence': 'true' if sequence else 'false'\n        }\n        if ephemeral:\n            if self._session:\n                flags['session'] = self._session\n            else:\n                raise ZooKeeper.Error, 'You need a session '\\\n                    'to create an ephemeral node'\n        flags = urllib.urlencode(flags)\n\n        url = \"%s/znodes/v1%s?op=create&name=%s&%s\" % \\\n            (self._base, head, name, flags)\n\n        return self._do_post(url, data)\n\n    def set(self, path, data=None, version=-1, null=False):\n        \"\"\" Set the value of node \"\"\"\n        url = \"%s/znodes/v1%s?%s\" % (self._base, path, \\\n            urllib.urlencode({\n                'version': version,\n                'null': 'true' if null else 'false'\n        }))\n        return self._do_put(url, data)\n\n    def delete(self, path, version=-1):\n        \"\"\" Delete a znode \"\"\"\n        if type(path) is list:\n            map(lambda el: self.delete(el, version), path)\n            return\n\n        url = '%s/znodes/v1%s?%s' % (self._base, path, \\\n            urllib.urlencode({\n                'version':version\n        }))\n        try:\n            return self._do_delete(url)\n        except urllib2.HTTPError, e:\n            if e.code == 412:\n                raise ZooKeeper.WrongVersion(path)\n            elif e.code == 404:\n                raise ZooKeeper.NotFound(path)\n            raise\n\n    def recursive_delete(self, path):\n        \"\"\" Delete all the nodes from the tree \"\"\"\n        for child in self.get_children_paths(path):\n            fp = (\"%s/%s\" % (path, child)).replace('//', '/')\n            self.recursive_delete(fp)\n        self.delete(path)\n\n    def exists(self, path):\n        \"\"\" Do a znode exists \"\"\"\n        try:\n            self.get(path)\n            return True\n        except ZooKeeper.NotFound:\n            return False\n\n    def _do_get(self, uri):\n        \"\"\" Send a GET request and convert errors to exceptions \"\"\"\n        try:\n            req = urllib2.urlopen(uri)\n            resp = simplejson.load(req)\n\n            if 'Error' in resp:\n               raise ZooKeeper.Error(resp['Error'])\n\n            return resp\n        except urllib2.HTTPError, e:\n            if e.code == 404:\n                raise ZooKeeper.NotFound(uri)\n            raise\n\n    def _do_post(self, uri, data=None):\n        \"\"\" Send a POST request and convert errors to exceptions \"\"\"\n        try:\n            req = urllib2.Request(uri, {})\n            req.add_header('Content-Type', 'application/octet-stream')\n            if data is not None:\n                req.add_data(data)\n\n            resp = simplejson.load(urllib2.urlopen(req))\n            if 'Error' in resp:\n                raise ZooKeeper.Error(resp['Error'])\n            return resp\n\n        except urllib2.HTTPError, e:\n            if e.code == 201:\n                return True\n            elif e.code == 409:\n                raise ZooKeeper.ZNodeExists(uri)\n            elif e.code == 401:\n                raise ZooKeeper.InvalidSession(uri)\n            raise\n\n    def _do_delete(self, uri):\n        \"\"\" Send a DELETE request \"\"\"\n        req = RequestWithMethod(uri)\n        req.set_method('DELETE')\n        req.add_header('Content-Type', 'application/octet-stream')\n        return urllib2.urlopen(req).read()\n\n    def _do_put(self, uri, data):\n        \"\"\" Send a PUT request \"\"\"\n        try:\n            req = RequestWithMethod(uri)\n            req.set_method('PUT')\n            req.add_header('Content-Type', 'application/octet-stream')\n            if data is not None:\n                req.add_data(data)\n\n            return urllib2.urlopen(req).read()\n        except urllib2.HTTPError, e:\n            if e.code == 412: # precondition failed\n                raise ZooKeeper.WrongVersion(uri)\n            raise\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/settings.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nDJANGO_APPS = [ \"zkui\" ]\nNICE_NAME = \"ZooKeeper Browser\"\nREQUIRES_HADOOP = False\n\nCLUSTERS = [{\n        'nice_name': 'Default',\n        'hostport': 'localhost:2181,localhost:2182,localhost:2183',\n        'rest_gateway': 'http://localhost:9998'\n    }\n]\n\nDEPENDER_PACKAGE_YMLS = [\n    \"src/zkui/static/js/package.yml\",\n]\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/static/bootstrap.js",
    "content": "// Licensed to the Apache Software Foundation (ASF) under one\n// or more contributor license agreements.  See the NOTICE file\n// distributed with this work for additional information\n// regarding copyright ownership.  The ASF licenses this file\n// to you under the Apache License, Version 2.0 (the\n// \"License\"); you may not use this file except in compliance\n// with the License.  You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nCCS.Desktop.register({\n\tZkui : {\n\t\tname : 'ZooKeeper Browser',\n\t\tcss : '/zkui/static/css/zkui.css',\n\t\trequire: [ 'Zkui' ],\n\t\tlaunch: function(path, options){\n\t\t\treturn new Zkui(path || '/zkui/', options);\n\t\t},\n\t\tmenu: {\n\t\t\tid: 'ccs-zkui-menu',\n\t\t\timg: {\n\t\t\t\tsrc: '/zkui/static/art/zkui.png'\n\t\t\t}\n\t\t},\n\t\thelp: '/help/zkui/'\n\t}\n});\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/static/css/zkui.css",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n.zkui img.zkui_icon {\n\twidth: 55px;\n\theight: 55px;\n\tposition: absolute;\n\ttop: 27px;\n\tleft: 3px;\n}\n\ndiv.zkui .left_col li {\n    margin: 5px 0px;\n    font-size: 16px;\n    background-color: white;\n    color: black;\n    padding: 2px 1px 1px 5px;\n    -moz-border-radius: 3px;\n    -webkit-border-radius: 3px;\n    border: solid black 1px;\n}\n\ndiv.zkui .left_col li:hover {\n    background-color: lightBlue;\n    color: white;\n}\n\ndiv.zkui .left_col li a {\n    color: black;\n    display: block;\n}\n\ndiv.zkui .left_col li a:hover {\n    text-decoration: none;\n}\n\ndiv.zkui .createZnodeForm td,\ndiv.zkui .editZnodeForm td {\n  padding: 5px;\n}\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/static/help/index.html",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<h1>ZooKeeper Browser</h1>\n\n\n<p>ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services</p>\n\n<h2>About</h2>\n\n<p>The ZooKeeper Browser application allows you to see how the cluster nodes are working and also allows you to do CRUD operations on the znode hierarchy.</p>\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/static/js/Source/Zkui/Zkui.js",
    "content": "// Licensed to the Apache Software Foundation (ASF) under one\n// or more contributor license agreements.  See the NOTICE file\n// distributed with this work for additional information\n// regarding copyright ownership.  The ASF licenses this file\n// to you under the Apache License, Version 2.0 (the\n// \"License\"); you may not use this file except in compliance\n// with the License.  You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/*\n---\n\nscript: Zkui.js\n\ndescription: Defines Zkui; a Hue application that extends CCS.JBrowser.\n\nauthors:\n- Unknown\n\nrequires:\n- ccs-shared/CCS.JBrowser\n\nprovides: [Zkui]\n\n...\n*/\nART.Sheet.define('window.art.browser.zkui', {\n\t'min-width': 620\n});\n\nvar Zkui = new Class({\n\n\tExtends: CCS.JBrowser,\n\n\toptions: {\n\t\tclassName: 'art browser logo_header zkui'\n\t},\n\n\tinitialize: function(path, options){\n\t\tthis.parent(path || '/zkui/', options);\n\t}\n\n});\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/static/js/package.yml",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\ncopyright: Apache License v2.0\nversion: 0.1\ndescription: ZooKeeper Browser\nname: ZooKeeper Browser\nsources: [Source/Zkui/Zkui.js]\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/stats.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport socket\nimport re\n\nfrom StringIO import StringIO\n\nclass Session(object):\n\n  class BrokenLine(Exception): pass\n\n  def __init__(self, session):\n    m = re.search('/(\\d+\\.\\d+\\.\\d+\\.\\d+):(\\d+)\\[(\\d+)\\]\\((.*)\\)', session)\n    if m:\n        self.host = m.group(1)\n        self.port = m.group(2)\n        self.interest_ops = m.group(3)\n        for d in m.group(4).split(\",\"):\n            k,v = d.split(\"=\")\n            self.__dict__[k] = v\n    else:\n        raise Session.BrokenLine() \n\nclass ZooKeeperStats(object):\n\n    def __init__(self, host='localhost', port='2181', timeout=1):\n        self._address = (host, int(port))\n        self._timeout = timeout\n\n    def get_stats(self):\n        \"\"\" Get ZooKeeper server stats as a map \"\"\"\n        data = self._send_cmd('mntr')\n        if data:\n            return self._parse(data)\n        else:\n            data = self._send_cmd('stat')\n            return self._parse_stat(data)\n\n    def get_clients(self):\n      \"\"\" Get ZooKeeper server clients \"\"\"\n      clients = []\n\n      stat = self._send_cmd('stat')\n      if not stat:\n        return clients\n\n      sio = StringIO(stat)\n\n      #skip two lines\n      sio.readline()\n      sio.readline()\n\n      for line in sio:\n        if not line.strip():\n          break\n        try:\n          clients.append(Session(line.strip()))\n        except Session.BrokenLine:\n          continue\n\n      return clients\n\n    def _create_socket(self):\n        return socket.socket()\n\n    def _send_cmd(self, cmd):\n        \"\"\" Send a 4letter word command to the server \"\"\"\n        s = self._create_socket()\n        s.settimeout(self._timeout)\n\n        s.connect(self._address)\n        s.send(cmd)\n\n        data = s.recv(2048)\n        s.close()\n\n        return data\n\n    def _parse(self, data):\n        \"\"\" Parse the output from the 'mntr' 4letter word command \"\"\"\n        h = StringIO(data)\n        \n        result = {}\n        for line in h.readlines():\n            try:\n                key, value = self._parse_line(line)\n                result[key] = value\n            except ValueError:\n                pass # ignore broken lines\n\n        return result\n\n    def _parse_stat(self, data):\n        \"\"\" Parse the output from the 'stat' 4letter word command \"\"\"\n        h = StringIO(data)\n\n        result = {}\n        \n        version = h.readline()\n        if version:\n            result['zk_version'] = version[version.index(':')+1:].strip()\n\n        # skip all lines until we find the empty one\n        while h.readline().strip(): pass\n\n        for line in h.readlines():\n            m = re.match('Latency min/avg/max: (\\d+)/(\\d+)/(\\d+)', line)\n            if m is not None:\n                result['zk_min_latency'] = int(m.group(1))\n                result['zk_avg_latency'] = int(m.group(2))\n                result['zk_max_latency'] = int(m.group(3))\n                continue\n\n            m = re.match('Received: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_received'] = int(m.group(1))\n                continue\n\n            m = re.match('Sent: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_sent'] = int(m.group(1))\n                continue\n\n            m = re.match('Outstanding: (\\d+)', line)\n            if m is not None:\n                result['zk_outstanding_requests'] = int(m.group(1))\n                continue\n\n            m = re.match('Mode: (.*)', line)\n            if m is not None:\n                result['zk_server_state'] = m.group(1)\n                continue\n\n            m = re.match('Node count: (\\d+)', line)\n            if m is not None:\n                result['zk_znode_count'] = int(m.group(1))\n                continue\n\n        return result \n\n    def _parse_line(self, line):\n        try:\n            key, value = map(str.strip, line.split('\\t'))\n        except ValueError:\n            raise ValueError('Found invalid line: %s' % line)\n\n        if not key:\n            raise ValueError('The key is mandatory and should not be empty')\n\n        try:\n            value = int(value)\n        except (TypeError, ValueError):\n            pass\n\n        return key, value\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/clients.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser > Clients > %s:%s\" % (host, port))}\n\n<h1>${host}:${port} :: client connections</h1>\n<br />\n\n% if clients:\n  <table data-filters=\"HtmlTable\"> \n  <thead>\n    <tr>\n      <th>Host</th>\n      <th>Port</th>\n      <th>Interest Ops</th>\n      <th>Queued</th>\n      <th>Received</th>\n      <th>Sent</th>\n  </thead>\n  % for client in clients:\n    <tr>\n      <td>${client.host}</td>\n      <td>${client.port}</td>\n      <td>${client.interest_ops}</td>\n      <td>${client.queued}</td>\n      <td>${client.recved}</td>\n      <td>${client.sent}</td>\n    </tr>\n  % endfor\n  </table>\n% endif\n\n${shared.footer()}\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/create.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser > Create Znode\")}\n\n<h2>Create New Znode :: ${path}</h2>\n<hr /><br />\n\n<form class=\"createZnodeForm\" action=\"\" method=\"POST\">\n<table align=\"center\">\n  ${form.as_table()|n}\n<tr><td colspan=\"2\" align=\"right\">\n  <button type=\"submit\">Create</button>\n</td></tr>\n</table>\n</form>\n\n${shared.footer()}\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/edit.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser > Edit Znode > %s\" % path)}\n\n<h2>Edit Znode Data :: ${path}</h2>\n<hr /><br />\n\n<form class=\"editZnodeForm\" action=\"\" method=\"POST\">\n<table align=\"center\">\n  ${form.as_table()|n}\n<tr><td colspan=\"2\" align=\"right\">\n  <button type=\"submit\">Save</button>\n</td></tr>\n</table>\n</form>\n\n${shared.footer()}\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/index.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser\")}\n\n<h2>Overview</h2>\n\n<br />\n\n% for i, c in enumerate(overview):\n  <h3> ${i+1}. <a href=\"${url('zkui.views.view', id=i)}\">${c['nice_name']} Cluster Overview</a></h3><br />\n\n  <table data-filters=\"HtmlTable\">\n  <thead>\n    <tr>\n      <th>Node</th>\n      <th>Role</th>\n      <th>Avg Latency</th>\n      <th>Watch Count</th>\n      <th>Version</th>\n    </tr>\n  </thead>\n  % for host, stats in c['stats'].items():\n    <tr>\n      <td>${host}</td>\n      <td>${stats.get('zk_server_state', '')}</td>\n      <td>${stats.get('zk_avg_latency', '')}</td>\n      <td>${stats.get('zk_watch_count', '')}</td>\n      <td>${stats.get('zk_version', '')}</td>\n    </tr>\n  % endfor\n  </table>\n\n  <br /><br />\n% endfor \n\n${shared.footer()}\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/shared_components.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n\n<%!\nimport datetime\nfrom django.template.defaultfilters import urlencode, escape\nfrom zkui import settings\n%>\n\n<%def name=\"header(title='ZooKeeper Browser', toolbar=True)\">\n  <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n  <html>\n    <head>\n      <title>${title}</title>\n    </head>\n    <body>\n      % if toolbar:\n      <div class=\"toolbar\">\n        <a href=\"${url('zkui.views.index')}\"><img src=\"/zkui/static/art/zkui.png\" class=\"zkui_icon\"/></a>\n      </div>\n      % endif\n\n    <div data-filters=\"SplitView\">\n    <div class=\"left_col jframe_padded\" style=\"width:150px;\">\n        <ul>\n          <li><a href=\"${url(\"zkui.views.index\")}\">Overview</a></li>\n        </ul>\n        <br />\n\n        <h2>Clusters</h2>\n        <ul>\n            % for id, c in enumerate(settings.CLUSTERS):\n                <li><a href=\"${url(\"zkui.views.view\", id=id)}\">\n                    ${c['nice_name']}</a></li>\n            % endfor\n        </ul>\n    </div>\n\n    <div class=\"right_col jframe_padded\">\n</%def>\n\n<%def name=\"info_button(url, text)\">\n  <a data-filters=\"ArtButton\" href=\"${url}\" style=\"background: url(/static/art/info.png) left 50%; padding: 6px 6px 6px 20px; margin: 10px;\" data-icon-styles=\"{'width': 14, 'height': 14}\">${text}</a>\n</%def>\n\n<%def name=\"footer()\">\n        </div>\n    </div>\n    </body>\n  </html>\n</%def>\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/tree.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser > Tree > %s > %s\" % (cluster['nice_name'], path))}\n\n<h1>${cluster['nice_name'].lower()} :: ${path}</h1>\n<br />\n\n<table data-filters=\"HtmlTable\">\n  <thead>\n  <th colspan=\"2\">Children</th>\n  </thead>\n  % for child in children:\n    <tr><td width=\"100%\">\n      <a href=\"${url('zkui.views.tree', id=cluster['id'], \\\n          path=(\"%s/%s\" % (path, child)).replace('//', '/'))}\">\n      ${child}</a>\n    </td><td>\n      <a title=\"Delete ${child}\" class=\"delete frame_tip confirm_and_post\" alt=\"Are you sure you want to delete ${child}?\" href=\"${url('zkui.views.delete', id=cluster['id'], \\\n          path=(\"%s/%s\" % (path, child)).replace('//', '/'))}\">Delete</a>\n    </td></tr>\n  % endfor\n</table>\n<br />\n<span style=\"float: right\">\n  ${shared.info_button(url('zkui.views.create', id=cluster['id'], path=path), 'Create New')}\n</span>\n\n<div style=\"clear: both\"></div>\n\n<h2>data :: base64 :: length :: ${znode.get('dataLength', 0)}</h2>\n<br />\n\n<textarea name=\"data64\" style=\"width: 100%;\" rows=\"5\" readonly=\"readonly\">${znode.get('data64', '')}</textarea>\n<div style=\"clear: both\"></div>\n<span style=\"float: right\">\n  ${shared.info_button(url('zkui.views.edit_as_base64', id=cluster['id'], path=path), 'Edit as Base64')}\n  ${shared.info_button(url('zkui.views.edit_as_text', id=cluster['id'], path=path), 'Edit as Text')}\n</span>\n<div style=\"clear: both\"></div>\n<br />\n\n<h2>stat information</h2>\n<br />\n\n<table data-filters=\"HtmlTable\">\n  <thead><tr><th>Key</th>\n    <th width=\"80%\">Value</th></tr></thead>\n  % for key in ('pzxid', 'ctime', 'aversion', 'mzxid', \\\n      'ephemeralOwner', 'version', 'mtime', 'cversion', 'czxid'):\n    <tr><td>${key}</td><td>${znode[key]}</td></tr> \n  % endfor\n</table>\n\n<br />\n<a target=\"_blank\" href=\"http://zookeeper.apache.org/docs/current/zookeeperProgrammers.html#sc_zkStatStructure\">Details on stat information.</a>\n\n${shared.footer()}\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/templates/view.mako",
    "content": "<%!\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n%>\n<%namespace name=\"shared\" file=\"shared_components.mako\" />\n\n${shared.header(\"ZooKeeper Browser > %s\" % cluster['nice_name'])}\n\n<%def name=\"show_stats(stats)\">\n    <thead>\n      <tr><th>Key</th>\n      <th width=\"100%\">Value</th></tr>\n    </thead>\n\n    <tr><td>Version</td>\n      <td>${stats.get('zk_version')}</td>\n    </tr>\n\n    <tr><td>Latency</td><td>\n      Min: ${stats.get('zk_min_latency', '')}\n      Avg: ${stats.get('zk_avg_latency', '')}\n      Max: ${stats.get('zk_max_latency', '')}\n    </td></tr>\n\n    <tr><td>Packets</td>\n      <td>Sent: ${stats.get('zk_packets_sent', '')}\n      Received: ${stats.get('zk_packets_received', '')}\n      </td>\n    </tr>\n\n    <tr><td>Outstanding Requests</td>\n      <td>${stats.get('zk_outstanding_requests', '')}</td>\n    </tr>\n\n    <tr><td>Watch Count</td>\n      <td>${stats.get('zk_watch_count', '')}</td>\n    </tr>\n\n    <tr><td>Open FD Count</td>\n      <td>${stats.get('zk_open_file_descriptor_count', '')}</td>\n    </tr>\n\n    <tr><td>Max FD Count</td>\n      <td>${stats.get('zk_max_file_descriptor_count', '')}</td>\n    </tr>\n\n</%def> \n\n<h2> ${cluster['nice_name']} Cluster Overview </h2>\n\n${shared.info_button(url('zkui.views.tree', id=cluster['id'], path='/'), 'View Znode Hierarchy')}\n\n<br /><br />\n\n% if leader:\n<h2>General</h2>\n\n<table data-filters=\"HtmlTable\">\n  <thead>\n    <tr><th>Key</th><th width=\"100%\">Value</th></tr>\n  </thead>\n\n  <tr><td>ZNode Count</td>\n    <td>${leader.get('zk_znode_count', '')}</td></tr>\n\n  <tr><td>Ephemerals Count</td>\n    <td>${leader.get('zk_ephemerals_count', '')}</td></tr>\n\n  <tr><td>Approximate Data Size</td>\n    <td>${leader.get('zk_approximate_data_size', '')} bytes</td></tr>\n\n</table>\n<br /><br />\n% endif\n\n% if leader:\n  <h2>node :: ${leader['host']} :: leader</h2>\n\n  ${shared.info_button(url('zkui.views.clients', host=leader['host']), 'View Client Connections')}\n\n  <br /><br />\n  <table data-filters=\"HtmlTable\">\n    ${show_stats(leader)}\n    \n    <tr><td>Followers</td>\n      <td>${leader.get('zk_followers', '')}</td>\n    </tr>\n\n    <tr><td>Synced Followers</td>\n      <td>${leader.get('zk_synced_followers', '')}</td>\n    </tr>\n\n    <tr><td>Pending Syncs</td>\n      <td>${leader.get('zk_pending_syncs', '')}</td>\n    </tr>\n  \n  </table>\n<br /><br />\n% endif\n\n% for stats in followers:\n  <h2>node :: ${stats['host']} :: follower</h2>\n  <br />\n\n  ${shared.info_button(url('zkui.views.clients', host=stats['host']), 'View Client Connections')}\n\n  <br /><br />\n  <table data-filters=\"HtmlTable\">\n    ${show_stats(stats)}\n  </table>\n  <br /><br />\n% endfor\n\n${shared.footer()}\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/urls.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom django.conf.urls.defaults import patterns, url\n\nurlpatterns = patterns('zkui',\n  url(r'^$', 'views.index'),\n  url(r'view/(?P<id>\\d+)$', 'views.view'),\n  url(r'clients/(?P<host>.+)$', 'views.clients'),\n  url(r'tree/(?P<id>\\d+)(?P<path>.+)$', 'views.tree'),\n  url(r'create/(?P<id>\\d+)(?P<path>.*)$', 'views.create'),\n  url(r'delete/(?P<id>\\d+)(?P<path>.*)$', 'views.delete'),\n  url(r'edit/base64/(?P<id>\\d+)(?P<path>.*)$', 'views.edit_as_base64'),\n  url(r'edit/text/(?P<id>\\d+)(?P<path>.*)$', 'views.edit_as_text')\n)\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/utils.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom zkui import settings\n\nfrom django.http import Http404\n\ndef get_cluster_or_404(id):\n  try:\n    id = int(id)\n    if not (0 <= id < len(settings.CLUSTERS)):\n      raise ValueError, 'Undefined cluster id.'\n  except (TypeError, ValueError):\n    raise Http404()\n\n  cluster = settings.CLUSTERS[id]\n  cluster['id'] = id\n\n  return cluster\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/views.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom desktop.lib.django_util import render\nfrom django.http import Http404\n\nfrom zkui import settings\nfrom zkui.stats import ZooKeeperStats\nfrom zkui.rest import ZooKeeper\nfrom zkui.utils import get_cluster_or_404\nfrom zkui.forms import CreateZNodeForm, EditZNodeForm\n\ndef _get_global_overview():\n  overview = []\n  for c in settings.CLUSTERS:\n    overview.append(_get_overview(c))\n  return overview\n\ndef _get_overview(cluster):\n  stats = {}\n  for s in cluster['hostport'].split(','):\n    host, port = map(str.strip, s.split(':'))\n\n    zks = ZooKeeperStats(host, port)\n    stats[s] = zks.get_stats() or {}\n\n  cluster['stats'] = stats\n  return cluster\n\ndef _group_stats_by_role(cluster):\n  leader, followers = None, []\n  for host, stats in cluster['stats'].items():\n    stats['host'] = host\n\n    if stats.get('zk_server_state') == 'leader':\n      leader = stats\n\n    elif stats.get('zk_server_state') == 'follower':\n      followers.append(stats) \n\n  return leader, followers           \n \ndef index(request):\n  overview = _get_global_overview()  \n  return render('index.mako', request, \n    dict(overview=overview))\n\ndef view(request, id):\n  cluster = get_cluster_or_404(id)\n\n  cluster = _get_overview(cluster)\n  leader, followers = _group_stats_by_role(cluster)\n\n  return render('view.mako', request, \n    dict(cluster=cluster, leader=leader, followers=followers))\n\ndef clients(request, host):\n  parts = host.split(':')  \n  if len(parts) != 2:\n    raise Http404\n\n  host, port = parts\n  zks = ZooKeeperStats(host, port)\n  clients = zks.get_clients()\n\n  return render('clients.mako', request,\n    dict(host=host, port=port, clients=clients))\n\ndef tree(request, id, path):\n  cluster = get_cluster_or_404(id)\n  zk = ZooKeeper(cluster['rest_gateway'])\n\n  znode = zk.get(path)\n  children = sorted(zk.get_children_paths(path))\n  \n  return render('tree.mako', request,\n    dict(cluster=cluster, path=path, \\\n      znode=znode, children=children))\n\ndef delete(request, id, path):\n  cluster = get_cluster_or_404(id)\n  if request.method == 'POST':\n    zk = ZooKeeper(cluster['rest_gateway'])\n    try:\n      zk.recursive_delete(path)\n    except ZooKeeper.NotFound:\n      pass\n\n  return tree(request, id, path[:path.rindex('/')] or '/')\n\ndef create(request, id, path):\n  cluster = get_cluster_or_404(id)\n\n  if request.method == 'POST':\n    form = CreateZNodeForm(request.POST)\n    if form.is_valid():\n      zk = ZooKeeper(cluster['rest_gateway'])\n\n      full_path = (\"%s/%s\" % (path, form.cleaned_data['name']))\\\n        .replace('//', '/')\n\n      zk.create(full_path, \\\n        form.cleaned_data['data'], \\\n        sequence = form.cleaned_data['sequence'])\n      return tree(request, id, path)\n  else:\n    form = CreateZNodeForm()\n\n  return render('create.mako', request, \n    dict(path=path, form=form))\n\ndef edit_as_base64(request, id, path):\n  cluster = get_cluster_or_404(id)\n  zk = ZooKeeper(cluster['rest_gateway'])\n  node = zk.get(path)\n\n  if request.method == 'POST':\n    form = EditZNodeForm(request.POST)\n    if form.is_valid():\n      # TODO is valid base64 string?\n      data = form.cleaned_data['data'].decode('base64')\n      zk.set(path, data, form.cleaned_data['version'])\n\n    return tree(request, id, path)\n  else:\n    form = EditZNodeForm(dict(\\\n      data=node.get('data64', ''), \n      version=node.get('version', '-1')))\n\n  return render('edit.mako', request,\n    dict(path=path, form=form))\n\ndef edit_as_text(request, id, path):\n  cluster = get_cluster_or_404(id)\n  zk = ZooKeeper(cluster['rest_gateway'])\n  node = zk.get(path)\n\n  if request.method == 'POST':\n    form = EditZNodeForm(request.POST)\n    if form.is_valid():\n      zk.set(path, form.cleaned_data['data'])\n\n    return tree(request, id, path)\n  else:\n    form = EditZNodeForm(dict(data=node.get('data64', '')\\\n      .decode('base64').strip(), \n      version=node.get('version', '-1')))\n\n  return render('edit.mako', request,\n    dict(path=path, form=form))\n\n\n"
  },
  {
    "path": "src/contrib/huebrowser/zkui/src/zkui/windmilltests.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom desktop.lib.windmill_util import logged_in_client\n\ndef test_zkui():\n  \"\"\" launches the default view for zkui \"\"\"\n  client = logged_in_client()\n  client.click(id='ccs-zkui-menu')\n  client.waits.forElement(classname='CCS-ZKUI', timeout='2000')  \n"
  },
  {
    "path": "src/contrib/loggraph/README.txt",
    "content": "LogGraph README\n\n1 - About\nLogGraph is an application for viewing and filtering zookeeper logs. It can handle transaction logs and message logs. \n\n2 - Compiling\n\nRun \"ant jar\" in src/contrib/loggraph/. This will download all dependencies and compile all the loggraph code.\n\nOnce compilation has finished, you can run it the the loggraph.sh script in src/contrib/loggraph/bin. This will start and embedded web server on your machine. \nNavigate to http://localhost:8182/graph/main.html\n\n3 - Usage\nLogGraph presents the user with 4 views, \n \n  a) Simple log view\n     This view simply displays the log text. This isn't very useful without filters (see \"Filtering the logs\").\n\n  b) Server view\n     The server view shows the interactions between the different servers in an ensemble. The X axis represents time. \n        * Exceptions show up as red dots. Hovering your mouse over them will give you more details of the exception\n\t* The colour of the line represents the election state of the server. \n\t   - orange means LOOKING for leader\n\t   - dark green means the server is the leader\n\t   - light green means the server is following a leader\n\t   - yellow means there isn't enough information to determine the state of the server. \n\t* The gray arrows denote election messages between servers. Pink dashed arrows are messages that were sent but never delivered.\n\n  c) Session view\n     The session view shows the lifetime of sessions on a server. Use the time filter to narrow down the view. Any more than about 2000 events will take a long time to view in your browser. \n     The X axis represents time. Each line is a session. The black dots represent events on the session. You can click on the black dots for more details of the event.\n\n  d) Stats view\n     There is currently only one statistics view, Transactions/minute. Suggestions for other statistic views are very welcome.\n\n4 - Filtering the logs\nThe logs can be filtered in 2 ways, by time and by content. \n\nTo filter by time simply move the slider to the desired start time. The time window specifies how many milliseconds after and including the start time will be displayed.\n\nContent filtering uses a adhoc filtering language, using prefix notation. The language looks somewhat similar to lisp. A statement in the language takes the form (op arg arg ....). A statement resolves to a boolean value. Statements can be nested. \n\n4.1 - Filter arguments\nAn argument can be a number, a string or a symbol. A number is any argument which starts with -, + or 0 to 9. If the number starts with 0x it is interpretted as hexidecimal. Otherwise it is interpretted as decimal. If the argument begins with a double-quote, (\") it is interpretted as a string. Anything else is interpretted as a symbol.\n\n4.2 - Filter symbols\nThe possible filter symbols are: \n\nclient-id : number, the session id of the client who initiated a transaction.\ncxid : number, the cxid of a transaction\nzxid : number, the zxid of a transaction\noperation : string, the operation being performed, for example \"setData\", \"createSession\", \"closeSession\", \"error\", \"create\"\n\n4.3 - Filter operations\nThe possible filter operations are:\n\nor : logical or, takes 1 or more arguments which must be other statements.\nand : logical and, takes 1 or more arguments which must be other statements.\nnot : logical not, takes 1 argument which must be another statement.\nxor : exclusive or, takes 1 or more arguments which must be other statements.\n= : equals, takes 1 or more arguments, which must all be equal to each other to return true.\n> : greater than, takes 1 or more arguments, to return true the 1st argument must be greater than the 2nd argument which must be greater than the 3rd argument and so on... \n< : less than, takes 1 or more arguments, to return true the 1st argument must be less than the 2nd argument which must be less than the 3rd argument and so on... \n\n4.3 - Filter examples\nGive me all the setData operations with session id 0xdeadbeef or 0xcafeb33r but not with zxid 0x12341234 ->\n\n(and (= operation \"setData\") (or (= client-id 0xdeadbeef) (= client-id 0xcafeb33r)) (not (= zxid 0x12341234)))\n\n"
  },
  {
    "path": "src/contrib/loggraph/bin/loggraph-dev.sh",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmake_canonical () {\n    cd $1; pwd;\n}\n\nSCRIPTDIR=`dirname $0`\nBUILDDIR=`make_canonical $SCRIPTDIR/../../../../build/contrib/loggraph`\nLIBDIR=`make_canonical $BUILDDIR/lib`\nWEBDIR=`make_canonical $SCRIPTDIR/../web`\nZKDIR=`make_canonical $SCRIPTDIR/../../../../build/`\n\nif [ ! -x $BUILDDIR ]; then\n    echo \"\\n\\n*** You need to build loggraph before running it ***\\n\\n\";\n    exit;\nfi\n\nfor i in `ls $LIBDIR`; do \n    CLASSPATH=$LIBDIR/$i:$CLASSPATH\ndone\n\nfor i in $ZKDIR/zookeeper-*.jar; do\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\nCLASSPATH=$BUILDDIR/classes:$WEBDIR:$CLASSPATH\necho $CLASSPATH\njava -Dlog4j.configuration=org/apache/zookeeper/graph/log4j.properties -Xdebug -Xrunjdwp:transport=dt_socket,address=4444,server=y,suspend=n -cp $CLASSPATH org.apache.zookeeper.graph.LogServer $*\n"
  },
  {
    "path": "src/contrib/loggraph/bin/loggraph.sh",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmake_canonical () {\n    cd $1; pwd;\n}\n\nSCRIPTDIR=`dirname $0`\nBUILDDIR=`make_canonical $SCRIPTDIR/../../../../build/contrib/loggraph`\nLIBDIR=`make_canonical $BUILDDIR/lib`\nZKDIR=`make_canonical $SCRIPTDIR/../../../../build/`\n\nif [ ! -x $BUILDDIR ]; then\n    echo \"\\n\\n*** You need to build loggraph before running it ***\\n\\n\";\n    exit;\nfi\n\nfor i in `ls $LIBDIR`; do \n    CLASSPATH=$LIBDIR/$i:$CLASSPATH\ndone\n\nfor i in `ls $BUILDDIR/*.jar`; do \n    CLASSPATH=$i:$CLASSPATH\ndone\n\nfor i in $ZKDIR/zookeeper-*.jar; do\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\njava -cp $CLASSPATH org.apache.zookeeper.graph.LogServer $*\n\n\n\n\n"
  },
  {
    "path": "src/contrib/loggraph/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"loggraph\" default=\"jar\">\n\n  <import file=\"../build-contrib.xml\"/>\n  \n  <target name=\"init\" depends=\"check-contrib,zookeeperbuildcontrib.init\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <antcall target=\"init-contrib\"/>\n  </target>\n\n  <target name=\"compile\" depends=\"init,ivy-retrieve,zookeeperbuildcontrib.compile\" unless=\"skip.contrib\">\n  </target>\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\" value=\"${build.dir}/zookeeper-${version}-${name}.jar\"/>\n  </target>\n\n  <target name=\"jar\" depends=\"setjarname,compile\"  >\n    <jar destfile=\"${jarname}\">\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset dir=\"${build.classes}\" />\n      <fileset dir=\"web\"/>\n      <manifest>\n        <attribute name=\"Built-By\" value=\"${user.name}\"/>\n        <attribute name=\"Built-At\" value=\"${build.time}\"/>\n        <attribute name=\"Built-On\" value=\"${host.name}\" />\n        <attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper.graph\"/>\n        <attribute name=\"Implementation-Version\" value=\"${revision}\"/>\n        <attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\"/>\n      </manifest>\n    </jar>\n  </target>\n  \n  <target name=\"test\">\n    <echo message=\"No test target defined for this package\" />\n  </target>\n  \n\n  <target name=\"package\" depends=\"compile, zookeeperbuildcontrib.package\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    \n    <copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}/contrib/${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}/src\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}/src\">\n      <fileset dir=\"${basedir}/src\"/>\n    </copy>\n\n  </target>\n\n</project>\n"
  },
  {
    "path": "src/contrib/loggraph/ivy.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<ivy-module version=\"2.0\"\n            xmlns:e=\"http://ant.apache.org/ivy/extra\">\n\n  <info organisation=\"org.apache.zookeeper\"\n        module=\"${name}\" revision=\"${version}\">\n    <license name=\"Apache 2.0\"/>\n    <ivyauthor name=\"Apache ZooKeeper\" url=\"http://zookeeper.apache.org\"/>\n    <description>ZooKeeper Graphing</description>\n  </info>\n\n  <configurations defaultconfmapping=\"default\">\n    <conf name=\"default\"/>\n    <conf name=\"test\"/>\n  </configurations>\n\n  <dependencies>\n    <dependency org=\"org.slf4j\" name=\"slf4j-api\" rev=\"1.6.1\"/>\n    <dependency org=\"org.slf4j\" name=\"slf4j-log4j12\" rev=\"1.6.1\" transitive=\"false\"/>\n  \n    <!-- transitive false turns off dependency checking, log4j deps seem borked -->\n    <dependency org=\"log4j\" name=\"log4j\" rev=\"1.2.15\" transitive=\"false\"/>\n    <dependency org=\"org.eclipse.jetty\" name=\"jetty-server\" rev=\"7.0.1.v20091125\" />\n    <dependency org=\"org.eclipse.jetty\" name=\"jetty-servlet\" rev=\"7.0.1.v20091125\" />\n    <dependency org=\"com.googlecode.json-simple\" name=\"json-simple\" rev=\"1.1\" />\n  </dependencies>\n\n</ivy-module>\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/FilterException.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\npublic class FilterException extends Exception {\n    public FilterException(String s) { super(s); }\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/FilterOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.util.ArrayList;\nimport org.apache.zookeeper.graph.filterops.*;\n\npublic abstract class FilterOp {\n    protected ArrayList<FilterOp> subOps;\n    protected ArrayList<Arg> args;\n\n    public enum ArgType {\n\tSTRING, NUMBER, SYMBOL\n    }\n\n    public FilterOp() {\n\tsubOps = new ArrayList<FilterOp>();\n\targs = new ArrayList<Arg>();\n    }\n\n    public static FilterOp newOp(String op) throws FilterException {\n\tif (op.equals(\"or\")) \n\t    return new OrOp();\n\tif (op.equals(\"and\"))\n\t    return new AndOp();\n\tif (op.equals(\"not\"))\n\t    return new NotOp();\n\tif (op.equals(\"xor\"))\n\t    return new XorOp();\n\tif (op.equals(\"=\"))\n\t    return new EqualsOp();\n\tif (op.equals(\"<\"))\n\t    return new LessThanOp();\n\tif (op.equals(\">\")) \n\t    return new GreaterThanOp();\n\n\tthrow new FilterException(\"Invalid operation '\"+op+\"'\");\n    }\n\n    public void addSubOp(FilterOp op) {\n\tsubOps.add(op);\n    }\n    \n    public void addArg(Arg arg) {\n\targs.add(arg); \n    }\n\n    public abstract boolean matches(LogEntry entry) throws FilterException;\n    \n    public String toString() {\n\tString op = \"(\" + getClass().getName();\n\tfor (FilterOp f :  subOps) {\n\t    op += \" \" + f;\n\t}\n\tfor (Arg a : args) {\n\t    op += \" \" + a;\n\t}\n\treturn op + \")\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/FilterParser.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.PushbackReader;\nimport java.io.StringReader;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport org.apache.zookeeper.graph.filterops.*;\n\npublic class FilterParser {\n    private PushbackReader reader;\n\n    public FilterParser(String s) {\n\treader = new PushbackReader(new StringReader(s));\n    }\n\n    private String readUntilSpace() throws IOException {\n\tStringBuffer buffer = new StringBuffer();\n\n\tint c = reader.read();\n\twhile (!Character.isWhitespace(c) && c != ')' && c != '(') {\n\t    buffer.append((char)c);\n\t    c = reader.read();\n\t    if (c == -1) {\n\t\tbreak;\n\t    }\n\t}\t\n\treader.unread(c);\n\n\treturn buffer.toString().trim();\n    }\n\n    private StringArg readStringArg() throws IOException, FilterException {\n\tint c = reader.read();\n\tint last = 0;\n\tif (c != '\"') {\n\t    throw new FilterException(\"Check the parser, trying to read a string that doesn't begin with quotes\");\n\t}\n\tStringBuffer buffer = new StringBuffer();\n\twhile (reader.ready()) {\n\t    last = c;\n\t    c = reader.read();\n\t    if (c == -1) {\n\t\tbreak;\n\t    }\n\t    \n\t    if (c == '\"' && last != '\\\\') {\n\t\treturn new StringArg(buffer.toString());\n\t    } else {\n\t\tbuffer.append((char)c);\n\t    }\n\t}\n\tthrow new FilterException(\"Unterminated string\");\n    }\n\n    private NumberArg readNumberArg() throws IOException, FilterException {\n\tString strval = readUntilSpace();\n\t\n\ttry {\n\t    if (strval.startsWith(\"0x\")) {\n\t\treturn new NumberArg(Long.valueOf(strval.substring(2), 16));\n\t    } else {\n\t\treturn new NumberArg(Long.valueOf(strval));\n\t    }\n\t} catch (NumberFormatException e) {\n\t    throw new FilterException(\"Not a number [\" + strval + \"]\\n\" + e);\n\t}\n    }\n\n    private SymbolArg readSymbolArg() throws IOException, FilterException {\n\treturn new SymbolArg(readUntilSpace());\n    }\n\n    public FilterOp parse() throws IOException, FilterException {\n\tint c = reader.read();\n\tif (c != '(') {\n\t    throw new FilterException(\"Invalid format\");\n\t}\n\n\tString opstr = readUntilSpace();\n\tFilterOp op = FilterOp.newOp(opstr);\n\n\twhile (reader.ready()) {\n\t    c = reader.read();\n\t    if (c == -1) {\n\t\tbreak;\n\t    }\n\t    if (c == '(') {\n\t\treader.unread(c);\n\t\top.addSubOp(parse());\n\t    } else if (c == ')') {\n\t\treturn op;\n\t    } else if (c == '\"') {\n\t\treader.unread(c);\n\t\top.addArg(readStringArg());\n\t    } else if (Character.isDigit(c) || c == '-' || c == '+') {\n\t\treader.unread(c);\n\t\top.addArg(readNumberArg());\n\t    } else if (Character.isJavaIdentifierStart(c)) {\n\t\treader.unread(c);\n\t\top.addArg(readSymbolArg());\n\t    }\n\t}\n\tthrow new FilterException(\"Incomplete filter\");\n    }\n\n    public static void main(String[] args) throws IOException, FilterException {\n\tif (args.length == 1) {\n\t    System.out.println(new FilterParser(args[0]).parse());\n\t} else {\n\t    System.out.println(new FilterParser(\"(or (and (= session foobar) (= session barfoo)) (= session sdfs))\").parse());\n\t}\n    }\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/JsonGenerator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\nimport java.io.Writer;\nimport java.io.OutputStreamWriter;\nimport java.io.IOException;\nimport java.util.regex.Pattern;\nimport java.util.regex.Matcher;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.ListIterator;\n\npublic class JsonGenerator {\n    private JSONObject root;\n    private HashSet<Integer> servers;\n\n    private class Message {\n\tprivate int from;\n\tprivate int to;\n\tprivate long zxid;\n\n\tpublic Message(int from, int to, long zxid) {\n\t    this.from = from;\n\t    this.to = to;\n\t    this.zxid = zxid;\n\t}\n\t\n\tpublic boolean equals(Message m) {\n\t    return (m.from == this.from \n\t\t    && m.to == this.to\n\t\t    && m.zxid == this.zxid);\n\t}\n    };\n\n    public JSONObject txnEntry(TransactionEntry e) {\n\tJSONObject event = new JSONObject();\n\n\tevent.put(\"time\", Long.toString(e.getTimestamp()));\n\tevent.put(\"client\", Long.toHexString(e.getClientId()));\n\tevent.put(\"cxid\", Long.toHexString(e.getCxid()));\n\tevent.put(\"zxid\", Long.toHexString(e.getZxid()));\n\tevent.put(\"op\", e.getOp());\n\tevent.put(\"extra\", e.getExtra());\n\tevent.put(\"type\", \"transaction\");\n\n\treturn event;\n    }\n\n    /**\n       Assumes entries are sorted by timestamp.\n     */\n    public JsonGenerator(LogIterator iter) {\n\tservers = new HashSet<Integer>();\n\n\tPattern stateChangeP = Pattern.compile(\"- (LOOKING|FOLLOWING|LEADING)\");\n\tPattern newElectionP = Pattern.compile(\"New election. My id =  (\\\\d+), Proposed zxid = (\\\\d+)\");\n\tPattern receivedProposalP = Pattern.compile(\"Notification: (\\\\d+) \\\\(n.leader\\\\), (\\\\d+) \\\\(n.zxid\\\\), (\\\\d+) \\\\(n.round\\\\), .+ \\\\(n.state\\\\), (\\\\d+) \\\\(n.sid\\\\), .+ \\\\(my state\\\\)\");\n\tPattern exceptionP = Pattern.compile(\"xception\");\n\t\n\troot = new JSONObject();\n\tMatcher m = null;\n\tJSONArray events = new JSONArray();\n\troot.put(\"events\", events);\n\t\n\tlong starttime = Long.MAX_VALUE;\n\tlong endtime = 0;\n\n\tint leader = 0;\n\tlong curEpoch = 0;\n\tboolean newEpoch = false;\n\n\twhile (iter.hasNext()) {\n\t    LogEntry ent = iter.next();\n\t    \n\t    if (ent.getTimestamp() < starttime) {\n\t\tstarttime = ent.getTimestamp();\n\t    }\n\t    if (ent.getTimestamp() > endtime) {\n\t\tendtime = ent.getTimestamp();\n\t    }\n\t    \n\t    if (ent.getType() == LogEntry.Type.TXN) {\n\t\tevents.add(txnEntry((TransactionEntry)ent));\n\t    } else {\n\t\tLog4JEntry e = (Log4JEntry)ent;\n\t\tservers.add(e.getNode());\n\t\t\n\t\tif ((m = stateChangeP.matcher(e.getEntry())).find()) {\n\t\t    JSONObject stateChange = new JSONObject();\n\t\t    stateChange.put(\"type\", \"stateChange\");\n\t\t    stateChange.put(\"time\", e.getTimestamp());\n\t\t    stateChange.put(\"server\", e.getNode());\n\t\t    stateChange.put(\"state\", m.group(1));\n\t\t    events.add(stateChange);\n\t\t    \n\t\t    if (m.group(1).equals(\"LEADING\")) {\n\t\t\tleader = e.getNode();\n\t\t    }\n\t\t} else if ((m = newElectionP.matcher(e.getEntry())).find()) {\n\t\t    Iterator<Integer> iterator = servers.iterator();\n\t\t    long zxid = Long.valueOf(m.group(2));\n\t\t    int count = (int)zxid;// & 0xFFFFFFFFL;\n\t\t    int epoch = (int)Long.rotateRight(zxid, 32);// >> 32;\n\t\t    \n\t\t    if (leader != 0 && epoch > curEpoch) {\n\t\t\tJSONObject stateChange = new JSONObject();\n\t\t\tstateChange.put(\"type\", \"stateChange\");\n\t\t\tstateChange.put(\"time\", e.getTimestamp());\n\t\t\tstateChange.put(\"server\", leader);\n\t\t\tstateChange.put(\"state\", \"INIT\");\n\t\t\tevents.add(stateChange);\n\t\t\tleader = 0;\n\t\t    }\n\t\t    \n\t\t    while (iterator.hasNext()) {\n\t\t\tint dst = iterator.next();\n\t\t\tif (dst != e.getNode()) {\n\t\t\t    JSONObject msg = new JSONObject();\n\t\t\t    msg.put(\"type\", \"postmessage\");\n\t\t\t    msg.put(\"src\", e.getNode());\n\t\t\t    msg.put(\"dst\", dst);\n\t\t\t    msg.put(\"time\", e.getTimestamp());\n\t\t\t    msg.put(\"zxid\", m.group(2));\n\t\t\t    msg.put(\"count\", count);\n\t\t\t    msg.put(\"epoch\", epoch);\n\t\t\t    \n\t\t\t    events.add(msg);\n\t\t\t}\n\t\t    }\n\t\t} else if ((m = receivedProposalP.matcher(e.getEntry())).find()) {\n\t\t    // Pattern.compile(\"Notification: \\\\d+, (\\\\d+), (\\\\d+), \\\\d+, [^,]*, [^,]*, (\\\\d+)\");//, LOOKING, LOOKING, 2\n\t\t    int src = Integer.valueOf(m.group(4));\n\t\t    long zxid = Long.valueOf(m.group(2));\n\t\t    int dst = e.getNode();\n\t\t    long epoch2 = Long.valueOf(m.group(3));\n\t\t    \n\t\t    int count = (int)zxid;// & 0xFFFFFFFFL;\n\t\t    int epoch = (int)Long.rotateRight(zxid, 32);// >> 32;\n\t\t    \n\t\t    if (leader != 0 && epoch > curEpoch) {\n\t\t\tJSONObject stateChange = new JSONObject();\n\t\t\tstateChange.put(\"type\", \"stateChange\");\n\t\t\tstateChange.put(\"time\", e.getTimestamp());\n\t\t\tstateChange.put(\"server\", leader);\n\t\t\tstateChange.put(\"state\", \"INIT\");\n\t\t\tevents.add(stateChange);\n\t\t\tleader = 0;\n\t\t    }\n\t\t    \n\t\t    if (src != dst) {\n\t\t\tJSONObject msg = new JSONObject();\n\t\t\tmsg.put(\"type\", \"delivermessage\");\n\t\t\tmsg.put(\"src\", src);\n\t\t\tmsg.put(\"dst\", dst);\n\t\t\tmsg.put(\"time\", e.getTimestamp());\n\t\t\tmsg.put(\"zxid\", zxid);\n\t\t\tmsg.put(\"epoch\", epoch);\n\t\t\tmsg.put(\"count\", count);\n\t\t\tmsg.put(\"epoch2\", epoch2);\n\t\t\t\n\t\t\tevents.add(msg);\n\t\t    }\n\t\t} else if ((m = exceptionP.matcher(e.getEntry())).find()) {\n\t\t    JSONObject ex = new JSONObject();\n\t\t    ex.put(\"type\", \"exception\");\n\t\t    ex.put(\"server\", e.getNode());\n\t\t    ex.put(\"time\", e.getTimestamp());\n\t\t    ex.put(\"text\", e.getEntry());\n\t\t    events.add(ex);\n\t\t} \n\t    }\n\t    JSONObject ex = new JSONObject();\n\t    ex.put(\"type\", \"text\");\n\t    ex.put(\"time\", ent.getTimestamp());\n\t    String txt = ent.toString();\n\t    ex.put(\"text\", txt);\n\t    events.add(ex);\n\t}\n\t//\tSystem.out.println(\"pending messages: \"+pendingMessages.size());\n\troot.put(\"starttime\", starttime);\n\troot.put(\"endtime\", endtime);\n\n\tJSONArray serversarray = new JSONArray();\n\troot.put(\"servers\", serversarray);\n\t\n\tIterator<Integer> iterator = servers.iterator();\n\twhile (iterator.hasNext()) {\n\t    serversarray.add(iterator.next());\n\t}\n    }\n\n    public String toString() {\n\treturn JSONValue.toJSONString(root);\n    }\n\n    public static void main(String[] args) throws Exception {\n\tMergedLogSource src = new MergedLogSource(args);\n\tLogIterator iter = src.iterator();\n\tSystem.out.println(new JsonGenerator(iter));\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/Log4JEntry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\npublic class Log4JEntry extends LogEntry {\n    public Log4JEntry(long timestamp, int node, String entry) { \n\tsuper(timestamp);\n\tsetAttribute(\"log-text\", entry);\n\tsetAttribute(\"node\", new Integer(node));\n    }\n\n    public String getEntry() {\n\treturn (String) getAttribute(\"log-text\");\n    }\n\n    public String toString() {\n\treturn \"\" + getTimestamp() + \"::::\" + getNode() + \"::::\"  + getEntry();\n    }\n\n    public int getNode() {\n\treturn (Integer) getAttribute(\"node\");\n    }\n\n    public Type getType() { return LogEntry.Type.LOG4J; }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/Log4JSource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.regex.Pattern;\nimport java.util.regex.Matcher;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.text.SimpleDateFormat;\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.GregorianCalendar;\n\nimport java.io.EOFException;\nimport java.io.Closeable;\nimport java.io.FileNotFoundException;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Log4JSource implements LogSource {\n    private static final Logger LOG = LoggerFactory.getLogger(Log4JSource.class);\n    \n    private static final int skipN = 10000;\n    private static final String DATE_FORMAT = \"yyyy-MM-dd HH:mm:ss,SSS\";\n\n    private LogSkipList skiplist = null;\n\n    private String file = null;\n    private long starttime = 0;\n    private long endtime = 0;\n    private int serverid = 0;\n    private long size = 0;\n\n    private Pattern timep;\n\n    public boolean overlapsRange(long starttime, long endtime) {\n\treturn (starttime <= this.endtime && endtime >= this.starttime);\n    }\n    \n    public long size() { return size; }\n    public long getStartTime() { return starttime; }\n    public long getEndTime() { return endtime; }\n    public LogSkipList getSkipList() { return skiplist; }\n    \n    private class Log4JSourceIterator implements LogIterator {\n\tprivate RandomAccessFileReader in;\n\tprivate LogEntry next = null;\n\tprivate long starttime = 0;\n\tprivate long endtime = 0;\n\tprivate String buf = \"\";\t\n\tprivate Log4JSource src = null;\n\tprivate long skippedAtStart = 0;\n\tprivate SimpleDateFormat dateformat = null;\n\tprivate FilterOp filter = null;\n\n\tpublic Log4JSourceIterator(Log4JSource src, long starttime, long endtime) throws IllegalArgumentException, FilterException {\n\t    this(src, starttime, endtime, null);\n\t}\n\n\tpublic Log4JSourceIterator(Log4JSource src, long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException {\n\n\t    this.dateformat = new SimpleDateFormat(DATE_FORMAT);\n\t    this.src = src;\n\t    this.starttime = starttime;\n\t    this.endtime = endtime;\n\n\t    File f = new File(src.file);\n\t    try {\n\t\tin = new RandomAccessFileReader(f);\n\t    } catch (FileNotFoundException e) {\n\t\tthrow new IllegalArgumentException(\"Bad file passed in (\" + src.file +\") cannot open:\" + e);\n\t    }\n\n\t    // skip to the offset of latest skip point before starttime\n\t    LogSkipList.Mark start = src.getSkipList().findMarkBefore(starttime);\n\t    try {\n\t\tin.seek(start.getBytes());\n\t\tskippedAtStart = start.getEntriesSkipped();\n\t    } catch (IOException ioe) {\n\t\t// if we can't skip, we should just read from the start\n\t    }\n\n\t    LogEntry e;\n\t    while ((e = readNextEntry()) != null && e.getTimestamp() < endtime) {\n\t\tif (e.getTimestamp() >= starttime && (filter == null || filter.matches(e))) {\n\t\t    next = e;\n\t\t    return;\n\t\t}\n\t\tskippedAtStart++;\n\t    }\n\t    this.filter = filter;\n\t}\n\t\n\tsynchronized public long size() throws IOException {\n\t    if (LOG.isTraceEnabled()) {\n\t\tLOG.trace(\"size() called\");\n\t    }\n\n\t    if (this.endtime >= src.getEndTime()) {\n\t\treturn src.size() - skippedAtStart;\n\t    }\n\t    \n\t    long pos = in.getPosition();\n\t    \n\t    if (LOG.isTraceEnabled()) {\n\t\tLOG.trace(\"saved pos () = \" + pos);\n\t    }\n\t    \n\t    LogEntry e;\n\t  \n\t    LogSkipList.Mark lastseg = src.getSkipList().findMarkBefore(this.endtime);\n\t    in.seek(lastseg.getBytes());\n\t    buf = \"\";  // clear the buf so we don't get something we read before we sought\n\t    // number of entries skipped to get to the end of the iterator, less the number skipped to get to the start\n\t    long count = lastseg.getEntriesSkipped() - skippedAtStart; \n\n\t    while ((e = readNextEntry()) != null) {\n\t\tif (LOG.isTraceEnabled()) {\n\t\t    //LOG.trace(e);\n\t\t}\n\t\tif (e.getTimestamp() > this.endtime) {\n\t\t    break;\n\t\t}\n\t\tcount++;\n\t    }\n\t    in.seek(pos);\n\t    buf = \"\";\n\n\t    if (LOG.isTraceEnabled()) {\n\t\tLOG.trace(\"size() = \" + count);\n\t    }\n\t    \n\t    return count;\n\t}\n\n\tsynchronized private LogEntry readNextEntry() {\n\t    try {\n\t\ttry {\n\t\t    while (true) {\n\t\t\tString line = in.readLine();\n\t\t\tif (line == null) {\n\t\t\t    break;\n\t\t\t}\n\n\t\t\tMatcher m = src.timep.matcher(line);\n\t\t\tif (m.lookingAt()) {\n\t\t\t    if (buf.length() > 0) {\n\t\t\t\tLogEntry e = new Log4JEntry(src.timestampFromText(dateformat, buf), src.getServerId(), buf);\n\t\t\t\tbuf = line;\n\t\t\t\treturn e;\n\t\t\t    }\n\t\t\t    buf = line;\n\t\t\t} else if (buf.length() > 0) {\n\t\t\t    buf += line + \"\\n\";\n\t\t\t}\n\t\t    }\n\t\t} catch (EOFException eof) {\n\t\t    // ignore, we've simply come to the end of the file\n\t\t}\n\t\tif (buf.length() > 0) {\n\t\t    LogEntry e = new Log4JEntry(src.timestampFromText(dateformat, buf), src.getServerId(), buf);\n\t\t    buf = \"\";\n\t\t    return e;\n\t\t}\n\t    } catch (Exception e) {\n\t\tLOG.error(\"Error reading next entry in file (\" + src.file + \"): \" + e);\n\t\treturn null;\n\t    }\n\t    return null;\n\t}\n\n\tpublic boolean hasNext() {\n\t    return next != null;\n\t}\n\t\n\tpublic LogEntry next() throws NoSuchElementException {\n\t    LogEntry ret = next;\n\t    LogEntry e = readNextEntry();\n\n\t    if (filter != null) {\n\t\ttry {\n\t\t    while (e != null && !filter.matches(e)) {\n\t\t\te = readNextEntry();\n\t\t    }\n\t\t} catch (FilterException fe) {\n\t\t    throw new NoSuchElementException(e.toString());\n\t\t}\n\t    }\n\n\t    if (e != null && e.getTimestamp() < endtime) {\n\t\tnext = e;\n\t    } else {\n\t\tnext = null;\n\t    }\n\t    return ret;\n\t}\n\n\tpublic void remove() throws UnsupportedOperationException {\n\t    throw new UnsupportedOperationException(\"remove not supported for L4J logs\");\n\t}\n\t\n\tpublic void close() throws IOException {\n\t    in.close();\n\t}\n\t\n\tpublic String toString() {\n\t    String size;\n\t    try {\n\t\tsize = new Long(size()).toString();\n\t    } catch (IOException ioe) {\n\t\tsize = \"Unable to read\";\n\t    }\n\t    return \"Log4JSourceIterator(start=\" + starttime + \", end=\" + endtime + \", size=\" + size + \")\";\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime) throws IllegalArgumentException {\n\ttry {\n\t    return iterator(starttime, endtime, null);\n\t} catch (FilterException fe) {\n\t    assert(false); //\"This should never happen, you can't have a filter exception without a filter\");\n\t    return null;\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException{\n\t// sanitise start and end times\n\tif (endtime < starttime) {\n\t    throw new IllegalArgumentException(\"End time (\" +  endtime + \") must be greater or equal to starttime (\" + starttime + \")\");\n\t}\n\n\treturn new Log4JSourceIterator(this, starttime, endtime, filter);\n    }\n\n    public LogIterator iterator() throws IllegalArgumentException {\n\treturn iterator(starttime, endtime+1);\n    }\n    \n    public Log4JSource(String file) throws IOException {\n\tthis.file=file;\n\t\n\ttimep = Pattern.compile(\"^(\\\\d{4}-\\\\d{2}-\\\\d{2} \\\\d{2}:\\\\d{2}:\\\\d{2},\\\\d{3})\");\n\tskiplist = new LogSkipList();\n\tinit();\n    }\n    \n    private static long timestampFromText(SimpleDateFormat format, String s) {\n\tDate d = null;\n\ttry {\n\t    d = format.parse(s);\n\t} catch (ParseException e) {\n\t    return 0;\n\t}\n\tCalendar c = new GregorianCalendar();\n\tc.setTime(d);\n\treturn c.getTimeInMillis();\n    }\n\n    private void init() throws IOException {\n\tFile f = new File(file);\n\tRandomAccessFileReader in = new RandomAccessFileReader(f);\n\tSimpleDateFormat dateformat = new SimpleDateFormat(DATE_FORMAT);\n\tPattern idp = Pattern.compile(\"\\\\[myid:(\\\\d+)\\\\]\");\n\n\tlong lastFp = in.getPosition();\n\tString line = in.readLine();\n\tMatcher m = null;\n\n\t// if we have read data from the file, and it matchs the timep pattern\n\tif ((line != null) && (m = timep.matcher(line)).lookingAt()) {\n\t    starttime = timestampFromText(dateformat, m.group(1));\n\t} else {\n\t    throw new IOException(\"Invalid log4j format. First line doesn't start with time\");\n\t}\n\n\t/*\n\t  Count number of log entries. Any line starting with a timestamp counts as an entry\n\t*/\n\tString lastentry = line;\n\ttry {\n\t    while (line != null) {\n\t\tm = timep.matcher(line);\n\t\tif (m.lookingAt()) {\n\t\t    if (size % skipN == 0) {\n\t\t\tlong time = timestampFromText(dateformat, m.group(1));\n\t\t\tskiplist.addMark(time, lastFp, size);\n\t\t    }\n\t\t    size++;\n\t\t    lastentry = line;\n\t\t} \n\t\tif (serverid == 0 && (m = idp.matcher(line)).find()) {\n\t\t    serverid = Integer.valueOf(m.group(1));\n\t\t}\n\n\t\tlastFp = in.getPosition();\n\t\tline = in.readLine();\n\t    }\n\t} catch (EOFException eof) {\n\t    // ignore, simply end of file, though really (line!=null) should have caught this\n\t} finally {\n\t    in.close();\n\t}\n\n\tm = timep.matcher(lastentry);\n\tif (m.lookingAt()) {\n\t    endtime = timestampFromText(dateformat, m.group(1));\n\t} else {\n\t    throw new IOException(\"Invalid log4j format. Last line doesn't start with time\");\n\t}\n    }\n    \n    public String toString() {\n\treturn \"Log4JSource(file=\" + file + \", size=\" + size + \", start=\" + starttime + \", end=\" + endtime +\", id=\" + serverid +\")\";\n    }\n\n    public static void main(String[] args) throws IOException {\n\tfinal Log4JSource s = new Log4JSource(args[0]);\n\tSystem.out.println(s);\n\n\tLogIterator iter;\n\n\tif (args.length == 3) {\n\t    final long starttime = Long.valueOf(args[1]);\n\t    final long endtime = Long.valueOf(args[2]);\n\t    iter = s.iterator(starttime, endtime);\n\t    \n\t    Thread t1 = new Thread() { public void run () { \n\t\t\n\t\tLogIterator iter = s.iterator(starttime, endtime);\n\t\tSystem.out.println(iter);\n\t\ttry {\n\t\t  iter.close();\n\t\t} catch (IOException ioe) {\n\t\t  System.out.println(ioe.getMessage());\n\t\t}\n\t    }; };\n\t    Thread t2 = new Thread() { public void run () { \n\t\t\n\t\tLogIterator iter = s.iterator(starttime, endtime);\n\t\tSystem.out.println(iter);\n\t\ttry {\n\t\t  iter.close();\n\t\t} catch (IOException ioe) {\n\t\t  System.out.println(ioe.getMessage());\n\t\t}\n\t    }; };\n\t    Thread t3 = new Thread() { public void run () { \n\t\t\n\t\tLogIterator iter = s.iterator(starttime, endtime);\n\t\tSystem.out.println(iter);\n\t    }; };\n\t    t1.start();\n\t    t2.start();\n\t    //\t    t3.start();\n\t} else {\n\t    iter = s.iterator();\n\t}\n\n\t/*while (iter.hasNext()) {\n\t    System.out.println(iter.next());\n\t    }*/\n\titer.close();\n    }\n\n    public int getServerId() {\n\treturn serverid;\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/LogEntry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.Serializable;\nimport java.util.HashMap;\n\npublic abstract class LogEntry implements Serializable {\n    private HashMap attributes;\n\n    public enum Type { UNKNOWN, LOG4J, TXN };\n        \n    public LogEntry(long timestamp) {\n\tattributes = new HashMap();\n\tsetAttribute(\"timestamp\", new Long(timestamp));\n    }\n    \n    public long getTimestamp() {\n\treturn (Long)getAttribute(\"timestamp\");\n    }    \n    \n    public abstract Type getType();\n    \n    public void setAttribute(String key, Object v) {\n\tattributes.put(key, v);\n    }\n\n    public Object getAttribute(String key) {\n\treturn attributes.get(key);\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/LogIterator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.Closeable;\nimport java.util.Iterator;\nimport java.io.IOException;\n\npublic interface LogIterator extends Iterator<LogEntry>, Closeable {\n    long size() throws IOException;;\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/LogServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.IOException;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.ServletException;\n \nimport java.io.IOException;\n \nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.Request;\nimport org.eclipse.jetty.server.handler.AbstractHandler;\nimport org.eclipse.jetty.servlet.ServletContextHandler;\nimport org.eclipse.jetty.servlet.ServletHolder;\n\nimport org.apache.zookeeper.graph.servlets.*;\n\npublic class LogServer extends ServletContextHandler {    \n    public LogServer(MergedLogSource src) throws Exception {\n\tsuper(ServletContextHandler.SESSIONS);\n\tsetContextPath(\"/\");\n\n\taddServlet(new ServletHolder(new StaticContent()),\"/graph/*\");\n\n\taddServlet(new ServletHolder(new Fs()),\"/fs\");\n\taddServlet(new ServletHolder(new GraphData(src)), \"/data\");\n\taddServlet(new ServletHolder(new FileLoader(src)), \"/loadfile\");\n\taddServlet(new ServletHolder(new NumEvents(src)), \"/info\");\n\taddServlet(new ServletHolder(new Throughput(src)), \"/throughput\");\n    }\n\n    public static void main(String[] args) {  \n\ttry {  \n\t    MergedLogSource src = new MergedLogSource(args);\n\t    System.out.println(src);\n\n\t    Server server = new Server(8182);\n\t    server.setHandler(new LogServer(src));\n\t    \n\t    server.start();\n\t    server.join();\n\n\t} catch (Exception e) {  \n\t    // Something is wrong.  \n\t    e.printStackTrace();  \n\t}  \n    } \n} \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/LogSkipList.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.util.List;\nimport java.util.LinkedList;\nimport java.util.NoSuchElementException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\nGeneric skip list for holding a rough index of a log file. When the log file is loaded, this \nindex is built by adding a mark every n entries. Then when a specific time position is requested\nfrom the file, a point at most n-1 entries before the time position can be jumped to.\n\n*/\npublic class LogSkipList {\n    private static final Logger LOG = LoggerFactory.getLogger(LogSkipList.class);\n    \n    private LinkedList<Mark> marks;\n\n    public class Mark {\n\tprivate long time;\n\tprivate long bytes;\n\tprivate long skipped;\n\n\tpublic Mark(long time, long bytes, long skipped) {\n\t    this.time = time;\n\t    this.bytes = bytes;\n\t    this.skipped = skipped;\n\t}\n\n\tpublic long getTime() { return this.time; }\n\tpublic long getBytes() { return this.bytes; }\n\tpublic long getEntriesSkipped() { return this.skipped; }\n\n\tpublic String toString() {\n\t    return \"Mark(time=\" + time + \", bytes=\" + bytes + \", skipped=\" + skipped + \")\";\n\t}\n    };\n\n    public LogSkipList() {\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"New skip list\");\n\t}\n\tmarks = new LinkedList<Mark>();\n    }\n\n    public void addMark(long time, long bytes, long skipped) {\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"addMark (time:\" + time + \", bytes: \" + bytes + \", skipped: \" + skipped + \")\");\n\t}\n\tmarks.add(new Mark(time, bytes, skipped));\n    }\n\n    /** \n\tFind the last mark in the skip list before time.\n     */\n    public Mark findMarkBefore(long time) throws NoSuchElementException {\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"findMarkBefore(\" + time + \")\");\n\t}\n\t\t    \n\tMark last = marks.getFirst();\n\tfor (Mark m: marks) {\n\t    if (m.getTime() > time) {\n\t\tbreak;\n\t    } \n\t    last = m;\n\t}\n\t\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"return \" + last );\n\t}\n\t\n\treturn last;\n    }\n\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/LogSource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\nimport java.util.Iterator;\n\npublic interface LogSource extends Iterable<LogEntry> {\n    public LogIterator iterator(long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException;\n\n    public LogIterator iterator(long starttime, long endtime) throws IllegalArgumentException;\n\n    public LogIterator iterator() throws IllegalArgumentException;\n\n    public boolean overlapsRange(long starttime, long endtime);\n\n    public long size();\n    public long getStartTime();\n    public long getEndTime();\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/MeasureThroughput.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.IOException;\nimport java.io.BufferedOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.PrintStream;\n\nimport java.util.HashSet;\n\npublic class MeasureThroughput {\n    private static final int MS_PER_SEC = 1000;\n    private static final int MS_PER_MIN = MS_PER_SEC*60;\n    private static final int MS_PER_HOUR = MS_PER_MIN*60;\n    \n    public static void main(String[] args) throws IOException {\t\n\tMergedLogSource source = new MergedLogSource(args);\n\n\tPrintStream ps_ms = new PrintStream(new BufferedOutputStream(new FileOutputStream(\"throughput-ms.out\")));\n\tPrintStream ps_sec = new PrintStream(new BufferedOutputStream(new FileOutputStream(\"throughput-sec.out\")));\n\tPrintStream ps_min = new PrintStream(new BufferedOutputStream(new FileOutputStream(\"throughput-min.out\")));\n\tPrintStream ps_hour = new PrintStream(new BufferedOutputStream(new FileOutputStream(\"throughput-hour.out\")));\n\tLogIterator iter;\n\t\n\tSystem.out.println(source);\n\titer = source.iterator();\n\tlong currentms = 0;\n\tlong currentsec = 0;\n\tlong currentmin = 0;\n\tlong currenthour = 0;\n\tHashSet<Long> zxids_ms = new HashSet<Long>();\n\tlong zxid_sec = 0;\n\tlong zxid_min = 0;\n\tlong zxid_hour = 0;\n\n\twhile (iter.hasNext()) {\n\t    LogEntry e = iter.next();\n\t    TransactionEntry cxn = (TransactionEntry)e;\n\t    \n\t    long ms = cxn.getTimestamp();\n\t    long sec = ms/MS_PER_SEC;\n\t    long min = ms/MS_PER_MIN;\n\t    long hour = ms/MS_PER_HOUR;\n\n\t    if (currentms != ms && currentms != 0) {\n\t\tps_ms.println(\"\" + currentms + \" \" + zxids_ms.size());\n\n\t\tzxid_sec += zxids_ms.size();\n\t\tzxid_min += zxids_ms.size();\n\t\tzxid_hour += zxids_ms.size();\n\t\tzxids_ms.clear();\n\t    }\n\n\t    if (currentsec != sec && currentsec != 0) {\n\t\tps_sec.println(\"\" + currentsec*MS_PER_SEC + \" \" + zxid_sec);\n\n\t\tzxid_sec = 0;\n\t    }\n\n\t    if (currentmin != min && currentmin != 0) {\n\t\tps_min.println(\"\" + currentmin*MS_PER_MIN + \" \" + zxid_min);\n\t\t\n\t\tzxid_min = 0;\n\t    }\n\n\t    if (currenthour != hour && currenthour != 0) {\n\t\tps_hour.println(\"\" + currenthour*MS_PER_HOUR + \" \" + zxid_hour);\n\t\t\n\t\tzxid_hour = 0;\n\t    }\n\n\t    currentms = ms;\n\t    currentsec = sec;\n\t    currentmin = min;\n\t    currenthour = hour;\n\n\t    zxids_ms.add(cxn.getZxid());\n\t}\n\n\titer.close();\n\tps_ms.close();\n\tps_sec.close();\n\tps_min.close();\n\tps_hour.close();\n    }\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/MergedLogSource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.util.Date;\nimport java.util.zip.Adler32;\nimport java.util.zip.Checksum;\nimport java.util.HashMap;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.server.TraceFormatter;\nimport org.apache.zookeeper.server.persistence.FileHeader;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\n\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\nimport java.io.Closeable;\nimport java.io.FileNotFoundException;\nimport java.util.Vector;\nimport java.util.Iterator;\nimport java.util.Collections;\nimport java.util.NoSuchElementException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MergedLogSource implements LogSource {\n    private static final Logger LOG = LoggerFactory.getLogger(MergedLogSource.class);\n    private Vector<LogSource> sources = null;\n    private long starttime = 0;\n    private long endtime = 0;\n    private long size = 0;\n\n    public boolean overlapsRange(long starttime, long endtime) {\n\treturn (starttime <= this.endtime && endtime >= this.starttime);\n    }\n    \n    public long size() { return size; }\n    public long getStartTime() { return starttime; }\n    public long getEndTime() { return endtime; }\n\n    private class MergedLogSourceIterator implements LogIterator {\n\tprivate LogEntry next = null;\n\tprivate long start = 0;\n\tprivate long end = 0;\n\tprivate MergedLogSource src = null;\n\tprivate LogIterator[] sources = null;\n\tprivate LogEntry[] nexts = null;\n\tprivate FilterOp filter = null;\n\t\n\tpublic MergedLogSourceIterator(MergedLogSource src, long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException {\n\t    Vector<LogIterator> iters = new Vector<LogIterator>();\n\t    for (LogSource s : src.sources) {\n\t\tif (s.overlapsRange(starttime, endtime)) {\n\t\t    iters.add(s.iterator(starttime, endtime, filter));\n\t\t}\n\t    }\n\t    \n\t    sources = new LogIterator[iters.size()];\n\t    sources = iters.toArray(sources);\n\t    nexts = new LogEntry[iters.size()];\n\t    for (int i = 0; i < sources.length; i++) {\n\t\tif (sources[i].hasNext()) \n\t\t    nexts[i] = sources[i].next();\n\t    }\n\t    this.filter = filter;\n\t}\n\t\t    \n\tpublic MergedLogSourceIterator(MergedLogSource src, long starttime, long endtime) throws IllegalArgumentException, FilterException {\n\t    this(src, starttime, endtime, null);\n\t}\n\t\n\tpublic long size() throws IOException {\n\t    long size = 0;\n\t    for (LogIterator i : sources) {\n\t\tsize += i.size();\n\t    }\n\t    return size;\n\t}\n\n\tpublic boolean hasNext() {\n\t    for (LogEntry n : nexts) {\n\t\tif (n != null) return true;\n\t    }\n\t    return false;\n\t}\n\t\n\tpublic LogEntry next() {\n\t    int min = -1;\n\t    for (int i = 0; i < nexts.length; i++) {\n\t\tif (nexts[i] != null) {\n\t\t    if (min == -1) {\n\t\t\tmin = i;\n\t\t    } else if (nexts[i].getTimestamp() < nexts[min].getTimestamp()) {\n\t\t\tmin = i;\n\t\t    }\n\t\t}\n\t    }\n\t    if (min == -1) {\n\t\treturn null;\n\t    } else {\n\t\tLogEntry e =  nexts[min];\n\t\tnexts[min] = sources[min].next();\n\t\treturn e;\n\t    }\n\t}\n\n\tpublic void remove() throws UnsupportedOperationException {\n\t    throw new UnsupportedOperationException(\"remove not supported for Merged logs\");\n\t}\n\t\n\tpublic void close() throws IOException {\n\t    for (LogIterator i : sources) {\n\t\ti.close();\n\t    }\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime) throws IllegalArgumentException {\n\ttry {\n\t    return iterator(starttime, endtime, null);\n\t} catch (FilterException fe) {\n\t    assert(false); // shouldn't happen without filter\n\t    return null;\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException {\n\t// sanitise start and end times\n\tif (endtime < starttime) {\n\t    throw new IllegalArgumentException(\"End time (\" +  endtime + \") must be greater or equal to starttime (\" + starttime + \")\");\n\t}\n\n\treturn new MergedLogSourceIterator(this, starttime, endtime, filter);\n    }\n\n    public LogIterator iterator() throws IllegalArgumentException {\n\treturn iterator(starttime, endtime+1);\n    }\n    \n    public MergedLogSource(String[] files) throws IOException {\n\tsources = new Vector<LogSource>();\n\tfor (String f : files) {\n\t    addSource(f);\n\t}\n    }\n    \n    public void addSource(String f) throws IOException {\n\tLogSource s = null;\n\tif (TxnLogSource.isTransactionFile(f)) {\n\t    s = new TxnLogSource(f);\n\t} else {\n\t    s = new Log4JSource(f);\n\t}\n\n\tsize += s.size();\n\tendtime = s.getEndTime() > endtime ? s.getEndTime() : endtime;\n\tstarttime = s.getStartTime() < starttime || starttime == 0 ? s.getStartTime() : starttime;\n\tsources.add(s);\n    }\n\n    public String toString() {\n\tString s = \"MergedLogSource(size=\" + size + \", start=\" + starttime + \", end=\" + endtime +\")\";\n\tfor (LogSource src : sources) {\n\t    s += \"\\n\\t- \" +src;\n\t}\n\treturn s;\n    }\n\n    public static void main(String[] args) throws IOException {\n\tSystem.out.println(\"Time: \" + System.currentTimeMillis());\n\tMergedLogSource s = new MergedLogSource(args);\n\tSystem.out.println(s);\n\n\tLogIterator iter;\n\n\titer = s.iterator();\n\tSystem.out.println(\"Time: \" + System.currentTimeMillis());\n\tSystem.out.println(\"Iterator Size: \" + iter.size());\n\tSystem.out.println(\"Time: \" + System.currentTimeMillis());\n\t/*\twhile (iter.hasNext()) {\n\t    System.out.println(iter.next());\n\t    }*/\n\titer.close();\n\tSystem.out.println(\"Time: \" + System.currentTimeMillis());\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/RandomAccessFileReader.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.File;\nimport java.io.Reader;\nimport java.io.IOException;\nimport java.io.EOFException;\nimport java.io.RandomAccessFile;\nimport java.io.FileNotFoundException;\n\nimport java.io.DataInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.DataInput;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RandomAccessFileReader extends Reader implements DataInput {\n    private static final Logger LOG = LoggerFactory.getLogger(RandomAccessFileReader.class);\n    private RandomAccessFile file;\n    private byte[] buffer;\n    private int buffersize;\n    private int bufferoffset;\n    private long fileoffset;\n    private long fp;\n\n    private static final int DEFAULT_BUFFER_SIZE = 512*1024; // 512k\n    private int point = 0;\n\n    public RandomAccessFileReader(File f) throws FileNotFoundException {\n\tfile = new RandomAccessFile(f, \"r\");\n\tif (LOG.isDebugEnabled()) {\n\t    try {\n\t\tLOG.debug(\"Opened file(\" + f + \") with FD (\" + file.getFD() + \")\");\n\t    } catch (IOException ioe) { \n\t\tLOG.debug(\"Opened file(\" + f + \") coulds get FD\");\n\t    }\n\t}\n\n\tbuffer = new byte[DEFAULT_BUFFER_SIZE];\n\tbuffersize = 0;\n\tbufferoffset = 0;\n\tfileoffset = 0;\n\tfp = 0;\n    }\n\n    /**\n       fill the buffer from the file.\n       fp keeps track of the file pointer.\n       fileoffset is the offset into the file to where the buffer came from.\n    */\n    private int fill() throws IOException {\n\tfileoffset = fp;\n\tint read = file.read(buffer, 0, buffer.length);\n\n\tif (LOG.isDebugEnabled()) {\n\t    String buf = new String(buffer, 0, 40, \"UTF-8\");\n\t    LOG.debug(\"fill(buffer=\" + buf + \")\");\n\t}\n\n\tif (read == -1) { // eof reached\n\t    buffersize = 0;\n\t} else {\n\t    buffersize = read;\n\t}\n\tfp += buffersize;\n\tbufferoffset = 0;\n\n\treturn buffersize;\n    }\n\n    /**\n     * Reader interface \n     */\n    public boolean markSupported() { return false; }\n\n    /**\n       copy what we can from buffer. if it's not enough, fill buffer again and copy again\n    */\n    synchronized public int read(char[] cbuf, int off, int len) throws IOException {\n\t// This could be faster, but probably wont be used\n\tbyte[] b = new byte[2];\n\tint bytesread = 0;\n\twhile (len > 0) {\n\t    int read = read(b, 0, 2);\n\t    bytesread += read;\n\t    if (read < 2) {\n\t\treturn bytesread;\n\t    }\n\t    cbuf[off] = (char)((b[0] << 8) | (b[1] & 0xff));\n\t    off += read;\n\t    len -= read;\n\t}\n\n\treturn bytesread;\n    }\n\n    synchronized public int read(byte[] buf, int off, int len) throws IOException {\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"read(buf, off=\" + off + \", len=\" + len);\n\t}\n\n\tint read = 0;\n\twhile (len > 0) {\n\t    if (buffersize == 0) {\n\t\tfill();\n\t\tif (buffersize == 0) {\n\t\t    break;\n\t\t}\n\t    }\n\n\t    int tocopy = Math.min(len, buffersize);\n\t    if (LOG.isTraceEnabled()) {\n\t\tLOG.trace(\"tocopy=\" + tocopy);\n\t    }\n\n\t    System.arraycopy(buffer, bufferoffset, buf, off, tocopy);\n\t    buffersize -= tocopy;\n\t    bufferoffset += tocopy;\n\n\t    len -= tocopy;\n\t    read += tocopy;\n\t    off += tocopy;\n\t}\n\tif (LOG.isTraceEnabled()) {\n\t    LOG.trace(\"read=\" + read);\n\t}\n\n\treturn read;\n    }\n\n    public void close() throws IOException {\n\tfile.close();\n    }\n\n    /**\n     * Seek interface \n     */\n    public long getPosition() {\n\treturn bufferoffset + fileoffset;\n    }\n    \n    synchronized public void seek(long pos) throws IOException {\n\tif (LOG.isDebugEnabled()) {\n\t    LOG.debug(\"seek(\" + pos + \")\");\n\t}\n\tfile.seek(pos);\n\tfp = pos;\n\tbuffersize = 0; // force a buffer fill on next read\n    }\n\n    /**\n       works like the usual readLine but disregards \\r to make things easier\n    */\n    synchronized public String readLine() throws IOException {\n\tStringBuffer s = null;\n\t\n\t// go through buffer until i find a \\n, if i reach end of buffer first, put whats in buffer into string buffer,\n\t// repeat\n\tbuffering:\n\tfor (;;) {\n\t    if (buffersize == 0) {\n\t\tfill();\n\t\tif (buffersize == 0) {\n\t\t    break;\n\t\t}\n\t    }\n\n\t    for (int i = 0; i < buffersize; i++) {\n\t\tif (buffer[bufferoffset + i] == '\\n') { \n\t\t    if (i > 0) { // if \\n is first char in buffer, leave the string buffer empty\n\t\t\tif (s == null) { s = new StringBuffer(); }\n\t\t\ts.append(new String(buffer, bufferoffset, i, \"UTF-8\"));\n\t\t    }\n\t\t    bufferoffset += i+1;\n\t\t    buffersize -= i+1; \n\t\t    break buffering;\n\t\t}\n\t    }\n\n\t    // We didn't find \\n, read the whole buffer into string buffer\n\t    if (s == null) { s = new StringBuffer(); }\n\t    s.append(new String(buffer, bufferoffset, buffersize, \"UTF-8\"));\n\t    buffersize = 0; \n\t}\n\n\tif (s == null) {\n\t    return null;\n\t} else {\n\t    return s.toString();\n\t}\t    \n    }\n\n    /**\n       DataInput interface\n    */\n    public void readFully(byte[] b) throws IOException {\n\treadFully(b, 0, b.length);\n    }\n\n    public void readFully(byte[] b, int off, int len) throws IOException\n    {\n\twhile (len > 0) {\n\t    int read = read(b, off, len);\n\t    len -= read;\n\t    off += read;\n\n\t    if (read == 0) {\n\t\tthrow new EOFException(\"End of file reached\");\n\t    }\t    \n\t}\n    }\n\n    public int skipBytes(int n) throws IOException {\n\tseek(getPosition() + n);\n\treturn n;\n    }\n\n    public boolean readBoolean() throws IOException {\n\treturn (readByte() != 0);\t    \n    }\n\n    public byte readByte() throws IOException {\n\tbyte[] b = new byte[1];\n\treadFully(b, 0, 1);\n\treturn b[0];\n    }\n\n    public int readUnsignedByte() throws IOException {\n\treturn (int)readByte();\n    }\n\n    public short readShort() throws IOException {\n\tbyte[] b = new byte[2];\n\treadFully(b, 0, 2);\n\treturn (short)((b[0] << 8) | (b[1] & 0xff));\n    }\n    \n    public int readUnsignedShort() throws IOException {\n\tbyte[] b = new byte[2];\n\treadFully(b, 0, 2);\n\treturn (((b[0] & 0xff) << 8) | (b[1] & 0xff));\n    }\n\n    public char readChar() throws IOException {\n\treturn (char)readShort();\n    }\n\n    public int readInt() throws IOException {\n\tbyte[] b = new byte[4];\n\treadFully(b, 0, 4);\n\treturn (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) |  ((b[2] & 0xff) << 8) | (b[3] & 0xff));\n    }\n\n    public long readLong() throws IOException {\n\tbyte[] b = new byte[8];\n\treadFully(b, 0, 8);\n\t\n\treturn (((long)(b[0] & 0xff) << 56) |  ((long)(b[1] & 0xff) << 48) |\n\t\t((long)(b[2] & 0xff) << 40) |  ((long)(b[3] & 0xff) << 32) |\n\t\t((long)(b[4] & 0xff) << 24) |  ((long)(b[5] & 0xff) << 16) |\n\t\t((long)(b[6] & 0xff) <<  8) |  ((long)(b[7] & 0xff)));\n    }\n\n    public float readFloat() throws IOException {\n\treturn Float.intBitsToFloat(readInt());\n    }\n\n    public double readDouble() throws IOException {\n\treturn Double.longBitsToDouble(readLong());\n    }\n\n    public String readUTF() throws IOException {\n\tint len = readUnsignedShort();\n\tbyte[] bytes = new byte[len+2];\n\tbytes[0] = (byte)((len >> 8) & 0xFF);\n\tbytes[1] = (byte)(len & 0xFF);\n\treadFully(bytes, 2, len);\n\tDataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));\n\treturn dis.readUTF();\n    }\n\n    public static void main(String[] args) throws IOException {\n\tRandomAccessFileReader f = new RandomAccessFileReader(new File(args[0]));\n\t\n\tlong pos0 = f.getPosition();\n\tfor (int i = 0; i < 5; i++) {\n\t    System.out.println(f.readLine());\n\t}\n\tSystem.out.println(\"=============\");\n\tlong pos1 = f.getPosition();\n\tSystem.out.println(\"pos: \" + pos1);\n\tfor (int i = 0; i < 5; i++) {\n\t    System.out.println(f.readLine());\n\t}\n\tSystem.out.println(\"=============\");\n\tf.seek(pos1);\n\tfor (int i = 0; i < 5; i++) {\n\t    System.out.println(f.readLine());\n\t}\n\tSystem.out.println(\"=============\");\n\tf.seek(pos0);\n\tfor (int i = 0; i < 5; i++) {\n\t    System.out.println(f.readLine());\n\t}\n\tlong pos2 = f.getPosition();\n\tSystem.out.println(\"=============\");\n\tSystem.out.println(f.readLine());\n\tf.seek(pos2);\n\tSystem.out.println(f.readLine());\n\tf.close();\n    }\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/TransactionEntry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\npublic class TransactionEntry extends LogEntry {\n    public TransactionEntry(long timestamp, long clientId, long Cxid, long Zxid, String op) {\n\tthis(timestamp, clientId, Cxid, Zxid, op, \"\");\n    }\n\n    public TransactionEntry(long timestamp, long clientId, long Cxid, long Zxid, String op, String extra) {\n\tsuper(timestamp);\n\tsetAttribute(\"client-id\", new Long(clientId));\n\tsetAttribute(\"cxid\", new Long(Cxid));\n\tsetAttribute(\"zxid\", new Long(Zxid));\n\tsetAttribute(\"operation\", op);\n\tsetAttribute(\"extra\", extra);\n    }\n\n    public long getClientId() {\n\treturn (Long)getAttribute(\"client-id\");\n    }\n\n    public long getCxid() {\n\treturn (Long)getAttribute(\"cxid\");\n    }\n\n    public long getZxid() {\n\treturn (Long)getAttribute(\"zxid\");\n    }\n\n    public String getOp() {\n\treturn (String)getAttribute(\"operation\");\n    }\n\n    public String getExtra() {\n\treturn (String)getAttribute(\"extra\");\n    }\n\n    public String toString() {\n\treturn getTimestamp() + \":::session(0x\" + Long.toHexString(getClientId()) + \") cxid(0x\" + Long.toHexString(getCxid()) + \") zxid(0x\" + Long.toHexString(getZxid()) + \") op(\" + getOp() + \") extra(\" + getExtra() +\")\";\n    }\n\n    public Type getType() { return LogEntry.Type.TXN; }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/TxnLogSource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.util.Date;\nimport java.util.zip.Adler32;\nimport java.util.zip.Checksum;\nimport java.util.HashMap;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.server.TraceFormatter;\nimport org.apache.zookeeper.server.persistence.FileHeader;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\n\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\nimport java.io.File;\nimport java.io.Closeable;\nimport java.io.FileNotFoundException;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TxnLogSource implements LogSource {\n    private static final Logger LOG = LoggerFactory.getLogger(TxnLogSource.class);\n\n    private LogSkipList skiplist = null;\n    private static final int skipN = 10000;\n\n    private String file = null;\n    private long starttime = 0;\n    private long endtime = 0;\n    private long size = 0;\n\n    public boolean overlapsRange(long starttime, long endtime) {\n\treturn (starttime <= this.endtime && endtime >= this.starttime);\n    }\n\n    public long size() { return size; }\n    public long getStartTime() { return starttime; }\n    public long getEndTime() { return endtime; }\n    public LogSkipList getSkipList() { return skiplist; }\n\n    public static boolean isTransactionFile(String file) throws IOException {\n        RandomAccessFileReader reader = new RandomAccessFileReader(new File(file));\n        BinaryInputArchive logStream = new BinaryInputArchive(reader);\n        FileHeader fhdr = new FileHeader();\n        fhdr.deserialize(logStream, \"fileheader\");\n\treader.close();\n\n        return fhdr.getMagic() == FileTxnLog.TXNLOG_MAGIC;\n    }\n\n    private class TxnLogSourceIterator implements LogIterator {\n\tprivate LogEntry next = null;\n\tprivate long starttime = 0;\n\tprivate long endtime = 0;\n\tprivate TxnLogSource src = null;\n\tprivate RandomAccessFileReader reader = null;\n\tprivate BinaryInputArchive logStream = null;\n\tprivate long skippedAtStart = 0;\n\tprivate FilterOp filter = null;\n\n\tpublic TxnLogSourceIterator(TxnLogSource src, long starttime, long endtime) throws IllegalArgumentException, FilterException {\n\t    this(src,starttime,endtime,null);\n\t}\n\t\n\tpublic TxnLogSourceIterator(TxnLogSource src, long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException {\n\t    try {\n\t\tthis.src = src;\n\t\tthis.starttime = starttime;\n\t\tthis.endtime = endtime;\n\t\treader = new RandomAccessFileReader(new File(src.file));\n\t\tlogStream = new BinaryInputArchive(reader);\n\t\tFileHeader fhdr = new FileHeader();\n\t\tfhdr.deserialize(logStream, \"fileheader\");\n\t    } catch (Exception e) {\n\t\tthrow new IllegalArgumentException(\"Cannot open transaction log (\"+src.file+\") :\" + e);\n\t    }\n\t    \n\t    LogSkipList.Mark start = src.getSkipList().findMarkBefore(starttime);\n\t    try {\n\t\treader.seek(start.getBytes());\n\t\tskippedAtStart = start.getEntriesSkipped();\n\t    } catch (IOException ioe) {\n\t\t// if we can't skip, we should just read from the start\n\t    }\n\n\t    this.filter = filter;\n\n\t    LogEntry e;\n\t    while ((e = readNextEntry()) != null && e.getTimestamp() < endtime) {\n\t\tif (e.getTimestamp() >= starttime && (filter == null || filter.matches(e))  ) {\n\t\t    next = e;\n\t\t    return;\n\t\t}\n\t\tskippedAtStart++;\n\t    }\n\n\n\t}\n\t\n\tpublic long size() throws IOException {\n\t    if (this.endtime >= src.getEndTime()) {\n\t\treturn src.size() - skippedAtStart;\n\t    }\n\t    \n\t    long pos = reader.getPosition();\n\t    LogEntry e;\n\n\t    LogSkipList.Mark lastseg = src.getSkipList().findMarkBefore(this.endtime);\n\t    reader.seek(lastseg.getBytes());\n\t    // number of entries skipped to get to the end of the iterator, less the number skipped to get to the start\n\t    long count = lastseg.getEntriesSkipped() - skippedAtStart; \n\n\t    while ((e = readNextEntry()) != null) {\n\t\tif (e.getTimestamp() > this.endtime) {\n\t\t    break;\n\t\t}\n\t\tcount++;\n\t    }\n\t    reader.seek(pos);;\n\n\t    return count;\n\t}\n\t\n\tprivate LogEntry readNextEntry() {\n\t    LogEntry e = null;\n\t    try {\n\t\tlong crcValue;\n\t\tbyte[] bytes;\n\t\ttry {\n\t\t    crcValue = logStream.readLong(\"crcvalue\");\n\t\t    \n\t\t    bytes = logStream.readBuffer(\"txnEntry\");\n\t\t} catch (EOFException ex) {\n\t\t    return null;\n\t\t}\n\t\t\n\t\tif (bytes.length == 0) {\n\t\t    return null;\n\t\t}\n\t\tChecksum crc = new Adler32();\n\t\tcrc.update(bytes, 0, bytes.length);\n\t\tif (crcValue != crc.getValue()) {\n\t\t    throw new IOException(\"CRC doesn't match \" + crcValue +\n\t\t\t\t\t  \" vs \" + crc.getValue());\n\t\t}\n\t\tTxnHeader hdr = new TxnHeader();\n\t\tRecord r = SerializeUtils.deserializeTxn(bytes, hdr);\n\n\t\tswitch (hdr.getType()) {\n\t\tcase OpCode.createSession: {\n\t\t    e = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"createSession\");\n\t\t}\n\t\t    break;\n\t\tcase OpCode.closeSession: {\n\t\t    e = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"closeSession\");\n\t\t}\n\t\t    break;\n\t\tcase OpCode.create:\n\t\t    if (r != null) {\n\t\t\tCreateTxn create = (CreateTxn)r;\n\t\t\tString path = create.getPath();\n\t\t\te = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"create\", path);\n\t\t    }\n\t\t    break;\n\t\tcase OpCode.setData:\n\t\t    if (r != null) {\n\t\t\tSetDataTxn set = (SetDataTxn)r;\n\t\t\tString path = set.getPath();\n\t\t\te = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"setData\", path);\n\t\t    }\n\t\t    break;\n\t\tcase OpCode.setACL:\n\t\t    if (r != null) {\n\t\t\tSetACLTxn setacl = (SetACLTxn)r;\n\t\t\tString path = setacl.getPath();\n\t\t    e = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"setACL\", path);\n\t\t    }\n\t\t    break;\n\t\tcase OpCode.error:\n\t\t    if (r != null)  {\n\t\t\tErrorTxn error = (ErrorTxn)r;\n\t\t\t\n\t\t\te = new TransactionEntry(hdr.getTime(), hdr.getClientId(), hdr.getCxid(), hdr.getZxid(), \"error\", \"Error: \" + error.getErr());\n\t\t    }\n\t\t    break;\n\t\tdefault:\n\t\t    LOG.info(\"Unknown op: \" + hdr.getType());\n\t\t    break;\n\t\t}\n\t\t\n\t\tif (logStream.readByte(\"EOR\") != 'B') {\n\t\t    throw new EOFException(\"Last transaction was partial.\");\n\t\t}\n\t    } catch (Exception ex) {\n\t\tLOG.error(\"Error reading transaction from (\" + src.file + \") :\" + e);\n\t\treturn null;\n\t    }\n\t    return e;\n\t}\n\n\tpublic boolean hasNext() {\n\t    return next != null;\n\t}\n\t\n\tpublic LogEntry next() throws NoSuchElementException {\n\t    LogEntry ret = next;\n\t    LogEntry e = readNextEntry();\n\n\t    if (filter != null) {\n\t\ttry {\n\t\t    while (e != null && !filter.matches(e)) {\n\t\t\te = readNextEntry();\n\t\t    }\n\t\t} catch (FilterException fe) {\n\t\t    throw new NoSuchElementException(fe.toString());\n\t\t}\n\t    }\n\t    if (e != null && e.getTimestamp() < endtime) {\n\t\tnext = e;\n\t    } else {\n\t\tnext = null;\n\t    }\n\t    return ret;\n\t}\n\n\tpublic void remove() throws UnsupportedOperationException {\n\t    throw new UnsupportedOperationException(\"remove not supported for Txn logs\");\n\t}\n\t\n\tpublic void close() throws IOException {\n\t    reader.close();\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime) throws IllegalArgumentException {\n\ttry {\n\t    return iterator(starttime, endtime, null);\n\t} catch (FilterException fe) {\n\t    assert(false); // should never ever happen\n\t    return null;\n\t}\n    }\n\n    public LogIterator iterator(long starttime, long endtime, FilterOp filter) throws IllegalArgumentException, FilterException {\n\t// sanitise start and end times\n\tif (endtime < starttime) {\n\t    throw new IllegalArgumentException(\"End time (\" +  endtime + \") must be greater or equal to starttime (\" + starttime + \")\");\n\t}\n\n\treturn new TxnLogSourceIterator(this, starttime, endtime, filter);\n    }\n\n    public LogIterator iterator() throws IllegalArgumentException {\n\treturn iterator(starttime, endtime+1);\n    }\n    \n    public TxnLogSource(String file) throws IOException {\n\tthis.file = file;\n\n\tskiplist = new LogSkipList();\n\n\tRandomAccessFileReader reader = new RandomAccessFileReader(new File(file));\n\ttry {\n\t    BinaryInputArchive logStream = new BinaryInputArchive(reader);\n\t    FileHeader fhdr = new FileHeader();\n\t    fhdr.deserialize(logStream, \"fileheader\");\n\t    \n\t    byte[] bytes = null;\n\t    while (true) {\n\t\tlong lastFp = reader.getPosition();\n\n\t\tlong crcValue;\n\n\t\ttry {\n\t\t    crcValue = logStream.readLong(\"crcvalue\");\n\t\t    bytes = logStream.readBuffer(\"txnEntry\");\n\t\t} catch (EOFException e) {\n\t\t    break;\n\t\t}\n\t\t\n\t\tif (bytes.length == 0) {\n\t\t    break;\n\t\t}\n\t\tChecksum crc = new Adler32();\n\t\tcrc.update(bytes, 0, bytes.length);\n\t\tif (crcValue != crc.getValue()) {\n\t\t    throw new IOException(\"CRC doesn't match \" + crcValue +\n\t\t\t\t\t  \" vs \" + crc.getValue());\n\t\t}\n\t\tif (logStream.readByte(\"EOR\") != 'B') {\n\t\t    throw new EOFException(\"Last transaction was partial.\");\n\t\t}\n\t\tTxnHeader hdr = new TxnHeader();\n\t\tRecord r = SerializeUtils.deserializeTxn(bytes, hdr);\n\t\t\n\t\tif (starttime == 0) {\n\t\t    starttime = hdr.getTime();\n\t\t}\n\t\tendtime = hdr.getTime();\n\n\t\tif (size % skipN == 0) {\n\t\t    skiplist.addMark(hdr.getTime(), lastFp, size);\n\t\t}\n\t\tsize++;\n\t    }\n\t    if (bytes == null) {\n\t\tthrow new IOException(\"Nothing read from (\"+file+\")\");\n\t    }\n\t} finally {\n\t    reader.close();\n\t}\n    }\n\n    public String toString() {\n\treturn \"TxnLogSource(file=\" + file + \", size=\" + size + \", start=\" + starttime + \", end=\" + endtime +\")\";\n    }\n\n    public static void main(String[] args) throws IOException, FilterException {\n\tTxnLogSource s = new TxnLogSource(args[0]);\n\tSystem.out.println(s);\n\n\tLogIterator iter;\n\n\tif (args.length == 3) {\n\t    long starttime = Long.valueOf(args[1]);\n\t    long endtime = Long.valueOf(args[2]);\n\t    FilterOp fo = new FilterParser(\"(or (and (> zxid 0x2f0bd6f5e0) (< zxid 0x2f0bd6f5e9)) (= operation \\\"error\\\"))\").parse();\n\t    System.out.println(\"fo: \" + fo);\n\t    iter = s.iterator(starttime, endtime, fo);\n\t} else {\n\t    iter = s.iterator();\n\t}\n\tSystem.out.println(iter);\n\twhile (iter.hasNext()) {\n\t    \t    System.out.println(iter.next());\n\t}\n\titer.close();\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/AndOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class AndOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tfor (FilterOp f : subOps) {\n\t    if (!f.matches(entry)) {\n\t\treturn false;\n\t    }\n\t}\n\treturn true;\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/Arg.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.FilterOp.*;\n\npublic class Arg<T> {\n    private ArgType type;\n    protected T value;\n    \n    protected Arg(ArgType type) {\n\tthis.type = type;\n    }\n    \n    public ArgType getType() { return type; }\n    public T getValue() { return value; }\n\n    public String toString() {\n\treturn \"[\" + type + \":\" + value + \"]\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/EqualsOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class EqualsOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\n\tObject last = null;\n\tfor (Arg a : args) {\n\t    Object v = a.getValue();\n\t    if (a.getType() == FilterOp.ArgType.SYMBOL) {\n\t\tString key = (String)a.getValue();\n\t\tv = entry.getAttribute(key);\n\t    }\n\n\t    if (last != null\n\t\t&& !last.equals(v)) {\n\t\treturn false;\n\t    }\n\t    last = v;\n\t}\n\n\treturn true;\n    }\n}    \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/GreaterThanOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class GreaterThanOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tArg first = args.get(0);\n\t\n\tif (first != null) {\n\t    FilterOp.ArgType type = first.getType();\n\t    if (type == FilterOp.ArgType.SYMBOL) {\n\t\tString key = (String)first.getValue();\n\t\tObject v = entry.getAttribute(key);\n\t\tif (v instanceof String) {\n\t\t    type = FilterOp.ArgType.STRING;\n\t\t} else if (v instanceof Double || v instanceof Long || v instanceof Integer || v instanceof Short) {\n\t\t    type = FilterOp.ArgType.NUMBER;\n\t\t} else {\n\t\t    throw new FilterException(\"LessThanOp: Invalid argument, first argument resolves to neither a String nor a Number\");\n\t\t}\n\t    }\n\t    \n\t    Object last = null;\n\t    for (Arg a : args) {\n\t\tObject v = a.getValue();\n\t\tif (a.getType() == FilterOp.ArgType.SYMBOL) {\n\t\t    String key = (String)a.getValue();\n\t\t    v = entry.getAttribute(key);\n\t\t}\n\n\t\tif (last != null) {\n\t\t    if (type == FilterOp.ArgType.STRING) {\n\t\t\tif (((String)last).compareTo((String)v) <= 0) {\n\t\t\t    return false;\n\t\t\t}\n\t\t    } else if (type == FilterOp.ArgType.NUMBER) {\n\t\t\t//\t\t\tSystem.out.println(\"last[\" + ((Number)last).longValue() + \"] v[\"+ ((Number)v).longValue() + \"]\");\n\t\t\tif (((Number)last).longValue() <= ((Number)v).longValue()) {\n\t\t\t    return false;\n\t\t\t}\n\t\t    }\n\t\t}\n\t\tlast = v;\n\t    }\n\t    return true;\n\t} else { \n\t    return true; \n\t}\n    }\n\t\n}    \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/LessThanOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class LessThanOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tArg first = args.get(0);\n\t\n\tif (first != null) {\n\t    FilterOp.ArgType type = first.getType();\n\t    if (type == FilterOp.ArgType.SYMBOL) {\n\t\tString key = (String)first.getValue();\n\t\tObject v = entry.getAttribute(key);\n\t\tif (v instanceof String) {\n\t\t    type = FilterOp.ArgType.STRING;\n\t\t} else if (v instanceof Double || v instanceof Long || v instanceof Integer || v instanceof Short) {\n\t\t    type = FilterOp.ArgType.NUMBER;\n\t\t} else {\n\t\t    throw new FilterException(\"LessThanOp: Invalid argument, first argument resolves to neither a String nor a Number\");\n\t\t}\n\t    }\n\t    \n\t    Object last = null;\n\t    for (Arg a : args) {\n\t\tObject v = a.getValue();\n\t\tif (a.getType() == FilterOp.ArgType.SYMBOL) {\n\t\t    String key = (String)a.getValue();\n\t\t    v = entry.getAttribute(key);\n\t\t}\n\n\t\tif (last != null) {\n\t\t    if (type == FilterOp.ArgType.STRING) {\n\t\t\tif (((String)last).compareTo((String)v) >= 0) {\n\t\t\t    return false;\n\t\t\t}\n\t\t    } else if (type == FilterOp.ArgType.NUMBER) {\n\t\t\tif (((Number)last).doubleValue() >= ((Number)v).doubleValue()) {\n\t\t\t    return false;\n\t\t\t}\n\t\t    }\n\t\t}\n\t\tlast = v;\n\t    }\n\t    return true;\n\t} else { \n\t    return true; \n\t}\n    }\n\t\n}    \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/NotOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class NotOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tif (subOps.size() != 1) {\n\t    throw new FilterException(\"Not operation can only take one argument\");\n\t}\n\treturn !subOps.get(0).matches(entry);\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/NumberArg.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.FilterOp.*;\n\npublic class NumberArg extends Arg<Long> {\n    public NumberArg(Long value) {\n\tsuper(ArgType.NUMBER);\n\tthis.value = value;\n    }\n};\n\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/OrOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class OrOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tfor (FilterOp f : subOps) {\n\t    if (f.matches(entry)) {\n\t\treturn true;\n\t    }\n\t}\n\treturn false;\n    }\n}    \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/StringArg.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.FilterOp.*;\n\npublic class StringArg extends Arg<String> {\n    public StringArg(String value) {\n\tsuper(ArgType.STRING);\n\t    this.value = value;\n    }\n};\n\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/SymbolArg.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.FilterOp.*;\n\npublic class SymbolArg extends Arg<String> {\n    public SymbolArg(String value) {\n\tsuper(ArgType.SYMBOL);\n\tthis.value = value;\n    }\n};\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/filterops/XorOp.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.filterops;\n\nimport org.apache.zookeeper.graph.LogEntry;\nimport org.apache.zookeeper.graph.FilterOp;\nimport org.apache.zookeeper.graph.FilterException;\n\npublic class XorOp extends FilterOp {\n    public boolean matches(LogEntry entry) throws FilterException {\n\tint count = 0;\n\tfor (FilterOp f : subOps) {\n\t    if (f.matches(entry)) {\n\t\tcount++;\n\t\tif (count > 1) {\n\t\t    return false;\n\t\t}\n\t    }\n\t}\n\tif (count == 1) {\n\t    return true;\n\t}\n\treturn false;\n    }\n}    \n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/FileLoader.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.FileNotFoundException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\nimport org.apache.zookeeper.graph.*;\n\npublic class FileLoader extends JsonServlet\n{\n    private MergedLogSource source = null;\n    \n    public FileLoader(MergedLogSource src) throws Exception {\n\tsource = src;\n    }\n\n    String handleRequest(JsonRequest request) throws Exception\n    {\n\tString output = \"\";\n\t\t\n\tString file = request.getString(\"path\", \"/\");\n\tJSONObject o = new JSONObject();\n\ttry {\n\t    this.source.addSource(file);\n\t    o.put(\"status\", \"OK\");\n\t\n\t} catch (Exception e) {\n\t    o.put(\"status\", \"ERR\");\n\t    o.put(\"error\",  e.toString());\n\t}\n\t\n\treturn JSONValue.toJSONString(o);\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/Fs.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.FileNotFoundException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\nimport java.util.Arrays;\nimport java.util.Comparator;\n\npublic class Fs extends JsonServlet\n{\n    String handleRequest(JsonRequest request) throws Exception\n    {\n\tString output = \"\";\n\tJSONArray filelist = new JSONArray();\n\n\tFile base = new File(request.getString(\"path\", \"/\"));\n\tif (!base.exists() || !base.isDirectory()) {\n\t    throw new FileNotFoundException(\"Couldn't find [\" + request + \"]\");\n\t}\n\tFile[] files = base.listFiles();\n\tArrays.sort(files, new Comparator<File>() { \n\t\tpublic int compare(File o1, File o2) {\n\t\t    if (o1.isDirectory() != o2.isDirectory()) {\n\t\t\tif (o1.isDirectory()) {\n\t\t\t    return -1;\n\t\t\t} else {\n\t\t\t    return 1;\n\t\t\t}\n\t\t    }\n\t\t    return o1.getName().compareToIgnoreCase(o2.getName());\n\t\t} \n\t    });\n\t\n\tfor (File f : files) {\n\t    JSONObject o = new JSONObject();\n\t    o.put(\"file\", f.getName());\n\t    o.put(\"type\", f.isDirectory() ? \"D\" : \"F\");\n\t    o.put(\"path\", f.getCanonicalPath());\n\t    filelist.add(o);\n\t}\n\treturn JSONValue.toJSONString(filelist);\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/GraphData.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.FileNotFoundException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.util.regex.Pattern;\nimport java.util.regex.Matcher;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\nimport org.apache.zookeeper.graph.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class GraphData extends JsonServlet\n{\n    private static final Logger LOG = LoggerFactory.getLogger(GraphData.class);\n    private static final int DEFAULT_PERIOD = 1000;\n\n    private LogSource source = null;\n\n    public GraphData(LogSource src) throws Exception {\n\tthis.source = src; \n    }\n\n    String handleRequest(JsonRequest request) throws Exception {\n\t\n\n\tlong starttime = 0;\n\tlong endtime = 0;\n\tlong period = 0;\n\tFilterOp fo = null;\n\n\tstarttime = request.getNumber(\"start\", 0);\n\tendtime = request.getNumber(\"end\", 0);\n\tperiod = request.getNumber(\"period\", 0);\n\tString filterstr = request.getString(\"filter\", \"\");\n\n\tif (filterstr.length() > 0) {\n\t    fo = new FilterParser(filterstr).parse();\n\t}\n\t\n\tif (starttime == 0) { starttime = source.getStartTime(); }\n\tif (endtime == 0) { \n\t    if (period > 0) {\n\t\tendtime = starttime + period;\n\t    } else {\n\t\tendtime = starttime + DEFAULT_PERIOD; \n\t    }\n\t}\n\n\tif (LOG.isDebugEnabled()) {\n\t    LOG.debug(\"handle(start= \" + starttime + \", end=\" + endtime + \", period=\" + period + \")\");\n\t}\n\t\n\tLogIterator iterator = (fo != null) ? \n\t    source.iterator(starttime, endtime, fo) : source.iterator(starttime, endtime);\n\treturn new JsonGenerator(iterator).toString();\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/JsonServlet.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\nimport java.util.Map;\n\nabstract public class JsonServlet extends HttpServlet {\n    abstract String handleRequest(JsonRequest request) throws Exception;\n\n    protected class JsonRequest {\n\tprivate Map map;\n\n\tpublic JsonRequest(ServletRequest request) {\n\t    map = request.getParameterMap();\n\t}\n\t\n\tpublic long getNumber(String name, long defaultnum) {\n\t    String[] vals = (String[])map.get(name);\n\t    if (vals == null || vals.length == 0) {\n\t\treturn defaultnum;\n\t    }\n\n\t    try {\n\t\treturn Long.valueOf(vals[0]);\n\t    } catch (NumberFormatException e) {\n\t\treturn defaultnum;\n\t    }\n\t}\n\t\n\tpublic String getString(String name, String defaultstr) {\n\t    String[] vals = (String[])map.get(name);\n\t    if (vals == null || vals.length == 0) {\n\t\treturn defaultstr;\n\t    } else {\n\t\treturn vals[0];\n\t    }\n\t}\n    }\n\n    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException\n    {\n        response.setContentType(\"text/plain;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n\t\n\ttry {\n\t    String req = request.getRequestURI().substring(request.getServletPath().length());\n\n\t    response.getWriter().println(handleRequest(new JsonRequest(request)));\n\t} catch (Exception e) {\n\t    JSONObject o = new JSONObject();\n\t    o.put(\"error\", e.toString());\n\t    response.getWriter().println(JSONValue.toJSONString(o));\n\t} catch (java.lang.OutOfMemoryError oom) {\n\t    JSONObject o = new JSONObject();\n\t    o.put(\"error\", \"Out of memory. Perhaps you've requested too many logs. Try narrowing you're filter criteria.\");\n\t    response.getWriter().println(JSONValue.toJSONString(o));\n\t}\n    }\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/NumEvents.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.FileNotFoundException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\nimport java.util.regex.Pattern;\nimport java.util.regex.Matcher;\n\nimport org.apache.zookeeper.graph.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\npublic class NumEvents extends JsonServlet\n{\n    private static final Logger LOG = LoggerFactory.getLogger(NumEvents.class);\n    private static final int DEFAULT_PERIOD = 1000;\n\n    private LogSource source = null;\n\n    public NumEvents(LogSource src) throws Exception {\n\tthis.source = src;\n    }\n\n    String handleRequest(JsonRequest request) throws Exception {\n\tString output = \"\";\n\n\tlong starttime = 0;\n\tlong endtime = 0;\n\tlong period = 0;\n\n\tstarttime = request.getNumber(\"start\", 0);\n\tendtime = request.getNumber(\"end\", 0);\n\tperiod = request.getNumber(\"period\", 0);\n\n\tif (starttime == 0) { starttime = source.getStartTime(); }\n\tif (endtime == 0) { \n\t    if (period > 0) {\n\t\tendtime = starttime + period;\n\t    } else {\n\t\tendtime = source.getEndTime(); \n\t    }\n\t}\n\t\n\tLogIterator iter = source.iterator(starttime, endtime);\n\tJSONObject data = new JSONObject();\n\tdata.put(\"startTime\", starttime);\n\tdata.put(\"endTime\", endtime);\n\tlong size = 0;\n\t\n\tsize = iter.size();\n\t\n\tdata.put(\"numEntries\",  size);\n\tif (LOG.isDebugEnabled()) {\n\t    LOG.debug(\"handle(start= \" + starttime + \", end=\" + endtime + \", numEntries=\" + size +\")\");\n\t}\n\titer.close();\n\treturn JSONValue.toJSONString(data);\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/StaticContent.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.BufferedReader;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class StaticContent extends HttpServlet {\n    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException\n    {\n\tString path = request.getRequestURI().substring(request.getServletPath().length());\n\n\tInputStream resource = ClassLoader.getSystemResourceAsStream(\"org/apache/zookeeper/graph/resources\" + path);\t  \n\tif (resource == null) {\n\t    response.getWriter().println(path + \" not found!\");\n\t    response.setStatus(HttpServletResponse.SC_NOT_FOUND);\n\t    return;\n\t}\n\ttry {\n\t  while (resource.available() > 0) {\n\t    response.getWriter().write(resource.read());\n\t  }\n\t} finally {\n\t  resource.close();\n\t}\n\t//        response.setContentType(\"text/plain;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/loggraph/src/java/org/apache/zookeeper/graph/servlets/Throughput.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.graph.servlets;\n\nimport java.io.IOException;\nimport java.io.BufferedOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.PrintStream;\n\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\n\nimport org.apache.zookeeper.graph.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.JSONValue;\n\n\npublic class Throughput extends JsonServlet\n{\n    private static final int MS_PER_SEC = 1000;\n    private static final int MS_PER_MIN = MS_PER_SEC*60;\n    private static final int MS_PER_HOUR = MS_PER_MIN*60;\n\n    private LogSource source = null;\n\n    public Throughput(LogSource src) throws Exception {\n\tthis.source = src; \n    }\n\n    public String handleRequest(JsonRequest request) throws Exception {\n\tlong starttime = 0;\n\tlong endtime = 0;\n\tlong period = 0;\n\tlong scale = 0;\n\t\n\tstarttime = request.getNumber(\"start\", 0);\n\tendtime = request.getNumber(\"end\", 0);\n\tperiod = request.getNumber(\"period\", 0);\n\t\n\n\tif (starttime == 0) { starttime = source.getStartTime(); }\n\tif (endtime == 0) { \n\t    if (period > 0) {\n\t\tendtime = starttime + period;\n\t    } else {\n\t\tendtime = source.getEndTime(); \n\t    }\n\t}\n\t\n\tString scalestr = request.getString(\"scale\", \"minutes\");\n\tif (scalestr.equals(\"seconds\")) {\n\t    scale = MS_PER_SEC;\n\t} else if (scalestr.equals(\"hours\")) {\n\t    scale = MS_PER_HOUR;\n\t} else {\n\t    scale = MS_PER_MIN;\n\t} \t\n\t\n\tLogIterator iter = source.iterator(starttime, endtime);\n\t\n\tlong current = 0;\n\tlong currentms = 0;\n\tHashSet<Long> zxids_ms = new HashSet<Long>();\n\tlong zxidcount = 0;\n\n\tJSONArray events = new JSONArray();\n\twhile (iter.hasNext()) {\n\t    LogEntry e = iter.next();\n\t    if (e.getType() != LogEntry.Type.TXN) {\n\t\tcontinue;\n\t    }\n\n\t    TransactionEntry cxn = (TransactionEntry)e;\n\t    \n\t    long ms = cxn.getTimestamp();\n\t    long inscale = ms/scale;\n\n\t    if (currentms != ms && currentms != 0) {\n\t\tzxidcount += zxids_ms.size();\n\t\tzxids_ms.clear();\n\t    }\n\n\t    if (inscale != current && current != 0) {\n\t\tJSONObject o = new JSONObject();\n\t\to.put(\"time\", current*scale);\n\t\to.put(\"count\", zxidcount);\n\t\tevents.add(o);\n\t\tzxidcount = 0;\n\t    }\n\t    current = inscale;\n\t    currentms = ms;\n\n\t    zxids_ms.add(cxn.getZxid());\n\t}\n\tJSONObject o = new JSONObject();\n\to.put(\"time\", current*scale);\n\to.put(\"count\", zxidcount);\n\tevents.add(o);\n\n\titer.close();\n\t\n\treturn JSONValue.toJSONString(events);\n    }\n\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/log4j.properties",
    "content": "log4j.rootLogger=TRACE, CONSOLE\n\n# Print the date in ISO 8601 format\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.Threshold=TRACE\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n\n\nlog4j.logger.org.apache.zookeeper.graph.LogSkipList=off\nlog4j.logger.org.apache.zookeeper.graph.RandomAccessFileReader=off\n#log4j.logger.org.apache.zookeeper.graph.Log4JSource=off"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/date.format.js",
    "content": "/*\n * Date Format 1.2.3\n * (c) 2007-2009 Steven Levithan <stevenlevithan.com>\n * MIT license\n *\n * Includes enhancements by Scott Trenda <scott.trenda.net>\n * and Kris Kowal <cixar.com/~kris.kowal/>\n *\n * Accepts a date, a mask, or a date and a mask.\n * Returns a formatted version of the given date.\n * The date defaults to the current date/time.\n * The mask defaults to dateFormat.masks.default.\n */\n\nvar dateFormat = function () {\n\tvar\ttoken = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\\1?|[LloSZ]|\"[^\"]*\"|'[^']*'/g,\n\t\ttimezone = /\\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\\d{4})?)\\b/g,\n\t\ttimezoneClip = /[^-+\\dA-Z]/g,\n\t\tpad = function (val, len) {\n\t\t\tval = String(val);\n\t\t\tlen = len || 2;\n\t\t\twhile (val.length < len) val = \"0\" + val;\n\t\t\treturn val;\n\t\t};\n\n\t// Regexes and supporting functions are cached through closure\n\treturn function (date, mask, utc) {\n\t\tvar dF = dateFormat;\n\n\t\t// You can't provide utc if you skip other args (use the \"UTC:\" mask prefix)\n\t\tif (arguments.length == 1 && Object.prototype.toString.call(date) == \"[object String]\" && !/\\d/.test(date)) {\n\t\t\tmask = date;\n\t\t\tdate = undefined;\n\t\t}\n\n\t\t// Passing date through Date applies Date.parse, if necessary\n\t\tdate = date ? new Date(date) : new Date;\n\t\tif (isNaN(date)) throw SyntaxError(\"invalid date\");\n\n\t\tmask = String(dF.masks[mask] || mask || dF.masks[\"default\"]);\n\n\t\t// Allow setting the utc argument via the mask\n\t\tif (mask.slice(0, 4) == \"UTC:\") {\n\t\t\tmask = mask.slice(4);\n\t\t\tutc = true;\n\t\t}\n\n\t\tvar\t_ = utc ? \"getUTC\" : \"get\",\n\t\t\td = date[_ + \"Date\"](),\n\t\t\tD = date[_ + \"Day\"](),\n\t\t\tm = date[_ + \"Month\"](),\n\t\t\ty = date[_ + \"FullYear\"](),\n\t\t\tH = date[_ + \"Hours\"](),\n\t\t\tM = date[_ + \"Minutes\"](),\n\t\t\ts = date[_ + \"Seconds\"](),\n\t\t\tL = date[_ + \"Milliseconds\"](),\n\t\t\to = utc ? 0 : date.getTimezoneOffset(),\n\t\t\tflags = {\n\t\t\t\td:    d,\n\t\t\t\tdd:   pad(d),\n\t\t\t\tddd:  dF.i18n.dayNames[D],\n\t\t\t\tdddd: dF.i18n.dayNames[D + 7],\n\t\t\t\tm:    m + 1,\n\t\t\t\tmm:   pad(m + 1),\n\t\t\t\tmmm:  dF.i18n.monthNames[m],\n\t\t\t\tmmmm: dF.i18n.monthNames[m + 12],\n\t\t\t\tyy:   String(y).slice(2),\n\t\t\t\tyyyy: y,\n\t\t\t\th:    H % 12 || 12,\n\t\t\t\thh:   pad(H % 12 || 12),\n\t\t\t\tH:    H,\n\t\t\t\tHH:   pad(H),\n\t\t\t\tM:    M,\n\t\t\t\tMM:   pad(M),\n\t\t\t\ts:    s,\n\t\t\t\tss:   pad(s),\n\t\t\t\tl:    pad(L, 3),\n\t\t\t\tL:    pad(L > 99 ? Math.round(L / 10) : L),\n\t\t\t\tt:    H < 12 ? \"a\"  : \"p\",\n\t\t\t\ttt:   H < 12 ? \"am\" : \"pm\",\n\t\t\t\tT:    H < 12 ? \"A\"  : \"P\",\n\t\t\t\tTT:   H < 12 ? \"AM\" : \"PM\",\n\t\t\t\tZ:    utc ? \"UTC\" : (String(date).match(timezone) || [\"\"]).pop().replace(timezoneClip, \"\"),\n\t\t\t\to:    (o > 0 ? \"-\" : \"+\") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),\n\t\t\t\tS:    [\"th\", \"st\", \"nd\", \"rd\"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]\n\t\t\t};\n\n\t\treturn mask.replace(token, function ($0) {\n\t\t\treturn $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);\n\t\t});\n\t};\n}();\n\n// Some common format strings\ndateFormat.masks = {\n\t\"default\":      \"ddd mmm dd yyyy HH:MM:ss\",\n\tshortDate:      \"m/d/yy\",\n\tmediumDate:     \"mmm d, yyyy\",\n\tlongDate:       \"mmmm d, yyyy\",\n\tfullDate:       \"dddd, mmmm d, yyyy\",\n\tshortTime:      \"h:MM TT\",\n\tmediumTime:     \"h:MM:ss TT\",\n\tlongTime:       \"h:MM:ss TT Z\",\n\tisoDate:        \"yyyy-mm-dd\",\n\tisoTime:        \"HH:MM:ss\",\n\tisoDateTime:    \"yyyy-mm-dd'T'HH:MM:ss\",\n\tisoUtcDateTime: \"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'\"\n};\n\n// Internationalization strings\ndateFormat.i18n = {\n\tdayNames: [\n\t\t\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\",\n\t\t\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"\n\t],\n\tmonthNames: [\n\t\t\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n\t\t\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n\t]\n};\n\n// For convenience...\nDate.prototype.format = function (mask, utc) {\n\treturn dateFormat(this, mask, utc);\n};\n\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.bar.js",
    "content": "/*\n * g.Raphael 0.4 - Charting library, based on Raphaël\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\nRaphael.fn.g.barchart = function (x, y, width, height, values, opts) {\n    opts = opts || {};\n    var type = {round: \"round\", sharp: \"sharp\", soft: \"soft\"}[opts.type] || \"square\",\n        gutter = parseFloat(opts.gutter || \"20%\"),\n        chart = this.set(),\n        bars = this.set(),\n        covers = this.set(),\n        covers2 = this.set(),\n        total = Math.max.apply(Math, values),\n        stacktotal = [],\n        paper = this,\n        multi = 0,\n        colors = opts.colors || this.g.colors,\n        len = values.length;\n    if (this.raphael.is(values[0], \"array\")) {\n        total = [];\n        multi = len;\n        len = 0;\n        for (var i = values.length; i--;) {\n            bars.push(this.set());\n            total.push(Math.max.apply(Math, values[i]));\n            len = Math.max(len, values[i].length);\n        }\n        if (opts.stacked) {\n            for (var i = len; i--;) {\n                var tot = 0;\n                for (var j = values.length; j--;) {\n                    tot +=+ values[j][i] || 0;\n                }\n                stacktotal.push(tot);\n            }\n        }\n        for (var i = values.length; i--;) {\n            if (values[i].length < len) {\n                for (var j = len; j--;) {\n                    values[i].push(0);\n                }\n            }\n        }\n        total = Math.max.apply(Math, opts.stacked ? stacktotal : total);\n    }\n    \n    total = (opts.to) || total;\n    var barwidth = width / (len * (100 + gutter) + gutter) * 100,\n        barhgutter = barwidth * gutter / 100,\n        barvgutter = opts.vgutter == null ? 20 : opts.vgutter,\n        stack = [],\n        X = x + barhgutter,\n        Y = (height - 2 * barvgutter) / total;\n    if (!opts.stretch) {\n        barhgutter = Math.round(barhgutter);\n        barwidth = Math.floor(barwidth);\n    }\n    !opts.stacked && (barwidth /= multi || 1);\n    for (var i = 0; i < len; i++) {\n        stack = [];\n        for (var j = 0; j < (multi || 1); j++) {\n            var h = Math.round((multi ? values[j][i] : values[i]) * Y),\n                top = y + height - barvgutter - h,\n                bar = this.g.finger(Math.round(X + barwidth / 2), top + h, barwidth, h, true, type).attr({stroke: colors[multi ? j : i], fill: colors[multi ? j : i]});\n            if (multi) {\n                bars[j].push(bar);\n            } else {\n                bars.push(bar);\n            }\n            bar.y = top;\n            bar.x = Math.round(X + barwidth / 2);\n            bar.w = barwidth;\n            bar.h = h;\n            bar.value = multi ? values[j][i] : values[i];\n            if (!opts.stacked) {\n                X += barwidth;\n            } else {\n                stack.push(bar);\n            }\n        }\n        if (opts.stacked) {\n            var cvr;\n            covers2.push(cvr = this.rect(stack[0].x - stack[0].w / 2, y, barwidth, height).attr(this.g.shim));\n            cvr.bars = this.set();\n            var size = 0;\n            for (var s = stack.length; s--;) {\n                stack[s].toFront();\n            }\n            for (var s = 0, ss = stack.length; s < ss; s++) {\n                var bar = stack[s],\n                    cover,\n                    h = (size + bar.value) * Y,\n                    path = this.g.finger(bar.x, y + height - barvgutter - !!size * .5, barwidth, h, true, type, 1);\n                cvr.bars.push(bar);\n                size && bar.attr({path: path});\n                bar.h = h;\n                bar.y = y + height - barvgutter - !!size * .5 - h;\n                covers.push(cover = this.rect(bar.x - bar.w / 2, bar.y, barwidth, bar.value * Y).attr(this.g.shim));\n                cover.bar = bar;\n                cover.value = bar.value;\n                size += bar.value;\n            }\n            X += barwidth;\n        }\n        X += barhgutter;\n    }\n    covers2.toFront();\n    X = x + barhgutter;\n    if (!opts.stacked) {\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < (multi || 1); j++) {\n                var cover;\n                covers.push(cover = this.rect(Math.round(X), y + barvgutter, barwidth, height - barvgutter).attr(this.g.shim));\n                cover.bar = multi ? bars[j][i] : bars[i];\n                cover.value = cover.bar.value;\n                X += barwidth;\n            }\n            X += barhgutter;\n        }\n    }\n    chart.label = function (labels, isBottom) {\n        labels = labels || [];\n        this.labels = paper.set();\n        var L, l = -Infinity;\n        if (opts.stacked) {\n            for (var i = 0; i < len; i++) {\n                var tot = 0;\n                for (var j = 0; j < (multi || 1); j++) {\n                    tot += multi ? values[j][i] : values[i];\n                    if (j == multi - 1) {\n                        var label = paper.g.labelise(labels[i], tot, total);\n                        L = paper.g.text(bars[i * (multi || 1) + j].x, y + height - barvgutter / 2, label).insertBefore(covers[i * (multi || 1) + j]);\n                        var bb = L.getBBox();\n                        if (bb.x - 7 < l) {\n                            L.remove();\n                        } else {\n                            this.labels.push(L);\n                            l = bb.x + bb.width;\n                        }\n                    }\n                }\n            }\n        } else {\n            for (var i = 0; i < len; i++) {\n                for (var j = 0; j < (multi || 1); j++) {\n                    var label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);\n                    L = paper.g.text(bars[i * (multi || 1) + j].x, isBottom ? y + height - barvgutter / 2 : bars[i * (multi || 1) + j].y - 10, label).insertBefore(covers[i * (multi || 1) + j]);\n                    var bb = L.getBBox();\n                    if (bb.x - 7 < l) {\n                        L.remove();\n                    } else {\n                        this.labels.push(L);\n                        l = bb.x + bb.width;\n                    }\n                }\n            }\n        }\n        return this;\n    };\n    chart.hover = function (fin, fout) {\n        covers2.hide();\n        covers.show();\n        covers.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.hoverColumn = function (fin, fout) {\n        covers.hide();\n        covers2.show();\n        fout = fout || function () {};\n        covers2.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.click = function (f) {\n        covers2.hide();\n        covers.show();\n        covers.click(f);\n        return this;\n    };\n    chart.each = function (f) {\n        if (!Raphael.is(f, \"function\")) {\n            return this;\n        }\n        for (var i = covers.length; i--;) {\n            f.call(covers[i]);\n        }\n        return this;\n    };\n    chart.eachColumn = function (f) {\n        if (!Raphael.is(f, \"function\")) {\n            return this;\n        }\n        for (var i = covers2.length; i--;) {\n            f.call(covers2[i]);\n        }\n        return this;\n    };\n    chart.clickColumn = function (f) {\n        covers.hide();\n        covers2.show();\n        covers2.click(f);\n        return this;\n    };\n    chart.push(bars, covers, covers2);\n    chart.bars = bars;\n    chart.covers = covers;\n    return chart;\n};\nRaphael.fn.g.hbarchart = function (x, y, width, height, values, opts) {\n    opts = opts || {};\n    var type = {round: \"round\", sharp: \"sharp\", soft: \"soft\"}[opts.type] || \"square\",\n        gutter = parseFloat(opts.gutter || \"20%\"),\n        chart = this.set(),\n        bars = this.set(),\n        covers = this.set(),\n        covers2 = this.set(),\n        total = Math.max.apply(Math, values),\n        stacktotal = [],\n        paper = this,\n        multi = 0,\n        colors = opts.colors || this.g.colors,\n        len = values.length;\n    if (this.raphael.is(values[0], \"array\")) {\n        total = [];\n        multi = len;\n        len = 0;\n        for (var i = values.length; i--;) {\n            bars.push(this.set());\n            total.push(Math.max.apply(Math, values[i]));\n            len = Math.max(len, values[i].length);\n        }\n        if (opts.stacked) {\n            for (var i = len; i--;) {\n                var tot = 0;\n                for (var j = values.length; j--;) {\n                    tot +=+ values[j][i] || 0;\n                }\n                stacktotal.push(tot);\n            }\n        }\n        for (var i = values.length; i--;) {\n            if (values[i].length < len) {\n                for (var j = len; j--;) {\n                    values[i].push(0);\n                }\n            }\n        }\n        total = Math.max.apply(Math, opts.stacked ? stacktotal : total);\n    }\n    \n    total = (opts.to) || total;\n    var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100),\n        bargutter = Math.floor(barheight * gutter / 100),\n        stack = [],\n        Y = y + bargutter,\n        X = (width - 1) / total;\n    !opts.stacked && (barheight /= multi || 1);\n    for (var i = 0; i < len; i++) {\n        stack = [];\n        for (var j = 0; j < (multi || 1); j++) {\n            var val = multi ? values[j][i] : values[i],\n                bar = this.g.finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type).attr({stroke: colors[multi ? j : i], fill: colors[multi ? j : i]});\n            if (multi) {\n                bars[j].push(bar);\n            } else {\n                bars.push(bar);\n            }\n            bar.x = x + Math.round(val * X);\n            bar.y = Y + barheight / 2;\n            bar.w = Math.round(val * X);\n            bar.h = barheight;\n            bar.value = +val;\n            if (!opts.stacked) {\n                Y += barheight;\n            } else {\n                stack.push(bar);\n            }\n        }\n        if (opts.stacked) {\n            var cvr = this.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(this.g.shim);\n            covers2.push(cvr);\n            cvr.bars = this.set();\n            var size = 0;\n            for (var s = stack.length; s--;) {\n                stack[s].toFront();\n            }\n            for (var s = 0, ss = stack.length; s < ss; s++) {\n                var bar = stack[s],\n                    cover,\n                    val = Math.round((size + bar.value) * X),\n                    path = this.g.finger(x, bar.y, val, barheight - 1, false, type, 1);\n                cvr.bars.push(bar);\n                size && bar.attr({path: path});\n                bar.w = val;\n                bar.x = x + val;\n                covers.push(cover = this.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(this.g.shim));\n                cover.bar = bar;\n                size += bar.value;\n            }\n            Y += barheight;\n        }\n        Y += bargutter;\n    }\n    covers2.toFront();\n    Y = y + bargutter;\n    if (!opts.stacked) {\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < multi; j++) {\n                var cover = this.rect(x, Y, width, barheight).attr(this.g.shim);\n                covers.push(cover);\n                cover.bar = bars[j][i];\n                Y += barheight;\n            }\n            Y += bargutter;\n        }\n    }\n    chart.label = function (labels, isRight) {\n        labels = labels || [];\n        this.labels = paper.set();\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < multi; j++) {\n                var  label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);\n                var X = isRight ? bars[i * (multi || 1) + j].x - barheight / 2 + 3 : x + 5,\n                    A = isRight ? \"end\" : \"start\",\n                    L;\n                this.labels.push(L = paper.g.text(X, bars[i * (multi || 1) + j].y, label).attr({\"text-anchor\": A}).insertBefore(covers[0]));\n                if (L.getBBox().x < x + 5) {\n                    L.attr({x: x + 5, \"text-anchor\": \"start\"});\n                } else {\n                    bars[i * (multi || 1) + j].label = L;\n                }\n            }\n        }\n        return this;\n    };\n    chart.hover = function (fin, fout) {\n        covers2.hide();\n        covers.show();\n        fout = fout || function () {};\n        covers.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.hoverColumn = function (fin, fout) {\n        covers.hide();\n        covers2.show();\n        fout = fout || function () {};\n        covers2.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.each = function (f) {\n        if (!Raphael.is(f, \"function\")) {\n            return this;\n        }\n        for (var i = covers.length; i--;) {\n            f.call(covers[i]);\n        }\n        return this;\n    };\n    chart.eachColumn = function (f) {\n        if (!Raphael.is(f, \"function\")) {\n            return this;\n        }\n        for (var i = covers2.length; i--;) {\n            f.call(covers2[i]);\n        }\n        return this;\n    };\n    chart.click = function (f) {\n        covers2.hide();\n        covers.show();\n        covers.click(f);\n        return this;\n    };\n    chart.clickColumn = function (f) {\n        covers.hide();\n        covers2.show();\n        covers2.click(f);\n        return this;\n    };\n    chart.push(bars, covers, covers2);\n    chart.bars = bars;\n    chart.covers = covers;\n    return chart;\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.dot.js",
    "content": "/*\n * g.Raphael 0.4 - Charting library, based on Raphaël\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\nRaphael.fn.g.dotchart = function (x, y, width, height, valuesx, valuesy, size, opts) {\n    function drawAxis(ax) {\n        +ax[0] && (ax[0] = paper.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, opts.axisxlabels || null, opts.axisxtype || \"t\"));\n        +ax[1] && (ax[1] = paper.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, opts.axisylabels || null, opts.axisytype || \"t\"));\n        +ax[2] && (ax[2] = paper.g.axis(x + gutter, y + height - gutter + maxR, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, opts.axisxlabels || null, opts.axisxtype || \"t\"));\n        +ax[3] && (ax[3] = paper.g.axis(x + gutter - maxR, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, opts.axisylabels || null, opts.axisytype || \"t\"));\n    }\n    opts = opts || {};\n    var xdim = this.g.snapEnds(Math.min.apply(Math, valuesx), Math.max.apply(Math, valuesx), valuesx.length - 1),\n        minx = xdim.from,\n        maxx = xdim.to,\n        gutter = opts.gutter || 10,\n        ydim = this.g.snapEnds(Math.min.apply(Math, valuesy), Math.max.apply(Math, valuesy), valuesy.length - 1),\n        miny = ydim.from,\n        maxy = ydim.to,\n        len = Math.max(valuesx.length, valuesy.length, size.length),\n        symbol = this.g.markers[opts.symbol] || \"disc\",\n        res = this.set(),\n        series = this.set(),\n        max = opts.max || 100,\n        top = Math.max.apply(Math, size),\n        R = [],\n        paper = this,\n        k = Math.sqrt(top / Math.PI) * 2 / max;\n\n    for (var i = 0; i < len; i++) {\n        R[i] = Math.min(Math.sqrt(size[i] / Math.PI) * 2 / k, max);\n    }\n    gutter = Math.max.apply(Math, R.concat(gutter));\n    var axis = this.set(),\n        maxR = Math.max.apply(Math, R);\n    if (opts.axis) {\n        var ax = (opts.axis + \"\").split(/[,\\s]+/);\n        drawAxis(ax);\n        var g = [], b = [];\n        for (var i = 0, ii = ax.length; i < ii; i++) {\n            var bb = ax[i].all ? ax[i].all.getBBox()[[\"height\", \"width\"][i % 2]] : 0;\n            g[i] = bb + gutter;\n            b[i] = bb;\n        }\n        gutter = Math.max.apply(Math, g.concat(gutter));\n        for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {\n            ax[i].remove();\n            ax[i] = 1;\n        }\n        drawAxis(ax);\n        for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {\n            axis.push(ax[i].all);\n        }\n        res.axis = axis;\n    }\n    var kx = (width - gutter * 2) / ((maxx - minx) || 1),\n        ky = (height - gutter * 2) / ((maxy - miny) || 1);\n    for (var i = 0, ii = valuesy.length; i < ii; i++) {\n        var sym = this.raphael.is(symbol, \"array\") ? symbol[i] : symbol,\n            X = x + gutter + (valuesx[i] - minx) * kx,\n            Y = y + height - gutter - (valuesy[i] - miny) * ky;\n        sym && R[i] && series.push(this.g[sym](X, Y, R[i]).attr({fill: opts.heat ? this.g.colorValue(R[i], maxR) : Raphael.fn.g.colors[0], \"fill-opacity\": opts.opacity ? R[i] / max : 1, stroke: \"none\"}));\n    }\n    var covers = this.set();\n    for (var i = 0, ii = valuesy.length; i < ii; i++) {\n        var X = x + gutter + (valuesx[i] - minx) * kx,\n            Y = y + height - gutter - (valuesy[i] - miny) * ky;\n        covers.push(this.circle(X, Y, maxR).attr(this.g.shim));\n        opts.href && opts.href[i] && covers[i].attr({href: opts.href[i]});\n        covers[i].r = +R[i].toFixed(3);\n        covers[i].x = +X.toFixed(3);\n        covers[i].y = +Y.toFixed(3);\n        covers[i].X = valuesx[i];\n        covers[i].Y = valuesy[i];\n        covers[i].value = size[i] || 0;\n        covers[i].dot = series[i];\n    }\n    res.covers = covers;\n    res.series = series;\n    res.push(series, axis, covers);\n    res.hover = function (fin, fout) {\n        covers.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    res.click = function (f) {\n        covers.click(f);\n        return this;\n    };\n    res.each = function (f) {\n        if (!Raphael.is(f, \"function\")) {\n            return this;\n        }\n        for (var i = covers.length; i--;) {\n            f.call(covers[i]);\n        }\n        return this;\n    };\n    res.href = function (map) {\n        var cover;\n        for (var i = covers.length; i--;) {\n            cover = covers[i];\n            if (cover.X == map.x && cover.Y == map.y && cover.value == map.value) {\n                cover.attr({href: map.href});\n            }\n        }\n    };\n    return res;\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.line.js",
    "content": "/*\n * g.Raphael 0.4 - Charting library, based on Raphaël\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\nRaphael.fn.g.linechart = function (x, y, width, height, valuesx, valuesy, opts) {\n    function shrink(values, dim) {\n        var k = values.length / dim,\n            j = 0,\n            l = k,\n            sum = 0,\n            res = [];\n        while (j < values.length) {\n            l--;\n            if (l < 0) {\n                sum += values[j] * (1 + l);\n                res.push(sum / k);\n                sum = values[j++] * -l;\n                l += k;\n            } else {\n                sum += values[j++];\n            }\n        }\n        return res;\n    }\n    opts = opts || {};\n    if (!this.raphael.is(valuesx[0], \"array\")) {\n        valuesx = [valuesx];\n    }\n    if (!this.raphael.is(valuesy[0], \"array\")) {\n        valuesy = [valuesy];\n    }\n    var allx = Array.prototype.concat.apply([], valuesx),\n        ally = Array.prototype.concat.apply([], valuesy),\n        xdim = this.g.snapEnds(Math.min.apply(Math, allx), Math.max.apply(Math, allx), valuesx[0].length - 1),\n        minx = xdim.from,\n        maxx = xdim.to,\n        gutter = opts.gutter || 10,\n        kx = (width - gutter * 2) / (maxx - minx),\n        ydim = this.g.snapEnds(Math.min.apply(Math, ally), Math.max.apply(Math, ally), valuesy[0].length - 1),\n        miny = ydim.from,\n        maxy = ydim.to,\n        ky = (height - gutter * 2) / (maxy - miny),\n        len = Math.max(valuesx[0].length, valuesy[0].length),\n        symbol = opts.symbol || \"\",\n        colors = opts.colors || Raphael.fn.g.colors,\n        that = this,\n        columns = null,\n        dots = null,\n        chart = this.set(),\n        path = [];\n\n    for (var i = 0, ii = valuesy.length; i < ii; i++) {\n        len = Math.max(len, valuesy[i].length);\n    }\n    var shades = this.set();\n    for (var i = 0, ii = valuesy.length; i < ii; i++) {\n        if (opts.shade) {\n            shades.push(this.path().attr({stroke: \"none\", fill: colors[i], opacity: opts.nostroke ? 1 : .3}));\n        }\n        if (valuesy[i].length > width - 2 * gutter) {\n            valuesy[i] = shrink(valuesy[i], width - 2 * gutter);\n            len = width - 2 * gutter;\n        }\n        if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {\n            valuesx[i] = shrink(valuesx[i], width - 2 * gutter);\n        }\n    }\n    var axis = this.set();\n    if (opts.axis) {\n        var ax = (opts.axis + \"\").split(/[,\\s]+/);\n        +ax[0] && axis.push(this.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, opts.northlabels));\n        +ax[1] && axis.push(this.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, opts.eastlabels));\n        +ax[2] && axis.push(this.g.axis(x + gutter, y + height - gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, opts.southlabels));\n        +ax[3] && axis.push(this.g.axis(x + gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, opts.westlabels));\n    }\n    if (opts.northAxisLabel) {\n\tthis.g.text(x + gutter + width/2, gutter, opts.northAxisLabel);\n    }\n    if (opts.southAxisLabel) {\n\tthis.g.text(x + gutter + width/2, y + height + 20, opts.southAxisLabel);\n    }\n    if (opts.westAxisLabel) {\n\tthis.g.text(gutter, y + gutter + height/2, opts.westAxisLabel).attr({rotation: -90});\n    }\n    if (opts.eastAxisLabel) {\n\tthis.g.text(x + gutter + width + 20, y + gutter + height/2, opts.eastAxisLabel).attr({rotation: 90});\n    }\n\n    var lines = this.set(),\n        symbols = this.set(),\n        line;\n    for (var i = 0, ii = valuesy.length; i < ii; i++) {\n        if (!opts.nostroke) {\n            lines.push(line = this.path().attr({\n                stroke: colors[i],\n                \"stroke-width\": opts.width || 2,\n                \"stroke-linejoin\": \"round\",\n                \"stroke-linecap\": \"round\",\n                \"stroke-dasharray\": opts.dash || \"\"\n            }));\n        }\n        var sym = this.raphael.is(symbol, \"array\") ? symbol[i] : symbol,\n            symset = this.set();\n        path = [];\n        for (var j = 0, jj = valuesy[i].length; j < jj; j++) {\n            var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx;\n            var Y = y + height - gutter - (valuesy[i][j] - miny) * ky;\n            (Raphael.is(sym, \"array\") ? sym[j] : sym) && symset.push(this.g[Raphael.fn.g.markers[this.raphael.is(sym, \"array\") ? sym[j] : sym]](X, Y, (opts.width || 2) * 3).attr({fill: colors[i], stroke: \"none\"}));\n            path = path.concat([j ? \"L\" : \"M\", X, Y]);\n        }\n        symbols.push(symset);\n        if (opts.shade) {\n            shades[i].attr({path: path.concat([\"L\", X, y + height - gutter, \"L\",  x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, \"z\"]).join(\",\")});\n        }\n        !opts.nostroke && line.attr({path: path.join(\",\")});\n    }\n    function createColumns(f) {\n        // unite Xs together\n        var Xs = [];\n        for (var i = 0, ii = valuesx.length; i < ii; i++) {\n            Xs = Xs.concat(valuesx[i]);\n        }\n        Xs.sort();\n        // remove duplicates\n        var Xs2 = [],\n            xs = [];\n        for (var i = 0, ii = Xs.length; i < ii; i++) {\n            Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);\n        }\n        Xs = Xs2;\n        ii = Xs.length;\n        var cvrs = f || that.set();\n        for (var i = 0; i < ii; i++) {\n            var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,\n                w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,\n                C;\n            f ? (C = {}) : cvrs.push(C = that.rect(X - 1, y, Math.max(w + 1, 1), height).attr({stroke: \"none\", fill: \"#000\", opacity: 0}));\n            C.values = [];\n            C.symbols = that.set();\n            C.y = [];\n            C.x = xs[i];\n            C.axis = Xs[i];\n            for (var j = 0, jj = valuesy.length; j < jj; j++) {\n                Xs2 = valuesx[j] || valuesx[0];\n                for (var k = 0, kk = Xs2.length; k < kk; k++) {\n                    if (Xs2[k] == Xs[i]) {\n                        C.values.push(valuesy[j][k]);\n                        C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);\n                        C.symbols.push(chart.symbols[j][k]);\n                    }\n                }\n            }\n            f && f.call(C);\n        }\n        !f && (columns = cvrs);\n    }\n    function createDots(f) {\n        var cvrs = f || that.set(),\n            C;\n        for (var i = 0, ii = valuesy.length; i < ii; i++) {\n            for (var j = 0, jj = valuesy[i].length; j < jj; j++) {\n                var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,\n                    nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,\n                    Y = y + height - gutter - (valuesy[i][j] - miny) * ky;\n                f ? (C = {}) : cvrs.push(C = that.circle(X, Y, Math.abs(nearX - X) / 2).attr({stroke: \"none\", fill: \"#000\", opacity: 0}));\n                C.x = X;\n                C.y = Y;\n                C.value = valuesy[i][j];\n                C.line = chart.lines[i];\n                C.shade = chart.shades[i];\n                C.symbol = chart.symbols[i][j];\n                C.symbols = chart.symbols[i];\n                C.axis = (valuesx[i] || valuesx[0])[j];\n                f && f.call(C);\n            }\n        }\n        !f && (dots = cvrs);\n    }\n    chart.push(lines, shades, symbols, axis, columns, dots);\n    chart.lines = lines;\n    chart.shades = shades;\n    chart.symbols = symbols;\n    chart.axis = axis;\n    chart.hoverColumn = function (fin, fout) {\n        !columns && createColumns();\n        columns.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.clickColumn = function (f) {\n        !columns && createColumns();\n        columns.click(f);\n        return this;\n    };\n    chart.hrefColumn = function (cols) {\n        var hrefs = that.raphael.is(arguments[0], \"array\") ? arguments[0] : arguments;\n        if (!(arguments.length - 1) && typeof cols == \"object\") {\n            for (var x in cols) {\n                for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {\n                    columns[i].attr(\"href\", cols[x]);\n                }\n            }\n        }\n        !columns && createColumns();\n        for (var i = 0, ii = hrefs.length; i < ii; i++) {\n            columns[i] && columns[i].attr(\"href\", hrefs[i]);\n        }\n        return this;\n    };\n    chart.hover = function (fin, fout) {\n        !dots && createDots();\n        dots.mouseover(fin).mouseout(fout);\n        return this;\n    };\n    chart.click = function (f) {\n        !dots && createDots();\n        dots.click(f);\n        return this;\n    };\n    chart.each = function (f) {\n        createDots(f);\n        return this;\n    };\n    chart.eachColumn = function (f) {\n        createColumns(f);\n        return this;\n    };\n    return chart;\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.pie.js",
    "content": "/*\n * g.Raphael 0.4 - Charting library, based on Raphaël\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\nRaphael.fn.g.piechart = function (cx, cy, r, values, opts) {\n    opts = opts || {};\n    var paper = this,\n        sectors = [],\n        covers = this.set(),\n        chart = this.set(),\n        series = this.set(),\n        order = [],\n        len = values.length,\n        angle = 0,\n        total = 0,\n        others = 0,\n        cut = 9,\n        defcut = true;\n    chart.covers = covers;\n    if (len == 1) {\n        series.push(this.circle(cx, cy, r).attr({fill: this.g.colors[0], stroke: opt.stroke || \"#fff\", \"stroke-width\": opts.strokewidth == null ? 1 : opts.strokewidth}));\n        covers.push(this.circle(cx, cy, r).attr(this.g.shim));\n        total = values[0];\n        values[0] = {value: values[0], order: 0, valueOf: function () { return this.value; }};\n        series[0].middle = {x: cx, y: cy};\n        series[0].mangle = 180;\n    } else {\n        function sector(cx, cy, r, startAngle, endAngle, fill) {\n            var rad = Math.PI / 180,\n                x1 = cx + r * Math.cos(-startAngle * rad),\n                x2 = cx + r * Math.cos(-endAngle * rad),\n                xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad),\n                y1 = cy + r * Math.sin(-startAngle * rad),\n                y2 = cy + r * Math.sin(-endAngle * rad),\n                ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad),\n                res = [\"M\", cx, cy, \"L\", x1, y1, \"A\", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2, \"z\"];\n            res.middle = {x: xm, y: ym};\n            return res;\n        }\n        for (var i = 0; i < len; i++) {\n            total += values[i];\n            values[i] = {value: values[i], order: i, valueOf: function () { return this.value; }};\n        }\n        values.sort(function (a, b) {\n            return b.value - a.value;\n        });\n        for (var i = 0; i < len; i++) {\n            if (defcut && values[i] * 360 / total <= 1.5) {\n                cut = i;\n                defcut = false;\n            }\n            if (i > cut) {\n                defcut = false;\n                values[cut].value += values[i];\n                values[cut].others = true;\n                others = values[cut].value;\n            }\n        }\n        len = Math.min(cut + 1, values.length);\n        others && values.splice(len) && (values[cut].others = true);\n        for (var i = 0; i < len; i++) {\n            var mangle = angle - 360 * values[i] / total / 2;\n            if (!i) {\n                angle = 90 - mangle;\n                mangle = angle - 360 * values[i] / total / 2;\n            }\n            if (opts.init) {\n                var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(\",\");\n            }\n            var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);\n            var p = this.path(opts.init ? ipath : path).attr({fill: opts.colors && opts.colors[i] || this.g.colors[i] || \"#666\", stroke: opts.stroke || \"#fff\", \"stroke-width\": (opts.strokewidth == null ? 1 : opts.strokewidth), \"stroke-linejoin\": \"round\"});\n            p.value = values[i];\n            p.middle = path.middle;\n            p.mangle = mangle;\n            sectors.push(p);\n            series.push(p);\n            opts.init && p.animate({path: path.join(\",\")}, (+opts.init - 1) || 1000, \">\");\n        }\n        for (var i = 0; i < len; i++) {\n            var p = paper.path(sectors[i].attr(\"path\")).attr(this.g.shim);\n            opts.href && opts.href[i] && p.attr({href: opts.href[i]});\n            p.attr = function () {};\n            covers.push(p);\n            series.push(p);\n        }\n    }\n\n    chart.hover = function (fin, fout) {\n        fout = fout || function () {};\n        var that = this;\n        for (var i = 0; i < len; i++) {\n            (function (sector, cover, j) {\n                var o = {\n                    sector: sector,\n                    cover: cover,\n                    cx: cx,\n                    cy: cy,\n                    mx: sector.middle.x,\n                    my: sector.middle.y,\n                    mangle: sector.mangle,\n                    r: r,\n                    value: values[j],\n                    total: total,\n                    label: that.labels && that.labels[j]\n                };\n                cover.mouseover(function () {\n                    fin.call(o);\n                }).mouseout(function () {\n                    fout.call(o);\n                });\n            })(series[i], covers[i], i);\n        }\n        return this;\n    };\n    // x: where label could be put\n    // y: where label could be put\n    // value: value to show\n    // total: total number to count %\n    chart.each = function (f) {\n        var that = this;\n        for (var i = 0; i < len; i++) {\n            (function (sector, cover, j) {\n                var o = {\n                    sector: sector,\n                    cover: cover,\n                    cx: cx,\n                    cy: cy,\n                    x: sector.middle.x,\n                    y: sector.middle.y,\n                    mangle: sector.mangle,\n                    r: r,\n                    value: values[j],\n                    total: total,\n                    label: that.labels && that.labels[j]\n                };\n                f.call(o);\n            })(series[i], covers[i], i);\n        }\n        return this;\n    };\n    chart.click = function (f) {\n        var that = this;\n        for (var i = 0; i < len; i++) {\n            (function (sector, cover, j) {\n                var o = {\n                    sector: sector,\n                    cover: cover,\n                    cx: cx,\n                    cy: cy,\n                    mx: sector.middle.x,\n                    my: sector.middle.y,\n                    mangle: sector.mangle,\n                    r: r,\n                    value: values[j],\n                    total: total,\n                    label: that.labels && that.labels[j]\n                };\n                cover.click(function () { f.call(o); });\n            })(series[i], covers[i], i);\n        }\n        return this;\n    };\n    chart.inject = function (element) {\n        element.insertBefore(covers[0]);\n    };\n    var legend = function (labels, otherslabel, mark, dir) {\n        var x = cx + r + r / 5,\n            y = cy,\n            h = y + 10;\n        labels = labels || [];\n        dir = (dir && dir.toLowerCase && dir.toLowerCase()) || \"east\";\n        mark = paper.g.markers[mark && mark.toLowerCase()] || \"disc\";\n        chart.labels = paper.set();\n        for (var i = 0; i < len; i++) {\n            var clr = series[i].attr(\"fill\"),\n                j = values[i].order,\n                txt;\n            values[i].others && (labels[j] = otherslabel || \"Others\");\n            labels[j] = paper.g.labelise(labels[j], values[i], total);\n            chart.labels.push(paper.set());\n            chart.labels[i].push(paper.g[mark](x + 5, h, 5).attr({fill: clr, stroke: \"none\"}));\n            chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(paper.g.txtattr).attr({fill: opts.legendcolor || \"#000\", \"text-anchor\": \"start\"}));\n            covers[i].label = chart.labels[i];\n            h += txt.getBBox().height * 1.2;\n        }\n        var bb = chart.labels.getBBox(),\n            tr = {\n                east: [0, -bb.height / 2],\n                west: [-bb.width - 2 * r - 20, -bb.height / 2],\n                north: [-r - bb.width / 2, -r - bb.height - 10],\n                south: [-r - bb.width / 2, r + 10]\n            }[dir];\n        chart.labels.translate.apply(chart.labels, tr);\n        chart.push(chart.labels);\n    };\n    if (opts.legend) {\n        legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);\n    }\n    chart.push(series, covers);\n    chart.series = series;\n    chart.covers = covers;\n    return chart;\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.raphael.js",
    "content": "/*\n * g.Raphael 0.4 - Charting library, based on Raphaël\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\n \n \n(function () {\n    Raphael.fn.g = Raphael.fn.g || {};\n    Raphael.fn.g.markers = {\n        disc: \"disc\",\n        o: \"disc\",\n        flower: \"flower\",\n        f: \"flower\",\n        diamond: \"diamond\",\n        d: \"diamond\",\n        square: \"square\",\n        s: \"square\",\n        triangle: \"triangle\",\n        t: \"triangle\",\n        star: \"star\",\n        \"*\": \"star\",\n        cross: \"cross\",\n        x: \"cross\",\n        plus: \"plus\",\n        \"+\": \"plus\",\n        arrow: \"arrow\",\n        \"->\": \"arrow\"\n    };\n    Raphael.fn.g.shim = {stroke: \"none\", fill: \"#000\", \"fill-opacity\": 0};\n    Raphael.fn.g.txtattr = {font: \"12px Arial, sans-serif\"};\n    Raphael.fn.g.colors = [];\n    var hues = [.6, .2, .05, .1333, .75, 0];\n    for (var i = 0; i < 10; i++) {\n        if (i < hues.length) {\n            Raphael.fn.g.colors.push(\"hsb(\" + hues[i] + \", .75, .75)\");\n        } else {\n            Raphael.fn.g.colors.push(\"hsb(\" + hues[i - hues.length] + \", 1, .5)\");\n        }\n    }\n    Raphael.fn.g.text = function (x, y, text) {\n        return this.text(x, y, text).attr(this.g.txtattr);\n    };\n    Raphael.fn.g.labelise = function (label, val, total) {\n        if (label) {\n            return (label + \"\").replace(/(##+(?:\\.#+)?)|(%%+(?:\\.%+)?)/g, function (all, value, percent) {\n                if (value) {\n                    return (+val).toFixed(value.replace(/^#+\\.?/g, \"\").length);\n                }\n                if (percent) {\n                    return (val * 100 / total).toFixed(percent.replace(/^%+\\.?/g, \"\").length) + \"%\";\n                }\n            });\n        } else {\n            return (+val).toFixed(0);\n        }\n    };\n\n    Raphael.fn.g.finger = function (x, y, width, height, dir, ending, isPath) {\n        // dir 0 for horisontal and 1 for vertical\n        if ((dir && !height) || (!dir && !width)) {\n            return isPath ? \"\" : this.path();\n        }\n        ending = {square: \"square\", sharp: \"sharp\", soft: \"soft\"}[ending] || \"round\";\n        var path;\n        height = Math.round(height);\n        width = Math.round(width);\n        x = Math.round(x);\n        y = Math.round(y);\n        switch (ending) {\n            case \"round\":\n            if (!dir) {\n                var r = Math.floor(height / 2);\n                if (width < r) {\n                    r = width;\n                    path = [\"M\", x + .5, y + .5 - Math.floor(height / 2), \"l\", 0, 0, \"a\", r, Math.floor(height / 2), 0, 0, 1, 0, height, \"l\", 0, 0, \"z\"];\n                } else {\n                    path = [\"M\", x + .5, y + .5 - r, \"l\", width - r, 0, \"a\", r, r, 0, 1, 1, 0, height, \"l\", r - width, 0, \"z\"];\n                }\n            } else {\n                var r = Math.floor(width / 2);\n                if (height < r) {\n                    r = height;\n                    path = [\"M\", x - Math.floor(width / 2), y, \"l\", 0, 0, \"a\", Math.floor(width / 2), r, 0, 0, 1, width, 0, \"l\", 0, 0, \"z\"];\n                } else {\n                    path = [\"M\", x - r, y, \"l\", 0, r - height, \"a\", r, r, 0, 1, 1, width, 0, \"l\", 0, height - r, \"z\"];\n                }\n            }\n            break;\n            case \"sharp\":\n            if (!dir) {\n                var half = Math.floor(height / 2);\n                path = [\"M\", x, y + half, \"l\", 0, -height, Math.max(width - half, 0), 0, Math.min(half, width), half, -Math.min(half, width), half + (half * 2 < height), \"z\"];\n            } else {\n                var half = Math.floor(width / 2);\n                path = [\"M\", x + half, y, \"l\", -width, 0, 0, -Math.max(height - half, 0), half, -Math.min(half, height), half, Math.min(half, height), half, \"z\"];\n            }\n            break;\n            case \"square\":\n            if (!dir) {\n                path = [\"M\", x, y + Math.floor(height / 2), \"l\", 0, -height, width, 0, 0, height, \"z\"];\n            } else {\n                path = [\"M\", x + Math.floor(width / 2), y, \"l\", 1 - width, 0, 0, -height, width - 1, 0, \"z\"];\n            }\n            break;\n            case \"soft\":\n            var r;\n            if (!dir) {\n                r = Math.min(width, Math.round(height / 5));\n                path = [\"M\", x + .5, y + .5 - Math.floor(height / 2), \"l\", width - r, 0, \"a\", r, r, 0, 0, 1, r, r, \"l\", 0, height - r * 2, \"a\", r, r, 0, 0, 1, -r, r, \"l\", r - width, 0, \"z\"];\n            } else {\n                r = Math.min(Math.round(width / 5), height);\n                path = [\"M\", x - Math.floor(width / 2), y, \"l\", 0, r - height, \"a\", r, r, 0, 0, 1, r, -r, \"l\", width - 2 * r, 0, \"a\", r, r, 0, 0, 1, r, r, \"l\", 0, height - r, \"z\"];\n            }\n        }\n        if (isPath) {\n            return path.join(\",\");\n        } else {\n            return this.path(path);\n        }\n    };\n\n    // Symbols\n    Raphael.fn.g.disc = function (cx, cy, r) {\n        return this.circle(cx, cy, r);\n    };\n    Raphael.fn.g.line = function (cx, cy, r) {\n        return this.rect(cx - r, cy - r / 5, 2 * r, 2 * r / 5);\n    };\n    Raphael.fn.g.square = function (cx, cy, r) {\n        r = r * .7;\n        return this.rect(cx - r, cy - r, 2 * r, 2 * r);\n    };\n    Raphael.fn.g.triangle = function (cx, cy, r) {\n        r *= 1.75;\n        return this.path(\"M\".concat(cx, \",\", cy, \"m0-\", r * .58, \"l\", r * .5, \",\", r * .87, \"-\", r, \",0z\"));\n    };\n    Raphael.fn.g.diamond = function (cx, cy, r) {\n        return this.path([\"M\", cx, cy - r, \"l\", r, r, -r, r, -r, -r, r, -r, \"z\"]);\n    };\n    Raphael.fn.g.flower = function (cx, cy, r, n) {\n        r = r * 1.25;\n        var rout = r,\n            rin = rout * .5;\n        n = +n < 3 || !n ? 5 : n;\n        var points = [\"M\", cx, cy + rin, \"Q\"],\n            R;\n        for (var i = 1; i < n * 2 + 1; i++) {\n            R = i % 2 ? rout : rin;\n            points = points.concat([+(cx + R * Math.sin(i * Math.PI / n)).toFixed(3), +(cy + R * Math.cos(i * Math.PI / n)).toFixed(3)]);\n        }\n        points.push(\"z\");\n        return this.path(points.join(\",\"));\n    };\n    Raphael.fn.g.star = function (cx, cy, r, r2) {\n        r2 = r2 || r * .5;\n        var points = [\"M\", cx, cy + r2, \"L\"],\n            R;\n        for (var i = 1; i < 10; i++) {\n            R = i % 2 ? r : r2;\n            points = points.concat([(cx + R * Math.sin(i * Math.PI * .2)).toFixed(3), (cy + R * Math.cos(i * Math.PI * .2)).toFixed(3)]);\n        }\n        points.push(\"z\");\n        return this.path(points.join(\",\"));\n    };\n    Raphael.fn.g.cross = function (cx, cy, r) {\n        r = r / 2.5;\n        return this.path(\"M\".concat(cx - r, \",\", cy, \"l\", [-r, -r, r, -r, r, r, r, -r, r, r, -r, r, r, r, -r, r, -r, -r, -r, r, -r, -r, \"z\"]));\n    };\n    Raphael.fn.g.plus = function (cx, cy, r) {\n        r = r / 2;\n        return this.path(\"M\".concat(cx - r / 2, \",\", cy - r / 2, \"l\", [0, -r, r, 0, 0, r, r, 0, 0, r, -r, 0, 0, r, -r, 0, 0, -r, -r, 0, 0, -r, \"z\"]));\n    };\n    Raphael.fn.g.arrow = function (cx, cy, r) {\n        return this.path(\"M\".concat(cx - r * .7, \",\", cy - r * .4, \"l\", [r * .6, 0, 0, -r * .4, r, r * .8, -r, r * .8, 0, -r * .4, -r * .6, 0], \"z\"));\n    };\n\n    // Tooltips\n    Raphael.fn.g.tag = function (x, y, text, angle, r) {\n        angle = angle || 0;\n        r = r == null ? 5 : r;\n        text = text == null ? \"$9.99\" : text;\n        var R = .5522 * r,\n            res = this.set(),\n            d = 3;\n        res.push(this.path().attr({fill: \"#000\", stroke: \"none\"}));\n        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: \"#fff\"}));\n        res.update = function () {\n            this.rotate(0, x, y);\n            var bb = this[1].getBBox();\n            if (bb.height >= r * 2) {\n                this[0].attr({path: [\"M\", x, y + r, \"a\", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, \"m\", 0, -r * 2 -d, \"a\", r + d, r + d, 0, 1, 0, 0, (r + d) * 2, \"L\", x + r + d, y + bb.height / 2 + d, \"l\", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0, \"L\", x, y - r - d].join(\",\")});\n            } else {\n                var dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2));\n                // [\"c\", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r]\n                // \"a\", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2,\n                this[0].attr({path: [\"M\", x, y + r, \"c\", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r, \"M\", x + dx, y - bb.height / 2 - d, \"a\", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d, \"l\", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d, \"L\", x + dx, y - bb.height / 2 - d].join(\",\")});\n            }\n            this[1].attr({x: x + r + d + bb.width / 2, y: y});\n            angle = (360 - angle) % 360;\n            this.rotate(angle, x, y);\n            angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]});\n            return this;\n        };\n        res.update();\n        return res;\n    };\n    Raphael.fn.g.popupit = function (x, y, set, dir, size) {\n        dir = dir == null ? 2 : dir;\n        size = size || 5;\n        x = Math.round(x) + .5;\n        y = Math.round(y) + .5;\n        var bb = set.getBBox(),\n            w = Math.round(bb.width / 2),\n            h = Math.round(bb.height / 2),\n            dx = [0, w + size * 2, 0, -w - size * 2],\n            dy = [-h * 2 - size * 3, -h - size, 0, -h - size],\n            p = [\"M\", x - dx[dir], y - dy[dir], \"l\", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, \"a\", size, size, 0, 0, 1, -size, -size,\n                \"l\", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), \"a\", size, size, 0, 0, 1, size, -size,\n                \"l\", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, \"a\", size, size, 0, 0, 1, size, size,\n                \"l\", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), \"a\", size, size, 0, 0, 1, -size, size,\n                \"l\", -Math.max(w - size, 0), 0, \"z\"].join(\",\"),\n            xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir];\n        set.translate(xy.x - w - bb.x, xy.y - h - bb.y);\n        return this.path(p).attr({fill: \"#000\", stroke: \"none\"}).insertBefore(set.node ? set : set[0]);\n    };\n    Raphael.fn.g.popup = function (x, y, text, dir, size) {\n        dir = dir == null ? 2 : dir;\n        size = size || 5;\n        text = text || \"$9.99\";\n        var res = this.set(),\n            d = 3;\n        res.push(this.path().attr({fill: \"#000\", stroke: \"none\"}));\n        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: \"#fff\"}));\n        res.update = function (X, Y, withAnimation) {\n            X = X || x;\n            Y = Y || y;\n            var bb = this[1].getBBox(),\n                w = bb.width / 2,\n                h = bb.height / 2,\n                dx = [0, w + size * 2, 0, -w - size * 2],\n                dy = [-h * 2 - size * 3, -h - size, 0, -h - size],\n                p = [\"M\", X - dx[dir], Y - dy[dir], \"l\", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, \"a\", size, size, 0, 0, 1, -size, -size,\n                    \"l\", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), \"a\", size, size, 0, 0, 1, size, -size,\n                    \"l\", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, \"a\", size, size, 0, 0, 1, size, size,\n                    \"l\", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), \"a\", size, size, 0, 0, 1, -size, size,\n                    \"l\", -Math.max(w - size, 0), 0, \"z\"].join(\",\"),\n                xy = [{x: X, y: Y + size * 2 + h}, {x: X - size * 2 - w, y: Y}, {x: X, y: Y - size * 2 - h}, {x: X + size * 2 + w, y: Y}][dir];\n            if (withAnimation) {\n                this[0].animate({path: p}, 500, \">\");\n                this[1].animate(xy, 500, \">\");\n            } else {\n                this[0].attr({path: p});\n                this[1].attr(xy);\n            }\n            return this;\n        };\n        return res.update(x, y);\n    };\n    Raphael.fn.g.flag = function (x, y, text, angle) {\n        angle = angle || 0;\n        text = text || \"$9.99\";\n        var res = this.set(),\n            d = 3;\n        res.push(this.path().attr({fill: \"#000\", stroke: \"none\"}));\n        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: \"#fff\"}));\n        res.update = function (x, y) {\n            this.rotate(0, x, y);\n            var bb = this[1].getBBox(),\n                h = bb.height / 2;\n            this[0].attr({path: [\"M\", x, y, \"l\", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0, \"z\"].join(\",\")});\n            this[1].attr({x: x + h + d + bb.width / 2, y: y});\n            angle = 360 - angle;\n            this.rotate(angle, x, y);\n            angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]});\n            return this;\n        };\n        return res.update(x, y);\n    };\n    Raphael.fn.g.label = function (x, y, text) {\n        var res = this.set();\n        res.push(this.rect(x, y, 10, 10).attr({stroke: \"none\", fill: \"#000\"}));\n        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: \"#fff\"}));\n        res.update = function () {\n            var bb = this[1].getBBox(),\n                r = Math.min(bb.width + 10, bb.height + 10) / 2;\n            this[0].attr({x: bb.x - r / 2, y: bb.y - r / 2, width: bb.width + r, height: bb.height + r, r: r});\n        };\n        res.update();\n        return res;\n    };\n    Raphael.fn.g.labelit = function (set) {\n        var bb = set.getBBox(),\n            r = Math.min(20, bb.width + 10, bb.height + 10) / 2;\n        return this.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({stroke: \"none\", fill: \"#000\"}).insertBefore(set[0]);\n    };\n    Raphael.fn.g.drop = function (x, y, text, size, angle) {\n        size = size || 30;\n        angle = angle || 0;\n        var res = this.set();\n        res.push(this.path([\"M\", x, y, \"l\", size, 0, \"A\", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7, \"z\"]).attr({fill: \"#000\", stroke: \"none\", rotation: [22.5 - angle, x, y]}));\n        angle = (angle + 90) * Math.PI / 180;\n        res.push(this.text(x + size * Math.sin(angle), y + size * Math.cos(angle), text).attr(this.g.txtattr).attr({\"font-size\": size * 12 / 30, fill: \"#fff\"}));\n        res.drop = res[0];\n        res.text = res[1];\n        return res;\n    };\n    Raphael.fn.g.blob = function (x, y, text, angle, size) {\n        angle = (+angle + 1 ? angle : 45) + 90;\n        size = size || 12;\n        var rad = Math.PI / 180,\n            fontSize = size * 12 / 12;\n        var res = this.set();\n        res.push(this.path().attr({fill: \"#000\", stroke: \"none\"}));\n        res.push(this.text(x + size * Math.sin((angle) * rad), y + size * Math.cos((angle) * rad) - fontSize / 2, text).attr(this.g.txtattr).attr({\"font-size\": fontSize, fill: \"#fff\"}));\n        res.update = function (X, Y, withAnimation) {\n            X = X || x;\n            Y = Y || y;\n            var bb = this[1].getBBox(),\n                w = Math.max(bb.width + fontSize, size * 25 / 12),\n                h = Math.max(bb.height + fontSize, size * 25 / 12),\n                x2 = X + size * Math.sin((angle - 22.5) * rad),\n                y2 = Y + size * Math.cos((angle - 22.5) * rad),\n                x1 = X + size * Math.sin((angle + 22.5) * rad),\n                y1 = Y + size * Math.cos((angle + 22.5) * rad),\n                dx = (x1 - x2) / 2,\n                dy = (y1 - y2) / 2,\n                rx = w / 2,\n                ry = h / 2,\n                k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)),\n                cx = k * rx * dy / ry + (x1 + x2) / 2,\n                cy = k * -ry * dx / rx + (y1 + y2) / 2;\n            if (withAnimation) {\n                this.animate({x: cx, y: cy, path: [\"M\", x, y, \"L\", x1, y1, \"A\", rx, ry, 0, 1, 1, x2, y2, \"z\"].join(\",\")}, 500, \">\");\n            } else {\n                this.attr({x: cx, y: cy, path: [\"M\", x, y, \"L\", x1, y1, \"A\", rx, ry, 0, 1, 1, x2, y2, \"z\"].join(\",\")});\n            }\n            return this;\n        };\n        res.update(x, y);\n        return res;\n    };\n\n    Raphael.fn.g.colorValue = function (value, total, s, b) {\n        return \"hsb(\" + [Math.min((1 - value / total) * .4, 1), s || .75, b || .75] + \")\";\n    };\n\n    Raphael.fn.g.snapEnds = function (from, to, steps) {\n        var f = from,\n            t = to;\n        if (f == t) {\n            return {from: f, to: t, power: 0};\n        }\n        function round(a) {\n            return Math.abs(a - .5) < .25 ? Math.floor(a) + .5 : Math.round(a);\n        }\n        var d = (t - f) / steps,\n            r = Math.floor(d),\n            R = r,\n            i = 0;\n        if (r) {\n            while (R) {\n                i--;\n                R = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i);\n            }\n            i ++;\n        } else {\n            while (!r) {\n                i = i || 1;\n                r = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i);\n                i++;\n            }\n            i && i--;\n        }\n        var t = round(to * Math.pow(10, i)) / Math.pow(10, i);\n        if (t < to) {\n            t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i);\n        }\n        var f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i);\n        return {from: f, to: t, power: i};\n    };\n    Raphael.fn.g.axis = function (x, y, length, from, to, steps, orientation, labels, type, dashsize) {\n        dashsize = dashsize == null ? 3 : dashsize;\n        type = type || \"t\";\n        steps = steps || 10;\n        var path = type == \"|\" || type == \" \" ? [\"M\", x + .5, y, \"l\", 0, .001] : orientation == 1 || orientation == 3 ? [\"M\", x + .5, y, \"l\", 0, -length] : [\"M\", x, y + .5, \"l\", length, 0],\n            ends = this.g.snapEnds(from, to, steps),\n            f = ends.from,\n            t = ends.to,\n            i = ends.power,\n            j = 0,\n            text = this.set();\n        d = (t - f) / steps;\n        var label = f,\n            rnd = i > 0 ? i : 0;\n            dx = length / steps;\n        if (+orientation == 1 || +orientation == 3) {\n            var Y = y,\n                addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1));\n            while (Y >= y - length) {\n                type != \"-\" && type != \" \" && (path = path.concat([\"M\", x - (type == \"+\" || type == \"|\" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, \"l\", dashsize * 2 + 1, 0]));\n                text.push(this.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({\"text-anchor\": orientation - 1 ? \"start\" : \"end\"}));\n                label += d;\n                Y -= dx;\n            }\n            if (Math.round(Y + dx - (y - length))) {\n                type != \"-\" && type != \" \" && (path = path.concat([\"M\", x - (type == \"+\" || type == \"|\" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, \"l\", dashsize * 2 + 1, 0]));\n                text.push(this.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({\"text-anchor\": orientation - 1 ? \"start\" : \"end\"}));\n            }\n        } else {\n            var X = x,\n                label = f,\n                rnd = i > 0 ? i : 0,\n                addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation),\n                dx = length / steps,\n                txt = 0,\n                prev = 0;\n            while (X <= x + length) {\n\n                text.push(txt = this.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr));\n\t\tvar bb = txt.getBBox();\n\t\tvar ds = dashsize;\n                if (prev >= bb.x - 5) {\n\t\t    text.pop(text.length - 1).remove();\n\t\t    ds = 1;\n                } else {\n                    prev = bb.x + bb.width;\n                }\n\n\t\ttype != \"-\" && type != \" \" && (path = path.concat([\"M\", X + .5, y - (type == \"+\" ? ds : !!orientation * ds * 2), \"l\", 0, ds * 2 + 1]));\n                \n                label += d;\n                X += dx;\n            }\n            if (Math.round(X - dx - x - length)) {\n                type != \"-\" && type != \" \" && (path = path.concat([\"M\", x + length + .5, y - (type == \"+\" ? dashsize : !!orientation * dashsize * 2), \"l\", 0, dashsize * 2 + 1]));\n                text.push(this.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr));\n            }\n        }\n        var res = this.path(path);\n        res.text = text;\n        res.all = this.set([res, text]);\n        res.remove = function () {\n            this.text.remove();\n            this.constructor.prototype.remove.call(this);\n        };\n        return res;\n    };\n\n    Raphael.el.lighter = function (times) {\n        times = times || 2;\n        var fs = [this.attrs.fill, this.attrs.stroke];\n        this.fs = this.fs || [fs[0], fs[1]];\n        fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);\n        fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);\n        fs[0].b = Math.min(fs[0].b * times, 1);\n        fs[0].s = fs[0].s / times;\n        fs[1].b = Math.min(fs[1].b * times, 1);\n        fs[1].s = fs[1].s / times;\n        this.attr({fill: \"hsb(\" + [fs[0].h, fs[0].s, fs[0].b] + \")\", stroke: \"hsb(\" + [fs[1].h, fs[1].s, fs[1].b] + \")\"});\n    };\n    Raphael.el.darker = function (times) {\n        times = times || 2;\n        var fs = [this.attrs.fill, this.attrs.stroke];\n        this.fs = this.fs || [fs[0], fs[1]];\n        fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);\n        fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);\n        fs[0].s = Math.min(fs[0].s * times, 1);\n        fs[0].b = fs[0].b / times;\n        fs[1].s = Math.min(fs[1].s * times, 1);\n        fs[1].b = fs[1].b / times;\n        this.attr({fill: \"hsb(\" + [fs[0].h, fs[0].s, fs[0].b] + \")\", stroke: \"hsb(\" + [fs[1].h, fs[1].s, fs[1].b] + \")\"});\n    };\n    Raphael.el.original = function () {\n        if (this.fs) {\n            this.attr({fill: this.fs[0], stroke: this.fs[1]});\n            delete this.fs;\n        }\n    };\n})();"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.css",
    "content": "/*\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n*/\nbody { font-family: sans-serif; }\n\ndiv.fileSelector { border: solid 3px black; position: absolute; background: white; \n\t\t   -moz-border-radius: 10px; border-radius: 10px; \n\t\t   padding: 5px; font-family: sans-serif;\n\t\t   right: 10px; top: 10px;\n\t\t }\ndiv.fileSelector a { cursor: pointer; }\n.fileSelector li.selectedFile { background: lightgreen; }\n\ndiv.selector { border: solid 3px black; position: absolute; background: white; \n\t\t   -moz-border-radius: 10px; border-radius: 10px; \n\t\t   padding: 5px; \n\t\t   right: 10px; top: 10px; background: #aaaaaa; opacity: 0.7;\n\t\t }\ndiv.selector a { cursor: pointer; }\n.fileSelector li.selectedFile { background: lightgreen; }\n\n#fileLoader  { -moz-border-radius: 10px; border-radius: 10px; background: #aaaaaa; opacity: 0.7; position: absolute; left: 20px; top: 20px; }\n#loadingScreen { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; text-align: center }\n#filterinput { width: 500px; height: 100px; }\n/* main interface */\n#actions { float: right; }\n#views { float: left; }\n\n.closebutton { position: absolute; right: 5px; float: right; display: block; cursor: pointer; }\n\n.actionbutton { color: blue; text-decoration: none; padding: 3px; cursor: pointer; }\nspan:hover.actionbutton { background: lightblue;  }\n\n#status { text-align: center; }\n\n#canvas { width: 100%; height: 1000px; }\n\n#logtable { width: 100%; }\n.popUp { border: 3px solid black; -moz-border-radius: 10px; border-radius: 10px; position: absolute; background: white; padding: 10px; min-width: 300px; }\n\n.errorpage { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; padding: 10px; }"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nLogGraph = function(canvas, status) {\n    this.canvas = document.getElementById(canvas);\n    this.status = document.getElementById(status);\n    this.starttime = 0;\n    this.endtime = 0;\n    this.period = 0;\n    this.numEntries = 0;\n    this.currentRender = 0;\n    this.filter = \"\";\n\n    this.saveFilters = function () {\n\tlocalStorage.starttime = this.starttime;\n\tlocalStorage.endtime = this.endtime;\n\tlocalStorage.period = this.period;\n\tlocalStorage.filter = this.filter;\n\t\n    };\n    this.loadFilters = function () {\n\tif (localStorage.starttime) { this.starttime = parseInt(localStorage.starttime); }\n\tif (localStorage.endtime) { this.endtime = parseInt(localStorage.endtime); }\n\tif (localStorage.period) { this.period = parseInt(localStorage.period); }\n\tif (localStorage.filter) { this.filter = localStorage.filter; }\n    };\n    this.loadFilters();\n    var self = this;\n\n    var updateStatus = function (starttime, period, filter, numEntries) {\n\tself.starttime = starttime;\n\tself.endtime = starttime + period;\n\tself.period = period;\n\tself.filter = filter;\n\tself.saveFilters(); \n       \n\tself.status.innerHTML = dateFormat(starttime, \"HH:MM:ss,l\") + \" &rArr; \" + dateFormat(self.endtime, \"HH:MM:ss,l\") + \" &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; \" + numEntries + \" entries  &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; \" +  (filter ? filter : \"No filter\");\n\t\n\tif (self.currentRender) {\n\t    self.currentRender();\n\t}\n    };\n\t\n    YUI().use(\"io-base\", function(Y) {\n\t    var uri = \"/info\";\n\t    if (self.starttime) {\n\t\tvar uri = \"/info?start=\" + self.starttime + \"&period=\" + self.period + \"&filter=\" + self.filter;\n\t    }\n\t    \n\t    function complete(id, o, args) {\n\t\tvar data = eval(\"(\" + o.responseText + \")\"); // Response data.\n\t\tvar period = data.endTime - data.startTime;\n\t\tupdateStatus(data.startTime, period, self.filter, data.numEntries);\n\t    };\n\t    \n\t    Y.on('io:complete', complete, Y, []);\n\t    var request = Y.io(uri);\n\t});\n    \n    this.addLogs = function() {\n\tnew LogGraph.fileSelector(function (files) { new LogGraph.fileLoader(files); });\n    };\n\n    this.editFilters = function() {\n\tnew LogGraph.filterSelector(this.starttime, this.period, this.filter, updateStatus);\n    };\t\n\t\n    this.getCleanCanvas = function () {\n\tthis.canvas.innerHTML = \"\";\n\treturn this.canvas;\n    };\n\n    this.showLoadingScreen = function () {\n\tthis.loadingScreen = document.createElement(\"div\");\n\tthis.loadingScreen.id = \"loadingScreen\";\n\tthis.loadingScreen.innerHTML = \"<img src=\\\"load-big.gif\\\" /> <p>Loading...</p>\";\n\tdocument.body.appendChild(this.loadingScreen);\n    };\n\n    this.hideLoadingScreen = function () {\n\tdocument.body.removeChild(this.loadingScreen);\n\tthis.loadingScreen.style.visibility = \"hidden\";\n    };\n\n\n    /***\n     * TODO: refactor these to load the data first, before handing to a draw funciton. \n     *       We shouldn't pass the async q into the drawing function\n     */\n    this.showLogs = function() {\n\tvar self= this;\n\tYUI().use('async-queue', function(Y) {\n\t\tvar q = new Y.AsyncQueue(self.showLoadingScreen,\n\t\t\t\t\t // The second callback will pause the Queue and send an XHR for data\n\t\t\t\t\t function () {\n\t\t\t\t\t     q.pause();\n\t\t\t\t\t     var loggraph = new LogGraph.LogTable(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);\n\t\t\t\t\t     self.currentRender = self.showLogs;\n\t\t\t\t\t },\n\t\t\t\t\t self.hideLoadingScreen);\n\t\tq.run();\n\t    }\n\t    );\n    };\n\n    this.serverGraph = function() {\n\tvar self= this;\n\tYUI().use('async-queue', function(Y) {\n\t\tvar q = new Y.AsyncQueue(self.showLoadingScreen,\n\t\t\t\t\t // The second callback will pause the Queue and send an XHR for data\n\t\t\t\t\t function () {\n\t\t\t\t\t     q.pause();\n\t\t\t\t\t     var servergraph = new LogGraph.ServerGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);\n\t\t\t\t\t     self.currentRender = self.showLogs;\n\t\t\t\t\t },\n\t\t\t\t\t self.hideLoadingScreen);\n\t\tq.run();\n\t    }\n\t    );\n    };\n    \n    this.sessionGraph = function() {\n\tvar self= this;\n\tYUI().use('async-queue', function(Y) {\n\t\tvar q = new Y.AsyncQueue(self.showLoadingScreen,\n\t\t\t\t\t // The second callback will pause the Queue and send an XHR for data\n\t\t\t\t\t function () {\n\t\t\t\t\t     q.pause();\n\t\t\t\t\t     var sessiongraph = new LogGraph.SessionGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);\n\t\t\t\t\t     self.currentRender = self.sessionGraph;\n\t\t\t\t\t },\n\t\t\t\t\t self.hideLoadingScreen);\n\t\tq.run();\n\t    }\n\t    );\n    };\n    \n    this.showStats = function() {\n\tvar self= this;\n\tYUI().use('async-queue', function(Y) {\n\t\tvar q = new Y.AsyncQueue(self.showLoadingScreen,\n\t\t\t\t\t // The second callback will pause the Queue and send an XHR for data\n\t\t\t\t\t function () {\n\t\t\t\t\t     q.pause();\n\t\t\t\t\t     var statgraph = new LogGraph.StatsGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);\n\t\t\t\t\t     self.currentRender = self.showStats;\n\t\t\t\t\t },\n\t\t\t\t\t self.hideLoadingScreen);\n\t\tq.run();\n\t    }\n\t    );\n    };\n};\n\nLogGraph.error = function(description) {\n    var errorPage = document.createElement(\"div\");\n    errorPage.className = \"errorpage\";\n    var p = document.createElement(\"p\");\n    p.innerHTML = description;\n    errorPage.appendChild(p);\n    \n    var span = document.createElement(\"span\");\n    p = document.createElement(\"p\");\n    span.className = \"actionButton\";\n    span.innerHTML = \"OK\";\n    span.onclick = function (evt) {\n\tdocument.body.removeChild(errorPage);\n\tdelete errorPage;\n    }\n    p.appendChild(span);\n    errorPage.appendChild(p);\n\n    document.body.appendChild(errorPage);\n};\n\nLogGraph.ticker =function(allow_dups) {\n    this.ticks = new Array();\n    this.current_tick = 0;\n    this.allow_dups = allow_dups;;\n    \n    this.tick = function(time) {\n\tif (time == this.ticks[this.ticks.length - 1] && this.allow_dups == true) \n\t    return this.current_tick;\n\t\n\tthis.ticks.push(time);\n\treturn this.current_tick++;\n    };\n    \n    this.current = function() {\n\treturn this.current_tick;\n    };\n    \n    this.reset = function() {\n\twhile (this.ticks.length) {\n\t    this.ticks.pop();\n\t}\n\tthis.current_tick = 0;\n    };\n};\n\n\nLogGraph.timescale = function(starttime, endtime) {\n    this.starttime = starttime;\n    this.endtime = endtime;\n    this.millis = endtime - starttime;\n    \n    this.draw = function(paper) {\n\tvar scale = paper.set();\n\tscale.push(paper.path(\"M0 0 L\" + paper.width + \" 0\"));\n\t\n\tfor (var i = 0; i < paper.width; i += 100) {\n\t    scale.push(paper.path(\"M\" + i + \" 0 L\" + i + \" 5\"));\n\t    //\t\tvar time = dateFormat((this.starttime + (i*ms_per_pixel)), \"h:MM:ss,l\");\n\t\t//\tpaper.text(i + 5, 10, time);\n\t}\n\t\n\tscale.attr({\"stroke-width\": 2});\n    };\n};\n\n/*\n  Fetch data from an uri and process it, the process data func returns true if any of the data is useful  \n*/\nLogGraph.loadData = function (asyncq, uri, processdata) {\n    YUI().use(\"io-base\", function(Y) {\n\t    function success(id, o, args) {\n\t\tvar data = eval(\"(\" + o.responseText + \")\"); // Response data.\n\t\tif (data.error) {\n\t\t    LogGraph.error(data.error);\n\t\t} else {\n\t\t    if (!processdata(data)) {\n\t\t\tLogGraph.error(\"No data. Perhaps you should loosen your filter criteria.\");\n\t\t    }\n\t\t}\n\t\tasyncq.run();\n\t    };\n\t    function failure(id, o, args) {\n\t\tLogGraph.error(\"Error contacting server: (\" + o.status + \") \" + o.statusText);\n\t\tasyncq.run();\n\t    };\n\n\t    Y.on('io:success', success, Y, []);\n\t    Y.on('io:failure', failure, Y, []);\n\t    \n\t    var request = Y.io(uri);\n\t});\n}"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.log.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nLogGraph.LogTable = function (asyncq, canvas, starttime, endtime, filter) {\n    this.starttime = starttime;\n    this.endtime = endtime;\n    this.filter = filter;\n\n    var table = document.createElement(\"table\");\n    table.id = \"logtable\";\n    canvas.appendChild(table);\n\n    this.addLogLine = function(time, text) {\n\tvar tr = document.createElement(\"tr\");\n\ttable.appendChild(tr);\n\t\n\tvar td = document.createElement(\"td\");\n\ttd.innerHTML = dateFormat(time, \"h:MM:ss,l\");\n\ttr.appendChild(td);\n\n\ttd = document.createElement(\"td\");\n\ttd.innerHTML = text;\n\ttr.appendChild(td);\n    }\n\n    var self = this;\n    var processdata = function(data) {\n\tvar events = data[\"events\"];\n\tvar count = 0;\n\tfor (var i in events) {\n\t    var e = events[i];\n\t    if (e.type == \"text\") {\n\t\tself.addLogLine(e.time, e.text);\n\t\tcount++;\n\t    }\n\t}\n\treturn count != 0;\n    };\n\n    var uri = \"/data?start=\" + self.starttime + \"&end=\" + self.endtime + \"&filter=\" + self.filter; \n    LogGraph.loadData(asyncq, uri, processdata);\n};\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.server.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nLogGraph.ServerGraph = function(asyncq, canvas, starttime, endtime, filter) {\n    this.starttime = starttime;\n    this.endtime = endtime;\n    this.millis = endtime - starttime;\n    this.nextserverid = 0;\n    this.serveroffset = 100;\n    this.filter = filter;\n    \n    this.pixels_per_tick =  20;\n    this.ticker = new LogGraph.ticker();\n\n    \n    var paper = Raphael(canvas, 1, 1);\n\n    var self = this;\n\n    this.timescale = new LogGraph.timescale(starttime, endtime);\n    this.objects = new Array();\n    \n    this.add = function(obj) {\n\tthis.objects.push(obj);\n    }\n    \n    this.tick_to_x = function (timestamp) {\n\tvar x = timestamp * this.pixels_per_tick; \n\treturn x;\n    }; \n    \n    this._drawTime  = function(paper, x, time) {\n\tvar p = paper.path(\"M\" + x + \" 0 L\" + x + \" \" + paper.height);\n\tvar t = paper.text(x, 10, dateFormat(time, \"h:MM:ss,l\"));\n\t\n\tt.hide();\n\tp.mouseover(function(evt) {\n\t\tt.show();\n\t\tp.attr({stroke: \"red\"});\n\t    });\n\tp.mouseout(function(evt) {\n\t\tt.hide();\n\t\tp.attr({stroke: \"lightgray\"});\n\t    });\n\t\n\treturn p;\n    };\n    \n    this.draw = function(paper) {\n\tvar grid = paper.set();\n\tfor (var i = 0; i < paper.height; i += 20) {\n\t    grid.push(paper.path(\"M0 \" + i + \" L\" + paper.width + \" \" + i));\n\t}\n\tvar lasttick = this.starttime;\n\tvar scale = 500; // 500 ms\n\t\n\tvar y = 0;\n\t\n\tfor (var t = 0, len = this.ticker.ticks.length; t < len; t++) {\n\t    var basex = t * this.pixels_per_tick;\n\t    var thistick = this.ticker.ticks[t];\n\t    var nexttick = t + 1 == this.ticker.ticks.length ? this.endtime : this.ticker.ticks[t+1];\n\t    if (nexttick == thistick) {\n\t\tcontinue;\n\t    }\n\t    var time = thistick - lasttick;\n\t    var first = scale - (lasttick % scale);\n\t    \n\t    /*\t\tfor (var i = 0; (first+scale*i) < time; i++) {\n\t\t\t\n\t\t\tvar toffset = first+scale*i;\n\t\t\tvar x = basex + LogGraph._pixels_per_tick * toffset/time;\n\t\t\tgrid.push(this._drawTime(paper, x, lasttick + toffset, grid));\n\t\t\t\n\t\t\t}*/\n\t    \n\t    \n\t    //grid.push(paper.path(\"M\" + i + \" 0 L\" + i + \" \" + paper.height));\n\t    lasttick = thistick;\n\t}\n\tgrid.attr({stroke: \"lightgray\"});\n\tthis.timescale.draw(paper);\n\t\n\tfor (o in this.objects) {\n\t    this.objects[o].draw(paper);\n\t}\n    };\n\n\n    var processdata = function(data) {\n\tvar servermap = {};\n\tvar servers = data.servers;\n\tvar count = 0;\n\tfor (s in servers) {\n\t    var server = new LogGraph.ServerGraph.server(self, \"Server \" + servers[s]);\n\t    servermap[servers[s]] = server;\n\t    self.add(server);\n\t    count++;\n\t}\n\t\n\tvar messages = {};\n\tvar events = data.events;\n\tfor (var i in events) {\n\t    var e = events[i];\n\t    var t = e.time;\n\t    if (e.type == \"stateChange\") {\n\t\tservermap[e.server].addState(e.state, self.ticker.tick(e.time));\n\t    }\n\t    if (e.type == \"postmessage\") {\n\t\tsrc = servermap[e.src];\n\t\tdst = servermap[e.dst];\n\t\tvar key = \"key:s\" + e.src + \",d\" + e.dst + \",z\" + e.zxid;\n\t\t    \n\t\tvar m = new LogGraph.ServerGraph.message(self, src, self.ticker.tick(e.time), dst, e.zxid);\n\t\tmessages[key] = m;\n\t    } \n\t    if (e.type == \"delivermessage\") {\n\t\tvar key = \"key:s\" + e.src + \",d\" + e.dst + \",z\" + e.zxid;\n\t\t\n\t\tvar m = messages[key];\n\t\tif (m) {\n\t\t    m.dsttime = self.ticker.tick(e.time);\n\t\t    m.name = \"Propose\";\n\t\t    self.add(m);\n\t\t    delete messages[key];\n\t\t}\n\t    } \n\t    if (e.type == \"exception\") {\n\t\tservermap[e.server].addException(self.ticker.tick(e.time), e.text, e.time);\n\t    }\n\t    count++;\n\t}\n\t\n\tfor (var i in messages) {\n\t    var m = messages[i];\n\t    m.markIncomplete();\n\t    self.add(m);\n\t    count++;\n\t}\n\n\tif (count != 0) {\n\t    paper.setSize(self.tick_to_x(self.ticker.current()), 1000);\t    \n\t    \n\t    var line = paper.path(\"M0 0 L0 1000\");\t    \n\t    line.attr({\"stroke\": \"red\", \"stroke-dasharray\": \"- \"});\n\t    var base = canvas.offsetLeft;// + ((canvas.offsetWidth - paper.width)/2);\n\t    canvas.onmousemove = function (evt) {\n\t\tvar x = evt.screenX - base;\n\t\t\n\t\tline.attr({\"path\": \"M\" + x + \" 0 L\"+ x +\" 1000\"});\n\t\t\n\t    };\n\n\t    self.draw(paper);\n\t    return true;\n\t} else {\n\t    return false;\n\t}\n    };\n\t\t\n    var uri = \"/data?start=\" + self.starttime + \"&end=\" + self.endtime + \"&filter=\" + filter;\n\n    LogGraph.loadData(asyncq, uri, processdata);    \n};\n\nLogGraph.ServerGraph.server = function (graph, name) {\n    this.graph = graph;\n    this.serverid = graph.nextserverid++;\n    this.name = name;\n    this.y = (this.serverid * 300 + graph.serveroffset);\n    this.states = new Array();\n    this.exception = new Array();\n    \n    this.addState = function(state, time) {\n\tthis.states.push([state, time]);\n    }\n    \n    this.addException = function(tick, exception, time) {\n\tthis.exception.push(new LogGraph.ServerGraph.exception(this.graph, tick, exception, time));\n    }\n    \n    this.draw = function(paper) {\n\tvar st = paper.set();\n\tst.push(paper.path(\"M0 \" + this.y + \" L\" + paper.width + \" \" + this.y));\n\tst.push(paper.text(20, this.y - 10, this.name));\n\tst.attr({stroke: \"gray\"});\n\t\n\tvar numstates = this.states.length;\n\t\n\tfor (s = 0; s < numstates; s++) {\n\t    var style = {};\n\t    switch (this.states[s][0]) {\n\t    case \"INIT\": style = {stroke: \"yellow\", \"stroke-width\":3}; break;\n\t    case \"FOLLOWING\": style = {stroke: \"lightgreen\", \"stroke-width\":7}; break;\n\t    case \"LEADING\": style = {stroke: \"green\", \"stroke-width\":10}; break;\n\t    case \"LOOKING\": style = {stroke: \"orange\", \"stroke-width\":5}; break;\n\t    }\n\t    var startx = this.graph.tick_to_x(this.states[s][1]);\n\t    var endx = s + 1 < numstates ? this.graph.tick_to_x(this.states[(s+1)][1]) : paper.width;\n\t    var p = paper.path(\"M\" + startx + \" \" + this.y + \" L\" + endx + \" \" + this.y);\n\t    p.attr(style);\n\t}\n\t\n\tfor (e in this.exception) {\n\t    this.exception[e].draw(paper, this);\n\t}\n    }\n};    \n    \nLogGraph.ServerGraph.message = function(graph, src, srctime, dst, zxid) {\n    this.graph = graph;\n    this.src = src;\n    this.srctime = srctime;\n    this.dst = dst;\n    this.dsttime = 0; //dsttime;\n    this.name = \"Unknown\";\n    this.zxid = zxid;\n    this.moreinfo = \"No extra information\";\n    this.incomplete = false;\n    \n    this.markIncomplete = function() {\n\tthis.incomplete = true;\n\tthis.dsttime = this.srctime;\n    }\n\n    this.draw = function(paper) {\n\tvar srcx = this.graph.tick_to_x(this.srctime);\n\tvar dstx = this.graph.tick_to_x(this.dsttime);\n\t\n\tvar arrow = paper.set();\n\tvar p = paper.path(\"M\" + srcx + \" \" + this.src.y + \" L\" + dstx + \" \" + this.dst.y);\n\tarrow.push(p);\n\t\n\tvar tx = (srcx + dstx)/2;\n\tvar ty = (this.src.y + this.dst.y)/2;\n\tvar t = paper.text(tx, ty, this.name);\n\t\n\tvar gradiant = (this.dst.y - this.src.y)/(dstx - srcx);\n\tvar angle = Math.atan(gradiant) * 57.2958;\n\tt.rotate(angle, true);\n\t\n\tvar arrowl = paper.path(\"M\" + dstx + \" \" + this.dst.y + \" L\" + (dstx - 10) +\" \" + this.dst.y);\n\tarrowl.rotate(angle + 20, dstx, this.dst.y);\n\tarrow.push(arrowl);\n\tvar arrowr = paper.path(\"M\" + dstx + \" \" + this.dst.y + \" L\" + (dstx - 10) +\" \" + this.dst.y);\n\tarrowr.rotate(angle - 20, dstx, this.dst.y);\n\tarrow.push(arrowr);\n\t\n\tarrow.attr({\"stroke-width\": 2, stroke: \"gray\"});\n\tif (this.incomplete) {\n\t    arrow.attr({\"stroke-dasharray\": \"- .\", stroke: \"pink\", \"stroke-width\": 2});\n\t}\n\tarrow.mouseover(function(evt) {\n\t\tt.attr({\"font-size\": 20});\n\t\tarrow.attr({stroke: \"red\", \"stroke-width\": 3});\n\t    });\n\tarrow.mouseout(function(evt) {\n\t\tt.attr({\"font-size\": 10});\n\t\t\n\t\tif (this.incomplete) {\n\t\t    arrow.attr({stroke: \"pink\", \"stroke-width\": 2});\n\t\t} else {\n\t\t    arrow.attr({stroke: \"gray\", \"stroke-width\": 2});\n\t\t}\n\t    });\n\t\n\t\n\n\tarrow.click(function(evt) { \n\t\tvar popup = document.createElement(\"div\");\n\t\tpopup.className = \"popUp\";\n\t\tpopup.innerHTML = \"zxid: \" + parseInt(this.zxid).toString(16);\n\n\t\tpopup.style.top = evt.clientY;\n\t\tpopup.style.left = evt.clientX;\n\t\tdocument.body.appendChild(popup);\n\n\t\tpopup.onclick = function(evt) { \n\t\t    document.body.removeChild(popup);\n\t\t};\n\t    });\n    }\n};\n    \nLogGraph.ServerGraph.exception = function(graph, tick, exceptiontext, time) {\n    this.graph = graph;\n    this.time = time;\n    this.text = exceptiontext;\n    this.tick = tick;\n    \n    var self = this;\n\n    this.draw = function(paper, server) {\n\tvar center = this.graph.tick_to_x(this.tick);\n\tvar p = paper.circle(center, server.y, 5);\n\tp.attr({stroke: \"orange\", fill: \"red\"});\n\t\n\tp.mouseover(function(evt) {\n\t\tp.popup = document.createElement(\"div\");\n\t\tp.popup.className = \"popUp\";\n\t\tp.popup.innerHTML = self.text.replace(\"\\n\", \"<br/>\");;\n\t\tp.popup.style.top = server.y + 50;\n\t\tp.popup.style.left = center + 25;\n\t\tdocument.body.appendChild(p.popup);\n\n\t\tp.animate({r: 10}, 500, \"elastic\");\n\t    });\n\tp.mouseout(function(evt) {\n\t\tdocument.body.removeChild(p.popup);\n\t\tp.animate({r: 5}, 100);\n\t    });\n    }\n};\n    \n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.session.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nLogGraph.SessionGraph = function (asyncq, canvas, starttime, endtime, filter) {\n    this.sessions = new Array();\n    this.counter = 0;\n    this.exceptions = new Array();\n    \n    this.pix_per_ticks = 4;\n    this.pix_per_session = 7;\n\n    var paper = Raphael(canvas, 1, 1);\n    this.ticker = new LogGraph.ticker();\n    var self = this;\n\n    this.starttime = starttime;\n    this.endtime = endtime;\n    this.filter = filter;\n\n    this.findOrCreateSession = function(id) {\n\tif (this.sessions[id] == undefined) {\n\t    this.sessions[id] = new LogGraph.SessionGraph.session(this, ++this.counter, id);\n\t}\n\treturn this.sessions[id];\n    }\n    \n    this.height = function () { return this.counter * this.pix_per_session + 10; };\n    this.width = function () { return (self.ticker.current() * this.pix_per_ticks); };\n\n    this.draw = function(paper) {\n\t\n\n\tvar line = paper.path(\"M0 0 L0 \" + this.height());\t    \n\tline.attr({\"stroke\": \"red\", \"stroke-dasharray\": \"- \"});\n\tvar base = canvas.offsetLeft;\n\tvar width = this.width();\n\tcanvas.onmousemove = function (evt) {\n\t    var x = evt.clientX - base;\n\n\t    line.attr({\"path\": \"M\" + x + \" 0 L\" + x + \" \" + self.height() });\n\t};\t\n\t\n\tfor (var i in this.sessions) {\n\t    var s = this.sessions[i];\n\t    s.draw(paper);\n\t}\n    };\n\n    var processdata = function(data) {\n\tvar count = 0;\n\tfor (var i in data.events) {\n\t    var e = data.events[i];\n\t    if (e.type == \"transaction\") {\n\t\te.tick = self.ticker.tick(e.time, true);\n\t\tvar session = self.findOrCreateSession(e.client);\n\t\tsession.addEvent(e);\n\t\tcount++;\n\t    }\n\t}\n\tpaper.setSize(self.width(), self.height());\n\t\n\tif (count != 0) {\n\t    self.draw(paper);\n\t    return true;\n\t} else {\n\t    return false;\n\t}\n    };\n    \n    var uri = \"/data?start=\" + self.starttime + \"&end=\" + self.endtime + \"&filter=\" + filter;\n\n    LogGraph.loadData(asyncq, uri, processdata);    \n};\n\nLogGraph.SessionGraph.sessionevent = function () {\n    this.time = time;\n    this.type = type;\n    this.client = client;\n    this.cxid = cxid;\n    this.zxid = zxid;\n    this.op = op;\n    this.extra = extra;\n};\n\nLogGraph.SessionGraph.sessionEventPopup = function (obj, e, x, y) {\n    obj.click(function(evt) {\n\t    var popup = document.createElement(\"div\");\n\t    popup.className = \"popUp\";\n\n\t    var closebutton = document.createElement(\"div\");\n\t    closebutton.className = \"closebutton\";\n\t    closebutton.title = \"Close popup\";\n\t    closebutton.innerHTML = \"&times;\";\n\t    popup.appendChild(closebutton);\n\t    closebutton.onclick= function(evt) { popup.style.visibility = \"hidden\"; document.body.removeChild(popup) };\n\t    var txt = document.createElement(\"span\");\n\t    txt.innerHTML = \"session: \" + e.client + \"<br/>op: \" + e.op + \"<br/>zxid: \" + e.zxid + \"<br/>time: \" + e.time + \"<br/>extra: \" + e.extra;\n\t    popup.appendChild(txt);\n\t    \n\t    popup.style.top = y;\n\t    popup.style.left = x;\n\t    document.body.appendChild(popup);\n\t    \n\t    YUI().use('dd-drag', function(Y) {\n\t\t    //Selector of the node to make draggable\n\t\t    var dd = new Y.DD.Drag({\n\t\t\t    node: popup\n\t\t\t});   \n\t\t});\n\t});\n};\n    \nLogGraph.SessionGraph.session = function (graph, index, id) {\n    this.index = index;\n    this.id = id;\n    this.graph = graph;\n    \n    this.events = new Array();\n    this.starttick = 0;\n    this.endtick = undefined;\n    \n    this.addEvent = function(e) {\n\tthis.events.push(e);\n\t\n\tif (e.op == \"createSession\") {\n\t    //\t\tdocument.write(\"createSession for \" + id.toString(16));\n\t    this.starttick = e.tick;\n\t} else if (e.op == \"closeSession\") {\n\t    this.endtick = e.tick;\n\t}\n    },\n    \n    this._attach_action = function (sess, label) {\n\tsess.mouseover(function(evt) {\n\t\tlabel.show();\n\t\tsess.attr({stroke: \"gray\"});\n\t    });\n\t\n\tsess.mouseout(function(evt) {\n\t\tlabel.hide();\n\t\tsess.attr({stroke: \"black\"});\n\t    });\n    },\n    \n    this.drawEvent = function (paper, y, e) {\n\tvar x = e.tick * this.graph.pix_per_ticks;;\n\tvar s = paper.path(\"M\" + x + \" \" + (y - 3) + \" L\" + x + \" \" + (y + 3));\n\ts.attr({\"stroke-width\": 2});\n\tif (e.op == \"error\") {\n\t    s.attr({\"stroke\": \"red\"});\n\t} \n\ts.mouseover(function(evt) {\n\t\ts.attr({\"stroke-width\": 5});\n\t    });\n\t\n\ts.mouseout(function(evt) {\n\t\ts.attr({\"stroke-width\": 2});\n\t    });\n\t\n\tLogGraph.SessionGraph.sessionEventPopup(s, e, x, y);\n    },\n    \n    this.draw = function(paper) {\n\tvar y = this.index*this.graph.pix_per_session;;\n\tvar start = this.starttick * this.graph.pix_per_ticks;\n\tvar end = this.endtick * this.graph.pix_per_ticks;\n\t\n\tvar sess = paper.set();\n\t\n\tif (this.endtick == undefined) {\n\t    end = this.graph.width();\n\t} \n\n\tsess.push(paper.path(\"M\" + start + \" \" + y + \" L\" + end + \" \" + y));\n\tfor (var i in this.events) {\n\t    var e = this.events[i];\n\t    this.drawEvent(paper, y, e);\n\t}\n\t\n\t//sess.attr({\"stroke-width\": 3});\n\tlabel = paper.text(start + 100, y, this.id);\n\tlabel.attr({\"font-size\": \"14px\"});\n\tlabel.hide();\n\tthis._attach_action(sess, label);\n    }\n};\n\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.stats.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nLogGraph.StatsGraph = function (asyncq, canvas, starttime, endtime, filter) {\n    var processdata = function(data) {\n\tvar r = Raphael(canvas);\n\tvar x = data.map(function (x) { return x.time; });\n\tvar y = data.map(function (x) { return x.count; });\n\tvar xlabels = data.map(function (x) { return dateFormat(x.time, \"HH:MM:ss,l\"); } );\n\tvar h1 = function () {\n\t    this.tags = r.set();\n\t    for (var i = 0, ii = this.y.length; i < ii; i++) {\n\t\tthis.tags.push(r.g.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{fill: \"#fff\"}, {fill: this.symbols[i].attr(\"fill\")}]));\n\t    }\n\t};\n\tvar h2 = function () {\n\t    this.tags && this.tags.remove();\n\t};\n\tr.g.linechart(40, 40, 1000, 500,  x, y, {shade: true, axis: \"0 0 1 1\", symbol: \"x\", southlabels: xlabels, axisxstep: xlabels.length - 1 , westAxisLabel: \"Write requests\", southAxisLabel: \"Time (min)\"}).hoverColumn(h1, h2);\n\n\treturn true;\n\t//r.g.barchart(0, 0, 1000, 100,  y, {shade: true, symbol: \"x\"}).hoverColumn(h1, h2);\n    };\n    \n    var uri = \"/throughput?scale=minutes\";\n    LogGraph.loadData(asyncq, uri, processdata);    \n};\n\n    \n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.ui.js",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Opens a window to load files into the engine\nLogGraph.fileSelector = function(callback) {\n    var self = this;\t\n    this.callback = callback;\n    this.selectedFiles = new Array();\n    \n    var divTag = document.createElement(\"div\");\n    divTag.id = \"fileSelector\" + Math.round(Math.random()*100000);\n    //\tdivTag.className = \"popUp\";\n    divTag.className = \"selector fileSelector\";\n    document.body.appendChild(divTag);\n    \n    YUI().use('dd-drag', function(Y) {\n\t    //Selector of the node to make draggable\n\t    var dd = new Y.DD.Drag({\n\t\t\tnode: '#' + divTag.id\n\t\t});   \n\t});\n    \n    var list = document.createElement(\"ul\");\n    divTag.appendChild(list);\n    var selectedList = document.createElement(\"selectedlist\");\n    divTag.appendChild(selectedList);\n    \n    var clearanchor = document.createElement(\"span\");\n    clearanchor.innerHTML = \"Remove All\";\n    clearanchor.className = \"actionbutton\";\n    clearanchor.style.cssFloat = \"right\";\n    clearanchor.onclick = function () {\n\tself.selectedFiles = new Array();\n\tself.updateSelectedList();\n    };\n    divTag.appendChild(clearanchor);\n    \n    var doneanchor = document.createElement(\"span\");\n    doneanchor.innerHTML = \"Process Files\";\n    doneanchor.className = \"actionbutton\";\n    doneanchor.style.cssFloat = \"left\";\n    doneanchor.onclick = function () {\n\tself.callback(self.selectedFiles);\n\tdocument.body.removeChild(divTag);\n\tdelete divTag;\n    };\n    divTag.appendChild(doneanchor);\n    \n    var cancelanchor = document.createElement(\"span\");\n    cancelanchor.innerHTML = \"Cancel\";\n    cancelanchor.className = \"actionbutton\";\n    cancelanchor.style.cssFloat = \"left\";\n    cancelanchor.onclick = function () {\n\tdocument.body.removeChild(divTag);\n\tdelete divTag;\n    };\n    divTag.appendChild(cancelanchor);\n    \n    this.createFileListItem = function (file) {\n\tvar li = document.createElement(\"li\");\n\tvar a = document.createElement(\"a\");\n\tif (file.type == \"D\") {\n\t    a.innerHTML = file.file + \"/\";\n\t    a.onclick = function () { self.updateList(file.path); };\n\t} else {\n\t    a.innerHTML = file.file;\n\t    a.onclick = function () { self.addSelectedFile(file.path); };\n\t}\n\t\n\ta.fullpath = file.path;;\n\tli.appendChild(a);\n\treturn li;\n    };\n    \n    this.addSelectedFile = function (file) {\n\tif (this.selectedFiles.indexOf(file) == -1) {\n\t    this.selectedFiles.push(file);\n\t    this.updateSelectedList();\n\t}\n    };\n    \n    this.removeSelectedFile = function (file) {\n\tthis.selectedFiles = this.selectedFiles.filter(function(f) { return !(file == f); });\n\tthis.updateSelectedList();\n    };\n    \n    this.createSelectedListItem = function (file) {\n\tvar li = document.createElement(\"li\");\n\tvar a = document.createElement(\"a\");\n\tli.className = \"selectedFile\";\n\ta.onclick = function () { self.removeSelectedFile(file); };\n\ta.innerHTML = file;\n\tli.appendChild(a);\n\treturn li;\n    };\n    \n    this.updateSelectedList = function () {\n\twhile (selectedList.firstChild) { selectedList.removeChild(selectedList.firstChild); }\n\t\n\tfor (var i in this.selectedFiles) {\n\t    var f = this.selectedFiles[i];\n\t    selectedList.appendChild(this.createSelectedListItem(f));\n\t}\n    };\n    \n    this.updateList = function (base) {\n\twhile (list.firstChild) list.removeChild(list.firstChild);\n\t\n\t// Create a YUI instance using io-base module.\n\tYUI().use(\"io-base\", function(Y) {\n\t\tvar uri = \"/fs?path=\" + base;\n\t\t\n\t\t// Define a function to handle the response data.\n\t\tfunction complete(id, o, args) {\n\t\t    var id = id; // Transaction ID.\n\t\t    var data = eval(\"(\" + o.responseText + \")\"); // Response data.\n\t\t    var parts = base.split(\"/\").slice(0,-1);\n\t\t    var parent = \"\"\n\t\t\tif (parts.length < 2) {\n\t\t\t    parent = \"/\";\n\t\t\t} else {\n\t\t\t    parent = parts.join(\"/\");\n\t\t\t}\n\t\t    if (base != \"/\") {\n\t\t\tvar li = self.createFileListItem({\"file\": \"..\", type: \"D\", path: parent});\n\t\t\tlist.appendChild(li);\n\t\t    }\n\t\t    for (var i in data) {\n\t\t\tvar f = data[i];\n\t\t\tif (f.file[0] != '.') {\n\t\t\t    var li = self.createFileListItem(f);\n\t\t\t    list.appendChild(li);\n\t\t\t}\n\t\t    }\n\t\t};\n\t\t\n\t\tY.on('io:complete', complete, Y, []);\n\t\tvar request = Y.io(uri);\n\t    });\n    };\n    \n    this.updateList(\"/\");\n};\n\n// Open a window which loads files into the engine\nLogGraph.fileLoader = function(files) {\n    var div = document.createElement(\"div\");\n    div.id = \"fileLoader\";\n    \n    var imgArray = new Array();\n    var pArray = new Array();\n    for (var index in files) {\n\tvar f = files[index];\n\tvar p = document.createElement(\"p\");\n\tvar i = document.createElement(\"img\");\n\ti.src = \"load.gif\";\n\ti.style.visibility = \"hidden\";\n\timgArray.push(i);\n\tpArray.push(p);\n\tvar span = document.createElement(\"span\");\n\tspan.innerHTML = f;\n\t\n\tp.appendChild(span);\n\tp.appendChild(i);\n\t\n\tdiv.appendChild(p);\n    }\n    \n    var loadFile = function (index) {\n\t// Create a YUI instance using io-base module.\n\tYUI().use(\"io-base\", function(Y) {\n\t\tvar file = files[index];\n\t\t    var uri = \"/loadfile?path=\" + file;\n\t\timgArray[index].style.visibility = \"visible\";\n\t\t\n\t\t// Define a function to handle the response data.\n\t\tfunction complete(id, o, args) {\n\t\t    var id = id; // Transaction ID.\n\t\t\tvar data = eval(\"(\" + o.responseText + \")\"); // Response data.\n\t\t\tif (data.status == \"ERR\") {\n\t\t\t    var err = document.createElement(\"div\");\n\t\t\t    err.innerHTML = data.error;\n\t\t\t    pArray[index].appendChild(err);\n\t\t\t} else if (data.status == \"OK\") {\n\t\t\t    var ok = document.createElement(\"div\");\n\t\t\t    ok.innerHTML = \"OK\";\n\t\t\t    pArray[index].appendChild(ok);\n\t\t\t}\n\t\t\t\n\t\t\timgArray[index].style.visibility = \"hidden\";\n\t\t\tif (index + 1 < files.length) {\n\t\t\t    loadFile(index + 1);\n\t\t\t} else {\n\t\t\t    //alert(\"DONE\");\n\t\t\t}\n\t\t};\n\t\t\n\t\tY.on('io:complete', complete, Y, []);\n\t\tvar request = Y.io(uri);\n\t    });\n    };\n\t\n    var doneanchor = document.createElement(\"a\");\n    doneanchor.className = \"actionbutton\";\n    doneanchor.innerHTML = \"Done\";\n    doneanchor.onclick = function () {\n\tdocument.body.removeChild(div);\n\tdelete div;\n    };\n    \n    document.body.appendChild(div);\n    if (files.length > 0) {\n\tloadFile(0);\n    } else {\n\tdiv.innerHTML =\"No files to load\";\n    }\n    div.appendChild(doneanchor);\n}\n\n// select a time period\nLogGraph.filterSelector = function(starttime, period, filter, callback) {\n    var self = this;\t\n    this.callback = callback;\n    \n    // Container other widgets will be in\n    var container = document.createElement(\"div\");\n    container.id = \"filterSelector\" + Math.round(Math.random()*100000);\n    container.className = \"selector filterSelector\";\n    document.body.appendChild(container);\n    \n    YUI().use('dd-drag', function(Y) {\n\t    //Selector of the node to make draggable\n\t    var dd = new Y.DD.Drag({\n\t\t    node: '#' + container.id\n\t\t});   \n\t});\n    \n    // Temporary loading screen\n    var loadingp = document.createElement(\"p\");\n    loadingp.innerHTML = \"Loading...\";\n    var loadimg = document.createElement(\"img\");\n    loadimg.src = \"load.gif\";\n    loadingp.appendChild(loadimg);\n    container.appendChild(loadingp);\n    \n    var addWithLabel = function (container, labeltxt, object) {\n\tvar p = document.createElement(\"p\");\n\tvar label = document.createElement(\"label\");\n\tlabel.innerHTML = labeltxt + \":\";\n\tp.appendChild(label);\n\tp.appendChild(object);\n\tcontainer.appendChild(p);\n    };\n    var draw = function(minstart, maxstart, entries) { \n\tcontainer.removeChild(loadingp);\n\tvar inittime = minstart > starttime ? minstart : starttime;\n\t\n\tvar numEntries = 0;\n\tvar startspan = document.createElement(\"span\");\n\taddWithLabel(container, \"Start time\", startspan);\n\tvar startinput = document.createElement(\"input\");\n\tstartinput.type = \"hidden\";\n\tstartinput.value = inittime;\n\tcontainer.appendChild(startinput);\n\tvar sliderspan = document.createElement(\"span\");\n\tcontainer.appendChild(sliderspan);\n\t\n\tvar countspan = document.createElement(\"p\");\n\tcountspan.innerHTML = entries + \" entries\";;\n\tcontainer.appendChild(countspan);\n\t\n\tvar windowinput = document.createElement(\"input\");\n\twindowinput.type = \"text\";\n\twindowinput.value = period;\n\taddWithLabel(container, \"Time window (ms)\", windowinput);\n\t\n\tvar filterinput = document.createElement(\"textarea\");\n\tfilterinput.id = \"filterinput\";\n\tfilterinput.value = filter;\n\taddWithLabel(container, \"Filter\", filterinput);\n\n\t/* done link, when clicked time is updated, */\n\tvar doneanchor = document.createElement(\"a\");\n\tdoneanchor.className = \"actionbutton\";\n\tdoneanchor.innerHTML = \"Done\";\n\tdoneanchor.onclick = function () {\n\t    var start = parseInt(startinput.value);\n\t    var period = parseInt(windowinput.value);\n\t    var filter = filterinput.value;\n\t    document.body.removeChild(container);\n\t    delete container;\n\t    \n\t    update(start, period, filter, function() {\n\t\t    callback(start, period, filter, numEntries);\n\t\t});\n\t};\n\tcontainer.appendChild(doneanchor);\n\t\n\tvar update = function(start, period, filter, thenrun) {\n\t    startspan.innerHTML = dateFormat(start, \"HH:MM:ss,l\");\n\t    // get the min and max start time\n\t    YUI().use(\"io-base\", function(Y) {\n\t\t    var uri = \"/info?start=\" + start + \"&period=\" + period + \"&filter=\" + filter;\n\t\t    function complete(id, o, args) {\n\t\t\tvar data = eval(\"(\" + o.responseText + \")\"); \n\t\t\tcountspan.innerHTML = data.numEntries + \" entries\";\n\t\t\tnumEntries = data.numEntries;\n\t\t\tif (thenrun) {\n\t\t\t    thenrun();\n\t\t\t}\n\t\t    };\n\t\t    \n\t\t    Y.on('io:complete', complete, Y, []);\n\t\t    var request = Y.io(uri);\n\t\t});\n\t};\n\t\n\tvar updatewindow = function(evt) {\t\t\n\t    var start = parseInt(startinput.value);\n\t    var period = parseInt(windowinput.value);\n\t    var filter = filterinput.value;\n\t    update(start, period, filter);\n\t};\n\twindowinput.onkeyup = updatewindow;\n\n\t\n\tYUI().use(\"slider\", function (Y) {\n\t\tvar input, slider; \n\t\t\n\t\tfunction updateInput( e ) {\n\t\t    this.set( \"value\", e.newVal );\n\t\t    \n\t\t    update(parseInt(startinput.value), parseInt(windowinput.value), filterinput.value);\n\t\t}\n\t\t\n\t\txSlider = new Y.Slider({min: minstart, max: maxstart, value: inittime, length: \"1000px\" });\n\t\t\n\t\t// Link the input value to the Slider\n\t\txInput = Y.one( startinput );\n\t\txInput.setData( { slider: xSlider } );\n\t\t\n\t\t// Pass the input as the 'this' object inside updateInput\n\t\txSlider.after( \"valueChange\", updateInput, xInput );\n\t\t\n\t\t// Render the Slider next to the input\n\t\txSlider.render(sliderspan);\n\t    });\n\tupdate(inittime, windowinput.value, filterinput);\n    };\n    \n    // get the min and max start time\n    YUI().use(\"io-base\", function(Y) {\n\t    var uri = \"/info\";\n\t    function complete(id, o, args) {\n\t\tvar data = eval(\"(\" + o.responseText + \")\"); \n\t\tdraw(data.startTime, data.endTime, data.numEntries);\n\t    };\n\t    \n\t    Y.on('io:complete', complete, Y, []);\n\t    var request = Y.io(uri);\n\t});\n}"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/main.html",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n<html>\n<head>\n<script src=\"raphael.js\"></script>\n<script src=\"date.format.js\"></script>\n<script src=\"loggraph.js\"></script>\n<script src=\"loggraph.ui.js\"></script>\n<script src=\"loggraph.log.js\"></script>\n<script src=\"loggraph.server.js\"></script>\n<script src=\"loggraph.stats.js\"></script>\n<script src=\"loggraph.session.js\"></script>\n\n<script src=\"g.raphael.js\"></script>\n<script src=\"g.line.js\"></script>\n<script src=\"g.pie.js\"></script>\n<script src=\"g.bar.js\"></script>\n\n<script type=\"text/javascript\" src=\"yui-min.js\"></script>\n\n<link rel=\"stylesheet\" type=\"text/css\" href=\"loggraph.css\">\n<script>\nvar g;\nfunction init() {\n     g = new LogGraph(\"canvas\", \"status\");\n}\n</script>\n</head>\n<body onLoad=\"init()\" class=\"yui3-skin-sam  yui-skin-sam\">\n\n<div id=\"actions\" class=\"maininterface\">\n  <span onclick=\"javascript:g.editFilters()\" class=\"actionbutton\">Edit Filters</span> \n  <span onclick=\"g.addLogs()\" class=\"actionbutton\">Add logs</span>\n</div>\n<div id=\"views\" class=\"maininterface\">\n  <span onclick=\"g.showLogs()\" class=\"actionbutton\">Log view</span>\n  <span onclick=\"g.serverGraph()\" class=\"actionbutton\">Servers view</span>\n  <span onclick=\"g.sessionGraph()\" class=\"actionbutton\">Sessions view</span> \n  <span onclick=\"g.showStats()\" class=\"actionbutton\">Statistics</span>\n</div>\n  <div id=\"status\"></div>\n<div id=\"outercontainer\">\n<div id=\"canvas\"></div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/raphael.js",
    "content": "/*!\n * Raphael 1.3.2 - JavaScript Vector Library\n *\n * Copyright (c) 2009 Dmitry Baranovskiy (http://raphaeljs.com)\n * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.\n */\n \nRaphael = (function () {\n    var separator = /[, ]+/,\n        elements = /^(circle|rect|path|ellipse|text|image)$/,\n        proto = \"prototype\",\n        has = \"hasOwnProperty\",\n        doc = document,\n        win = window,\n        oldRaphael = {\n            was: Object[proto][has].call(win, \"Raphael\"),\n            is: win.Raphael\n        },\n        R = function () {\n            if (R.is(arguments[0], \"array\")) {\n                var a = arguments[0],\n                    cnv = create[apply](R, a.splice(0, 3 + R.is(a[0], nu))),\n                    res = cnv.set();\n                for (var i = 0, ii = a[length]; i < ii; i++) {\n                    var j = a[i] || {};\n                    elements.test(j.type) && res[push](cnv[j.type]().attr(j));\n                }\n                return res;\n            }\n            return create[apply](R, arguments);\n        },\n        Paper = function () {},\n        appendChild = \"appendChild\",\n        apply = \"apply\",\n        concat = \"concat\",\n        E = \"\",\n        S = \" \",\n        split = \"split\",\n        events = \"click dblclick mousedown mousemove mouseout mouseover mouseup\"[split](S),\n        join = \"join\",\n        length = \"length\",\n        lowerCase = String[proto].toLowerCase,\n        math = Math,\n        mmax = math.max,\n        mmin = math.min,\n        nu = \"number\",\n        toString = \"toString\",\n        objectToString = Object[proto][toString],\n        paper = {},\n        pow = math.pow,\n        push = \"push\",\n        rg = /^(?=[\\da-f]$)/,\n        ISURL = /^url\\(['\"]?([^\\)]+?)['\"]?\\)$/i, //\"\n        colourRegExp = /^\\s*((#[a-f\\d]{6})|(#[a-f\\d]{3})|rgb\\(\\s*([\\d\\.]+\\s*,\\s*[\\d\\.]+\\s*,\\s*[\\d\\.]+)\\s*\\)|rgb\\(\\s*([\\d\\.]+%\\s*,\\s*[\\d\\.]+%\\s*,\\s*[\\d\\.]+%)\\s*\\)|hs[bl]\\(\\s*([\\d\\.]+\\s*,\\s*[\\d\\.]+\\s*,\\s*[\\d\\.]+)\\s*\\)|hs[bl]\\(\\s*([\\d\\.]+%\\s*,\\s*[\\d\\.]+%\\s*,\\s*[\\d\\.]+%)\\s*\\))\\s*$/i,\n        round = math.round,\n        setAttribute = \"setAttribute\",\n        toFloat = parseFloat,\n        toInt = parseInt,\n        upperCase = String[proto].toUpperCase,\n        availableAttrs = {blur: 0, \"clip-rect\": \"0 0 1e9 1e9\", cursor: \"default\", cx: 0, cy: 0, fill: \"#fff\", \"fill-opacity\": 1, font: '10px \"Arial\"', \"font-family\": '\"Arial\"', \"font-size\": \"10\", \"font-style\": \"normal\", \"font-weight\": 400, gradient: 0, height: 0, href: \"http://raphaeljs.com/\", opacity: 1, path: \"M0,0\", r: 0, rotation: 0, rx: 0, ry: 0, scale: \"1 1\", src: \"\", stroke: \"#000\", \"stroke-dasharray\": \"\", \"stroke-linecap\": \"butt\", \"stroke-linejoin\": \"butt\", \"stroke-miterlimit\": 0, \"stroke-opacity\": 1, \"stroke-width\": 1, target: \"_blank\", \"text-anchor\": \"middle\", title: \"Raphael\", translation: \"0 0\", width: 0, x: 0, y: 0},\n        availableAnimAttrs = {along: \"along\", blur: nu, \"clip-rect\": \"csv\", cx: nu, cy: nu, fill: \"colour\", \"fill-opacity\": nu, \"font-size\": nu, height: nu, opacity: nu, path: \"path\", r: nu, rotation: \"csv\", rx: nu, ry: nu, scale: \"csv\", stroke: \"colour\", \"stroke-opacity\": nu, \"stroke-width\": nu, translation: \"csv\", width: nu, x: nu, y: nu},\n        rp = \"replace\";\n    R.version = \"1.3.2\";\n    R.type = (win.SVGAngle || doc.implementation.hasFeature(\"http://www.w3.org/TR/SVG11/feature#BasicStructure\", \"1.1\") ? \"SVG\" : \"VML\");\n    if (R.type == \"VML\") {\n        var d = doc.createElement(\"div\");\n        d.innerHTML = '<!--[if vml]><br><br><![endif]-->';\n        if (d.childNodes[length] != 2) {\n            return R.type = null;\n        }\n        d = null;\n    }\n    R.svg = !(R.vml = R.type == \"VML\");\n    Paper[proto] = R[proto];\n    R._id = 0;\n    R._oid = 0;\n    R.fn = {};\n    R.is = function (o, type) {\n        type = lowerCase.call(type);\n        return ((type == \"object\" || type == \"undefined\") && typeof o == type) || (o == null && type == \"null\") || lowerCase.call(objectToString.call(o).slice(8, -1)) == type;\n    };\n    R.setWindow = function (newwin) {\n        win = newwin;\n        doc = win.document;\n    };\n    // colour utilities\n    var toHex = function (color) {\n        if (R.vml) {\n            // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/\n            var trim = /^\\s+|\\s+$/g;\n            toHex = cacher(function (color) {\n                var bod;\n                color = (color + E)[rp](trim, E);\n                try {\n                    var docum = new win.ActiveXObject(\"htmlfile\");\n                    docum.write(\"<body>\");\n                    docum.close();\n                    bod = docum.body;\n                } catch(e) {\n                    bod = win.createPopup().document.body;\n                }\n                var range = bod.createTextRange();\n                try {\n                    bod.style.color = color;\n                    var value = range.queryCommandValue(\"ForeColor\");\n                    value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);\n                    return \"#\" + (\"000000\" + value[toString](16)).slice(-6);\n                } catch(e) {\n                    return \"none\";\n                }\n            });\n        } else {\n            var i = doc.createElement(\"i\");\n            i.title = \"Rapha\\xebl Colour Picker\";\n            i.style.display = \"none\";\n            doc.body[appendChild](i);\n            toHex = cacher(function (color) {\n                i.style.color = color;\n                return doc.defaultView.getComputedStyle(i, E).getPropertyValue(\"color\");\n            });\n        }\n        return toHex(color);\n    };\n    var hsbtoString = function () {\n        return \"hsb(\" + [this.h, this.s, this.b] + \")\";\n    },\n    rgbtoString = function () {\n        return this.hex;\n    };\n    R.hsb2rgb = cacher(function (hue, saturation, brightness) {\n        if (R.is(hue, \"object\") && \"h\" in hue && \"s\" in hue && \"b\" in hue) {\n            brightness = hue.b;\n            saturation = hue.s;\n            hue = hue.h;\n        }\n        var red,\n            green,\n            blue;\n        if (brightness == 0) {\n            return {r: 0, g: 0, b: 0, hex: \"#000\"};\n        }\n        if (hue > 1 || saturation > 1 || brightness > 1) {\n            hue /= 255;\n            saturation /= 255;\n            brightness /= 255;\n        }\n        var i = ~~(hue * 6),\n            f = (hue * 6) - i,\n            p = brightness * (1 - saturation),\n            q = brightness * (1 - (saturation * f)),\n            t = brightness * (1 - (saturation * (1 - f)));\n        red = [brightness, q, p, p, t, brightness, brightness][i];\n        green = [t, brightness, brightness, q, p, p, t][i];\n        blue = [p, p, t, brightness, brightness, q, p][i];\n        red *= 255;\n        green *= 255;\n        blue *= 255;\n        var rgb = {r: red, g: green, b: blue, toString: rgbtoString},\n            r = (~~red)[toString](16),\n            g = (~~green)[toString](16),\n            b = (~~blue)[toString](16);\n        r = r[rp](rg, \"0\");\n        g = g[rp](rg, \"0\");\n        b = b[rp](rg, \"0\");\n        rgb.hex = \"#\" + r + g + b;\n        return rgb;\n    }, R);\n    R.rgb2hsb = cacher(function (red, green, blue) {\n        if (R.is(red, \"object\") && \"r\" in red && \"g\" in red && \"b\" in red) {\n            blue = red.b;\n            green = red.g;\n            red = red.r;\n        }\n        if (R.is(red, \"string\")) {\n            var clr = R.getRGB(red);\n            red = clr.r;\n            green = clr.g;\n            blue = clr.b;\n        }\n        if (red > 1 || green > 1 || blue > 1) {\n            red /= 255;\n            green /= 255;\n            blue /= 255;\n        }\n        var max = mmax(red, green, blue),\n            min = mmin(red, green, blue),\n            hue,\n            saturation,\n            brightness = max;\n        if (min == max) {\n            return {h: 0, s: 0, b: max};\n        } else {\n            var delta = (max - min);\n            saturation = delta / max;\n            if (red == max) {\n                hue = (green - blue) / delta;\n            } else if (green == max) {\n                hue = 2 + ((blue - red) / delta);\n            } else {\n                hue = 4 + ((red - green) / delta);\n            }\n            hue /= 6;\n            hue < 0 && hue++;\n            hue > 1 && hue--;\n        }\n        return {h: hue, s: saturation, b: brightness, toString: hsbtoString};\n    }, R);\n    var p2s = /,?([achlmqrstvxz]),?/gi;\n    R._path2string = function () {\n        return this.join(\",\")[rp](p2s, \"$1\");\n    };\n    function cacher(f, scope, postprocessor) {\n        function newf() {\n            var arg = Array[proto].slice.call(arguments, 0),\n                args = arg[join](\"\\u25ba\"),\n                cache = newf.cache = newf.cache || {},\n                count = newf.count = newf.count || [];\n            if (cache[has](args)) {\n                return postprocessor ? postprocessor(cache[args]) : cache[args];\n            }\n            count[length] >= 1e3 && delete cache[count.shift()];\n            count[push](args);\n            cache[args] = f[apply](scope, arg);\n            return postprocessor ? postprocessor(cache[args]) : cache[args];\n        }\n        return newf;\n    }\n \n    R.getRGB = cacher(function (colour) {\n        if (!colour || !!((colour = colour + E).indexOf(\"-\") + 1)) {\n            return {r: -1, g: -1, b: -1, hex: \"none\", error: 1};\n        }\n        if (colour == \"none\") {\n            return {r: -1, g: -1, b: -1, hex: \"none\"};\n        }\n        !(({hs: 1, rg: 1})[has](colour.substring(0, 2)) || colour.charAt() == \"#\") && (colour = toHex(colour));\n        var res,\n            red,\n            green,\n            blue,\n            t,\n            rgb = colour.match(colourRegExp);\n        if (rgb) {\n            if (rgb[2]) {\n                blue = toInt(rgb[2].substring(5), 16);\n                green = toInt(rgb[2].substring(3, 5), 16);\n                red = toInt(rgb[2].substring(1, 3), 16);\n            }\n            if (rgb[3]) {\n                blue = toInt((t = rgb[3].charAt(3)) + t, 16);\n                green = toInt((t = rgb[3].charAt(2)) + t, 16);\n                red = toInt((t = rgb[3].charAt(1)) + t, 16);\n            }\n            if (rgb[4]) {\n                rgb = rgb[4][split](/\\s*,\\s*/);\n                red = toFloat(rgb[0]);\n                green = toFloat(rgb[1]);\n                blue = toFloat(rgb[2]);\n            }\n            if (rgb[5]) {\n                rgb = rgb[5][split](/\\s*,\\s*/);\n                red = toFloat(rgb[0]) * 2.55;\n                green = toFloat(rgb[1]) * 2.55;\n                blue = toFloat(rgb[2]) * 2.55;\n            }\n            if (rgb[6]) {\n                rgb = rgb[6][split](/\\s*,\\s*/);\n                red = toFloat(rgb[0]);\n                green = toFloat(rgb[1]);\n                blue = toFloat(rgb[2]);\n                return R.hsb2rgb(red, green, blue);\n            }\n            if (rgb[7]) {\n                rgb = rgb[7][split](/\\s*,\\s*/);\n                red = toFloat(rgb[0]) * 2.55;\n                green = toFloat(rgb[1]) * 2.55;\n                blue = toFloat(rgb[2]) * 2.55;\n                return R.hsb2rgb(red, green, blue);\n            }\n            rgb = {r: red, g: green, b: blue};\n            var r = (~~red)[toString](16),\n                g = (~~green)[toString](16),\n                b = (~~blue)[toString](16);\n            r = r[rp](rg, \"0\");\n            g = g[rp](rg, \"0\");\n            b = b[rp](rg, \"0\");\n            rgb.hex = \"#\" + r + g + b;\n            return rgb;\n        }\n        return {r: -1, g: -1, b: -1, hex: \"none\", error: 1};\n    }, R);\n    R.getColor = function (value) {\n        var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75},\n            rgb = this.hsb2rgb(start.h, start.s, start.b);\n        start.h += .075;\n        if (start.h > 1) {\n            start.h = 0;\n            start.s -= .2;\n            start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b});\n        }\n        return rgb.hex;\n    };\n    R.getColor.reset = function () {\n        delete this.start;\n    };\n    // path utilities\n    var pathCommand = /([achlmqstvz])[\\s,]*((-?\\d*\\.?\\d*(?:e[-+]?\\d+)?\\s*,?\\s*)+)/ig,\n        pathValues = /(-?\\d*\\.?\\d*(?:e[-+]?\\d+)?)\\s*,?\\s*/ig;\n    R.parsePathString = cacher(function (pathString) {\n        if (!pathString) {\n            return null;\n        }\n        var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},\n            data = [];\n        if (R.is(pathString, \"array\") && R.is(pathString[0], \"array\")) { // rough assumption\n            data = pathClone(pathString);\n        }\n        if (!data[length]) {\n            (pathString + E)[rp](pathCommand, function (a, b, c) {\n                var params = [],\n                    name = lowerCase.call(b);\n                c[rp](pathValues, function (a, b) {\n                    b && params[push](+b);\n                });\n                if (name == \"m\" && params[length] > 2) {\n                    data[push]([b][concat](params.splice(0, 2)));\n                    name = \"l\";\n                    b = b == \"m\" ? \"l\" : \"L\";\n                }\n                while (params[length] >= paramCounts[name]) {\n                    data[push]([b][concat](params.splice(0, paramCounts[name])));\n                    if (!paramCounts[name]) {\n                        break;\n                    }\n                }\n            });\n        }\n        data[toString] = R._path2string;\n        return data;\n    });\n    R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {\n        var t1 = 1 - t,\n            x = pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,\n            y = pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y,\n            mx = p1x + 2 * t * (c1x - p1x) + t * t * (c2x - 2 * c1x + p1x),\n            my = p1y + 2 * t * (c1y - p1y) + t * t * (c2y - 2 * c1y + p1y),\n            nx = c1x + 2 * t * (c2x - c1x) + t * t * (p2x - 2 * c2x + c1x),\n            ny = c1y + 2 * t * (c2y - c1y) + t * t * (p2y - 2 * c2y + c1y),\n            ax = (1 - t) * p1x + t * c1x,\n            ay = (1 - t) * p1y + t * c1y,\n            cx = (1 - t) * c2x + t * p2x,\n            cy = (1 - t) * c2y + t * p2y,\n            alpha = (90 - math.atan((mx - nx) / (my - ny)) * 180 / math.PI);\n        (mx > nx || my < ny) && (alpha += 180);\n        return {x: x, y: y, m: {x: mx, y: my}, n: {x: nx, y: ny}, start: {x: ax, y: ay}, end: {x: cx, y: cy}, alpha: alpha};\n    };\n    var pathDimensions = cacher(function (path) {\n        if (!path) {\n            return {x: 0, y: 0, width: 0, height: 0};\n        }\n        path = path2curve(path);\n        var x = 0, \n            y = 0,\n            X = [],\n            Y = [],\n            p;\n        for (var i = 0, ii = path[length]; i < ii; i++) {\n            p = path[i];\n            if (p[0] == \"M\") {\n                x = p[1];\n                y = p[2];\n                X[push](x);\n                Y[push](y);\n            } else {\n                var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);\n                X = X[concat](dim.min.x, dim.max.x);\n                Y = Y[concat](dim.min.y, dim.max.y);\n                x = p[5];\n                y = p[6];\n            }\n        }\n        var xmin = mmin[apply](0, X),\n            ymin = mmin[apply](0, Y);\n        return {\n            x: xmin,\n            y: ymin,\n            width: mmax[apply](0, X) - xmin,\n            height: mmax[apply](0, Y) - ymin\n        };\n    }),\n        pathClone = function (pathArray) {\n            var res = [];\n            if (!R.is(pathArray, \"array\") || !R.is(pathArray && pathArray[0], \"array\")) { // rough assumption\n                pathArray = R.parsePathString(pathArray);\n            }\n            for (var i = 0, ii = pathArray[length]; i < ii; i++) {\n                res[i] = [];\n                for (var j = 0, jj = pathArray[i][length]; j < jj; j++) {\n                    res[i][j] = pathArray[i][j];\n                }\n            }\n            res[toString] = R._path2string;\n            return res;\n        },\n        pathToRelative = cacher(function (pathArray) {\n            if (!R.is(pathArray, \"array\") || !R.is(pathArray && pathArray[0], \"array\")) { // rough assumption\n                pathArray = R.parsePathString(pathArray);\n            }\n            var res = [],\n                x = 0,\n                y = 0,\n                mx = 0,\n                my = 0,\n                start = 0;\n            if (pathArray[0][0] == \"M\") {\n                x = pathArray[0][1];\n                y = pathArray[0][2];\n                mx = x;\n                my = y;\n                start++;\n                res[push]([\"M\", x, y]);\n            }\n            for (var i = start, ii = pathArray[length]; i < ii; i++) {\n                var r = res[i] = [],\n                    pa = pathArray[i];\n                if (pa[0] != lowerCase.call(pa[0])) {\n                    r[0] = lowerCase.call(pa[0]);\n                    switch (r[0]) {\n                        case \"a\":\n                            r[1] = pa[1];\n                            r[2] = pa[2];\n                            r[3] = pa[3];\n                            r[4] = pa[4];\n                            r[5] = pa[5];\n                            r[6] = +(pa[6] - x).toFixed(3);\n                            r[7] = +(pa[7] - y).toFixed(3);\n                            break;\n                        case \"v\":\n                            r[1] = +(pa[1] - y).toFixed(3);\n                            break;\n                        case \"m\":\n                            mx = pa[1];\n                            my = pa[2];\n                        default:\n                            for (var j = 1, jj = pa[length]; j < jj; j++) {\n                                r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);\n                            }\n                    }\n                } else {\n                    r = res[i] = [];\n                    if (pa[0] == \"m\") {\n                        mx = pa[1] + x;\n                        my = pa[2] + y;\n                    }\n                    for (var k = 0, kk = pa[length]; k < kk; k++) {\n                        res[i][k] = pa[k];\n                    }\n                }\n                var len = res[i][length];\n                switch (res[i][0]) {\n                    case \"z\":\n                        x = mx;\n                        y = my;\n                        break;\n                    case \"h\":\n                        x += +res[i][len - 1];\n                        break;\n                    case \"v\":\n                        y += +res[i][len - 1];\n                        break;\n                    default:\n                        x += +res[i][len - 2];\n                        y += +res[i][len - 1];\n                }\n            }\n            res[toString] = R._path2string;\n            return res;\n        }, 0, pathClone),\n        pathToAbsolute = cacher(function (pathArray) {\n            if (!R.is(pathArray, \"array\") || !R.is(pathArray && pathArray[0], \"array\")) { // rough assumption\n                pathArray = R.parsePathString(pathArray);\n            }\n            var res = [],\n                x = 0,\n                y = 0,\n                mx = 0,\n                my = 0,\n                start = 0;\n            if (pathArray[0][0] == \"M\") {\n                x = +pathArray[0][1];\n                y = +pathArray[0][2];\n                mx = x;\n                my = y;\n                start++;\n                res[0] = [\"M\", x, y];\n            }\n            for (var i = start, ii = pathArray[length]; i < ii; i++) {\n                var r = res[i] = [],\n                    pa = pathArray[i];\n                if (pa[0] != upperCase.call(pa[0])) {\n                    r[0] = upperCase.call(pa[0]);\n                    switch (r[0]) {\n                        case \"A\":\n                            r[1] = pa[1];\n                            r[2] = pa[2];\n                            r[3] = pa[3];\n                            r[4] = pa[4];\n                            r[5] = pa[5];\n                            r[6] = +(pa[6] + x);\n                            r[7] = +(pa[7] + y);\n                            break;\n                        case \"V\":\n                            r[1] = +pa[1] + y;\n                            break;\n                        case \"H\":\n                            r[1] = +pa[1] + x;\n                            break;\n                        case \"M\":\n                            mx = +pa[1] + x;\n                            my = +pa[2] + y;\n                        default:\n                            for (var j = 1, jj = pa[length]; j < jj; j++) {\n                                r[j] = +pa[j] + ((j % 2) ? x : y);\n                            }\n                    }\n                } else {\n                    for (var k = 0, kk = pa[length]; k < kk; k++) {\n                        res[i][k] = pa[k];\n                    }\n                }\n                switch (r[0]) {\n                    case \"Z\":\n                        x = mx;\n                        y = my;\n                        break;\n                    case \"H\":\n                        x = r[1];\n                        break;\n                    case \"V\":\n                        y = r[1];\n                        break;\n                    default:\n                        x = res[i][res[i][length] - 2];\n                        y = res[i][res[i][length] - 1];\n                }\n            }\n            res[toString] = R._path2string;\n            return res;\n        }, null, pathClone),\n        l2c = function (x1, y1, x2, y2) {\n            return [x1, y1, x2, y2, x2, y2];\n        },\n        q2c = function (x1, y1, ax, ay, x2, y2) {\n            var _13 = 1 / 3,\n                _23 = 2 / 3;\n            return [\n                    _13 * x1 + _23 * ax,\n                    _13 * y1 + _23 * ay,\n                    _13 * x2 + _23 * ax,\n                    _13 * y2 + _23 * ay,\n                    x2,\n                    y2\n                ];\n        },\n        a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {\n            // for more information of where this math came from visit:\n            // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes\n            var PI = math.PI,\n                _120 = PI * 120 / 180,\n                rad = PI / 180 * (+angle || 0),\n                res = [],\n                xy,\n                rotate = cacher(function (x, y, rad) {\n                    var X = x * math.cos(rad) - y * math.sin(rad),\n                        Y = x * math.sin(rad) + y * math.cos(rad);\n                    return {x: X, y: Y};\n                });\n            if (!recursive) {\n                xy = rotate(x1, y1, -rad);\n                x1 = xy.x;\n                y1 = xy.y;\n                xy = rotate(x2, y2, -rad);\n                x2 = xy.x;\n                y2 = xy.y;\n                var cos = math.cos(PI / 180 * angle),\n                    sin = math.sin(PI / 180 * angle),\n                    x = (x1 - x2) / 2,\n                    y = (y1 - y2) / 2;\n                // rx = mmax(rx, math.abs(x));\n                // ry = mmax(ry, math.abs(y));\n                var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);\n                if (h > 1) {\n                    h = math.sqrt(h);\n                    rx = h * rx;\n                    ry = h * ry;\n                }\n                var rx2 = rx * rx,\n                    ry2 = ry * ry,\n                    k = (large_arc_flag == sweep_flag ? -1 : 1) *\n                        math.sqrt(math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),\n                    cx = k * rx * y / ry + (x1 + x2) / 2,\n                    cy = k * -ry * x / rx + (y1 + y2) / 2,\n                    f1 = math.asin(((y1 - cy) / ry).toFixed(7)),\n                    f2 = math.asin(((y2 - cy) / ry).toFixed(7));\n\n                f1 = x1 < cx ? PI - f1 : f1;\n                f2 = x2 < cx ? PI - f2 : f2;\n                f1 < 0 && (f1 = PI * 2 + f1);\n                f2 < 0 && (f2 = PI * 2 + f2);\n                if (sweep_flag && f1 > f2) {\n                    f1 = f1 - PI * 2;\n                }\n                if (!sweep_flag && f2 > f1) {\n                    f2 = f2 - PI * 2;\n                }\n            } else {\n                f1 = recursive[0];\n                f2 = recursive[1];\n                cx = recursive[2];\n                cy = recursive[3];\n            }\n            var df = f2 - f1;\n            if (math.abs(df) > _120) {\n                var f2old = f2,\n                    x2old = x2,\n                    y2old = y2;\n                f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);\n                x2 = cx + rx * math.cos(f2);\n                y2 = cy + ry * math.sin(f2);\n                res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);\n            }\n            df = f2 - f1;\n            var c1 = math.cos(f1),\n                s1 = math.sin(f1),\n                c2 = math.cos(f2),\n                s2 = math.sin(f2),\n                t = math.tan(df / 4),\n                hx = 4 / 3 * rx * t,\n                hy = 4 / 3 * ry * t,\n                m1 = [x1, y1],\n                m2 = [x1 + hx * s1, y1 - hy * c1],\n                m3 = [x2 + hx * s2, y2 - hy * c2],\n                m4 = [x2, y2];\n            m2[0] = 2 * m1[0] - m2[0];\n            m2[1] = 2 * m1[1] - m2[1];\n            if (recursive) {\n                return [m2, m3, m4][concat](res);\n            } else {\n                res = [m2, m3, m4][concat](res)[join]()[split](\",\");\n                var newres = [];\n                for (var i = 0, ii = res[length]; i < ii; i++) {\n                    newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;\n                }\n                // alert(newres);\n                return newres;\n            }\n        },\n        findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {\n            var t1 = 1 - t;\n            return {\n                x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,\n                y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y\n            };\n        },\n        curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {\n            var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),\n                b = 2 * (c1x - p1x) - 2 * (c2x - c1x),\n                c = p1x - c1x,\n                t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,\n                t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,\n                y = [p1y, p2y],\n                x = [p1x, p2x],\n                dot;\n            math.abs(t1) > 1e12 && (t1 = .5);\n            math.abs(t2) > 1e12 && (t2 = .5);\n            if (t1 > 0 && t1 < 1) {\n                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);\n                x[push](dot.x);\n                y[push](dot.y);\n            }\n            if (t2 > 0 && t2 < 1) {\n                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);\n                x[push](dot.x);\n                y[push](dot.y);\n            }\n            a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);\n            b = 2 * (c1y - p1y) - 2 * (c2y - c1y);\n            c = p1y - c1y;\n            t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;\n            t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;\n            math.abs(t1) > 1e12 && (t1 = .5);\n            math.abs(t2) > 1e12 && (t2 = .5);\n            if (t1 > 0 && t1 < 1) {\n                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);\n                x[push](dot.x);\n                y[push](dot.y);\n            }\n            if (t2 > 0 && t2 < 1) {\n                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);\n                x[push](dot.x);\n                y[push](dot.y);\n            }\n            return {\n                min: {x: mmin[apply](0, x), y: mmin[apply](0, y)},\n                max: {x: mmax[apply](0, x), y: mmax[apply](0, y)}\n            };\n        }),\n        path2curve = cacher(function (path, path2) {\n            var p = pathToAbsolute(path),\n                p2 = path2 && pathToAbsolute(path2),\n                attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},\n                attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},\n                processPath = function (path, d) {\n                    var nx, ny;\n                    if (!path) {\n                        return [\"C\", d.x, d.y, d.x, d.y, d.x, d.y];\n                    }\n                    !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);\n                    switch (path[0]) {\n                        case \"M\":\n                            d.X = path[1];\n                            d.Y = path[2];\n                            break;\n                        case \"A\":\n                            path = [\"C\"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));\n                            break;\n                        case \"S\":\n                            nx = d.x + (d.x - (d.bx || d.x));\n                            ny = d.y + (d.y - (d.by || d.y));\n                            path = [\"C\", nx, ny][concat](path.slice(1));\n                            break;\n                        case \"T\":\n                            d.qx = d.x + (d.x - (d.qx || d.x));\n                            d.qy = d.y + (d.y - (d.qy || d.y));\n                            path = [\"C\"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));\n                            break;\n                        case \"Q\":\n                            d.qx = path[1];\n                            d.qy = path[2];\n                            path = [\"C\"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));\n                            break;\n                        case \"L\":\n                            path = [\"C\"][concat](l2c(d.x, d.y, path[1], path[2]));\n                            break;\n                        case \"H\":\n                            path = [\"C\"][concat](l2c(d.x, d.y, path[1], d.y));\n                            break;\n                        case \"V\":\n                            path = [\"C\"][concat](l2c(d.x, d.y, d.x, path[1]));\n                            break;\n                        case \"Z\":\n                            path = [\"C\"][concat](l2c(d.x, d.y, d.X, d.Y));\n                            break;\n                    }\n                    return path;\n                },\n                fixArc = function (pp, i) {\n                    if (pp[i][length] > 7) {\n                        pp[i].shift();\n                        var pi = pp[i];\n                        while (pi[length]) {\n                            pp.splice(i++, 0, [\"C\"][concat](pi.splice(0, 6)));\n                        }\n                        pp.splice(i, 1);\n                        ii = mmax(p[length], p2 && p2[length] || 0);\n                    }\n                },\n                fixM = function (path1, path2, a1, a2, i) {\n                    if (path1 && path2 && path1[i][0] == \"M\" && path2[i][0] != \"M\") {\n                        path2.splice(i, 0, [\"M\", a2.x, a2.y]);\n                        a1.bx = 0;\n                        a1.by = 0;\n                        a1.x = path1[i][1];\n                        a1.y = path1[i][2];\n                        ii = mmax(p[length], p2 && p2[length] || 0);\n                    }\n                };\n            for (var i = 0, ii = mmax(p[length], p2 && p2[length] || 0); i < ii; i++) {\n                p[i] = processPath(p[i], attrs);\n                fixArc(p, i);\n                p2 && (p2[i] = processPath(p2[i], attrs2));\n                p2 && fixArc(p2, i);\n                fixM(p, p2, attrs, attrs2, i);\n                fixM(p2, p, attrs2, attrs, i);\n                var seg = p[i],\n                    seg2 = p2 && p2[i],\n                    seglen = seg[length],\n                    seg2len = p2 && seg2[length];\n                attrs.x = seg[seglen - 2];\n                attrs.y = seg[seglen - 1];\n                attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;\n                attrs.by = toFloat(seg[seglen - 3]) || attrs.y;\n                attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);\n                attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);\n                attrs2.x = p2 && seg2[seg2len - 2];\n                attrs2.y = p2 && seg2[seg2len - 1];\n            }\n            return p2 ? [p, p2] : p;\n        }, null, pathClone),\n        parseDots = cacher(function (gradient) {\n            var dots = [];\n            for (var i = 0, ii = gradient[length]; i < ii; i++) {\n                var dot = {},\n                    par = gradient[i].match(/^([^:]*):?([\\d\\.]*)/);\n                dot.color = R.getRGB(par[1]);\n                if (dot.color.error) {\n                    return null;\n                }\n                dot.color = dot.color.hex;\n                par[2] && (dot.offset = par[2] + \"%\");\n                dots[push](dot);\n            }\n            for (i = 1, ii = dots[length] - 1; i < ii; i++) {\n                if (!dots[i].offset) {\n                    var start = toFloat(dots[i - 1].offset || 0),\n                        end = 0;\n                    for (var j = i + 1; j < ii; j++) {\n                        if (dots[j].offset) {\n                            end = dots[j].offset;\n                            break;\n                        }\n                    }\n                    if (!end) {\n                        end = 100;\n                        j = ii;\n                    }\n                    end = toFloat(end);\n                    var d = (end - start) / (j - i + 1);\n                    for (; i < j; i++) {\n                        start += d;\n                        dots[i].offset = start + \"%\";\n                    }\n                }\n            }\n            return dots;\n        }),\n        getContainer = function (x, y, w, h) {\n            var container;\n            if (R.is(x, \"string\") || R.is(x, \"object\")) {\n                container = R.is(x, \"string\") ? doc.getElementById(x) : x;\n                if (container.tagName) {\n                    if (y == null) {\n                        return {\n                            container: container,\n                            width: container.style.pixelWidth || container.offsetWidth,\n                            height: container.style.pixelHeight || container.offsetHeight\n                        };\n                    } else {\n                        return {container: container, width: y, height: w};\n                    }\n                }\n            } else if (R.is(x, nu) && h != null) {\n                return {container: 1, x: x, y: y, width: w, height: h};\n            }\n        },\n        plugins = function (con, add) {\n            var that = this;\n            for (var prop in add) {\n                if (add[has](prop) && !(prop in con)) {\n                    switch (typeof add[prop]) {\n                        case \"function\":\n                            (function (f) {\n                                con[prop] = con === that ? f : function () { return f[apply](that, arguments); };\n                            })(add[prop]);\n                        break;\n                        case \"object\":\n                            con[prop] = con[prop] || {};\n                            plugins.call(this, con[prop], add[prop]);\n                        break;\n                        default:\n                            con[prop] = add[prop];\n                        break;\n                    }\n                }\n            }\n        },\n        tear = function (el, paper) {\n            el == paper.top && (paper.top = el.prev);\n            el == paper.bottom && (paper.bottom = el.next);\n            el.next && (el.next.prev = el.prev);\n            el.prev && (el.prev.next = el.next);\n        },\n        tofront = function (el, paper) {\n            if (paper.top === el) {\n                return;\n            }\n            tear(el, paper);\n            el.next = null;\n            el.prev = paper.top;\n            paper.top.next = el;\n            paper.top = el;\n        },\n        toback = function (el, paper) {\n            if (paper.bottom === el) {\n                return;\n            }\n            tear(el, paper);\n            el.next = paper.bottom;\n            el.prev = null;\n            paper.bottom.prev = el;\n            paper.bottom = el;\n        },\n        insertafter = function (el, el2, paper) {\n            tear(el, paper);\n            el2 == paper.top && (paper.top = el);\n            el2.next && (el2.next.prev = el);\n            el.next = el2.next;\n            el.prev = el2;\n            el2.next = el;\n        },\n        insertbefore = function (el, el2, paper) {\n            tear(el, paper);\n            el2 == paper.bottom && (paper.bottom = el);\n            el2.prev && (el2.prev.next = el);\n            el.prev = el2.prev;\n            el2.prev = el;\n            el.next = el2;\n        },\n        removed = function (methodname) {\n            return function () {\n                throw new Error(\"Rapha\\xebl: you are calling to method \\u201c\" + methodname + \"\\u201d of removed object\");\n            };\n        },\n        radial_gradient = /^r(?:\\(([^,]+?)\\s*,\\s*([^\\)]+?)\\))?/;\n \n    // SVG\n    if (R.svg) {\n        Paper[proto].svgns = \"http://www.w3.org/2000/svg\";\n        Paper[proto].xlink = \"http://www.w3.org/1999/xlink\";\n        round = function (num) {\n            return +num + (~~num === num) * .5;\n        };\n        var roundPath = function (path) {\n            for (var i = 0, ii = path[length]; i < ii; i++) {\n                if (lowerCase.call(path[i][0]) != \"a\") {\n                    for (var j = 1, jj = path[i][length]; j < jj; j++) {\n                        path[i][j] = round(path[i][j]);\n                    }\n                } else {\n                    path[i][6] = round(path[i][6]);\n                    path[i][7] = round(path[i][7]);\n                }\n            }\n            return path;\n        },\n        $ = function (el, attr) {\n            if (attr) {\n                for (var key in attr) {\n                    if (attr[has](key)) {\n                        el[setAttribute](key, attr[key] + E);\n                    }\n                }\n            } else {\n                return doc.createElementNS(Paper[proto].svgns, el);\n            }\n        };\n        R[toString] = function () {\n            return  \"Your browser supports SVG.\\nYou are running Rapha\\xebl \" + this.version;\n        };\n        var thePath = function (pathString, SVG) {\n            var el = $(\"path\");\n            SVG.canvas && SVG.canvas[appendChild](el);\n            var p = new Element(el, SVG);\n            p.type = \"path\";\n            setFillAndStroke(p, {fill: \"none\", stroke: \"#000\", path: pathString});\n            return p;\n        };\n        var addGradientFill = function (o, gradient, SVG) {\n            var type = \"linear\",\n                fx = .5, fy = .5,\n                s = o.style;\n            gradient = (gradient + E)[rp](radial_gradient, function (all, _fx, _fy) {\n                type = \"radial\";\n                if (_fx && _fy) {\n                    fx = toFloat(_fx);\n                    fy = toFloat(_fy);\n                    var dir = ((fy > .5) * 2 - 1);\n                    pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&\n                        (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&\n                        fy != .5 &&\n                        (fy = fy.toFixed(5) - 1e-5 * dir);\n                }\n                return E;\n            });\n            gradient = gradient[split](/\\s*\\-\\s*/);\n            if (type == \"linear\") {\n                var angle = gradient.shift();\n                angle = -toFloat(angle);\n                if (isNaN(angle)) {\n                    return null;\n                }\n                var vector = [0, 0, math.cos(angle * math.PI / 180), math.sin(angle * math.PI / 180)],\n                    max = 1 / (mmax(math.abs(vector[2]), math.abs(vector[3])) || 1);\n                vector[2] *= max;\n                vector[3] *= max;\n                if (vector[2] < 0) {\n                    vector[0] = -vector[2];\n                    vector[2] = 0;\n                }\n                if (vector[3] < 0) {\n                    vector[1] = -vector[3];\n                    vector[3] = 0;\n                }\n            }\n            var dots = parseDots(gradient);\n            if (!dots) {\n                return null;\n            }\n            var id = o.getAttribute(\"fill\");\n            id = id.match(/^url\\(#(.*)\\)$/);\n            id && SVG.defs.removeChild(doc.getElementById(id[1]));\n            \n            var el = $(type + \"Gradient\");\n            el.id = \"r\" + (R._id++)[toString](36);\n            $(el, type == \"radial\" ? {fx: fx, fy: fy} : {x1: vector[0], y1: vector[1], x2: vector[2], y2: vector[3]});\n            SVG.defs[appendChild](el);\n            for (var i = 0, ii = dots[length]; i < ii; i++) {\n                var stop = $(\"stop\");\n                $(stop, {\n                    offset: dots[i].offset ? dots[i].offset : !i ? \"0%\" : \"100%\",\n                    \"stop-color\": dots[i].color || \"#fff\"\n                });\n                el[appendChild](stop);\n            }\n            $(o, {\n                fill: \"url(#\" + el.id + \")\",\n                opacity: 1,\n                \"fill-opacity\": 1\n            });\n            s.fill = E;\n            s.opacity = 1;\n            s.fillOpacity = 1;\n            return 1;\n        };\n        var updatePosition = function (o) {\n            var bbox = o.getBBox();\n            $(o.pattern, {patternTransform: R.format(\"translate({0},{1})\", bbox.x, bbox.y)});\n        };\n        var setFillAndStroke = function (o, params) {\n            var dasharray = {\n                    \"\": [0],\n                    \"none\": [0],\n                    \"-\": [3, 1],\n                    \".\": [1, 1],\n                    \"-.\": [3, 1, 1, 1],\n                    \"-..\": [3, 1, 1, 1, 1, 1],\n                    \". \": [1, 3],\n                    \"- \": [4, 3],\n                    \"--\": [8, 3],\n                    \"- .\": [4, 3, 1, 3],\n                    \"--.\": [8, 3, 1, 3],\n                    \"--..\": [8, 3, 1, 3, 1, 3]\n                },\n                node = o.node,\n                attrs = o.attrs,\n                rot = o.rotate(),\n                addDashes = function (o, value) {\n                    value = dasharray[lowerCase.call(value)];\n                    if (value) {\n                        var width = o.attrs[\"stroke-width\"] || \"1\",\n                            butt = {round: width, square: width, butt: 0}[o.attrs[\"stroke-linecap\"] || params[\"stroke-linecap\"]] || 0,\n                            dashes = [];\n                        var i = value[length];\n                        while (i--) {\n                            dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;\n                        }\n                        $(node, {\"stroke-dasharray\": dashes[join](\",\")});\n                    }\n                };\n            params[has](\"rotation\") && (rot = params.rotation);\n            var rotxy = (rot + E)[split](separator);\n            if (!(rotxy.length - 1)) {\n                rotxy = null;\n            } else {\n                rotxy[1] = +rotxy[1];\n                rotxy[2] = +rotxy[2];\n            }\n            toFloat(rot) && o.rotate(0, true);\n            for (var att in params) {\n                if (params[has](att)) {\n                    if (!availableAttrs[has](att)) {\n                        continue;\n                    }\n                    var value = params[att];\n                    attrs[att] = value;\n                    switch (att) {\n                        case \"blur\":\n                            o.blur(value);\n                            break;\n                        case \"rotation\":\n                            o.rotate(value, true);\n                            break;\n                        // Hyperlink\n                        case \"href\":\n                        case \"title\":\n                        case \"target\":\n                            var pn = node.parentNode;\n                            if (lowerCase.call(pn.tagName) != \"a\") {\n                                var hl = $(\"a\");\n                                pn.insertBefore(hl, node);\n                                hl[appendChild](node);\n                                pn = hl;\n                            }\n                            pn.setAttributeNS(o.paper.xlink, att, value);\n                            break;\n                        case \"cursor\":\n                            node.style.cursor = value;\n                            break;\n                        case \"clip-rect\":\n                            var rect = (value + E)[split](separator);\n                            if (rect[length] == 4) {\n                                o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);\n                                var el = $(\"clipPath\"),\n                                    rc = $(\"rect\");\n                                el.id = \"r\" + (R._id++)[toString](36);\n                                $(rc, {\n                                    x: rect[0],\n                                    y: rect[1],\n                                    width: rect[2],\n                                    height: rect[3]\n                                });\n                                el[appendChild](rc);\n                                o.paper.defs[appendChild](el);\n                                $(node, {\"clip-path\": \"url(#\" + el.id + \")\"});\n                                o.clip = rc;\n                            }\n                            if (!value) {\n                                var clip = doc.getElementById(node.getAttribute(\"clip-path\")[rp](/(^url\\(#|\\)$)/g, E));\n                                clip && clip.parentNode.removeChild(clip);\n                                $(node, {\"clip-path\": E});\n                                delete o.clip;\n                            }\n                        break;\n                        case \"path\":\n                            if (o.type == \"path\") {\n                                $(node, {d: value ? attrs.path = roundPath(pathToAbsolute(value)) : \"M0,0\"});\n                            }\n                            break;\n                        case \"width\":\n                            node[setAttribute](att, value);\n                            if (attrs.fx) {\n                                att = \"x\";\n                                value = attrs.x;\n                            } else {\n                                break;\n                            }\n                        case \"x\":\n                            if (attrs.fx) {\n                                value = -attrs.x - (attrs.width || 0);\n                            }\n                        case \"rx\":\n                            if (att == \"rx\" && o.type == \"rect\") {\n                                break;\n                            }\n                        case \"cx\":\n                            rotxy && (att == \"x\" || att == \"cx\") && (rotxy[1] += value - attrs[att]);\n                            node[setAttribute](att, round(value));\n                            o.pattern && updatePosition(o);\n                            break;\n                        case \"height\":\n                            node[setAttribute](att, value);\n                            if (attrs.fy) {\n                                att = \"y\";\n                                value = attrs.y;\n                            } else {\n                                break;\n                            }\n                        case \"y\":\n                            if (attrs.fy) {\n                                value = -attrs.y - (attrs.height || 0);\n                            }\n                        case \"ry\":\n                            if (att == \"ry\" && o.type == \"rect\") {\n                                break;\n                            }\n                        case \"cy\":\n                            rotxy && (att == \"y\" || att == \"cy\") && (rotxy[2] += value - attrs[att]);\n                            node[setAttribute](att, round(value));\n                            o.pattern && updatePosition(o);\n                            break;\n                        case \"r\":\n                            if (o.type == \"rect\") {\n                                $(node, {rx: value, ry: value});\n                            } else {\n                                node[setAttribute](att, value);\n                            }\n                            break;\n                        case \"src\":\n                            if (o.type == \"image\") {\n                                node.setAttributeNS(o.paper.xlink, \"href\", value);\n                            }\n                            break;\n                        case \"stroke-width\":\n                            node.style.strokeWidth = value;\n                            // Need following line for Firefox\n                            node[setAttribute](att, value);\n                            if (attrs[\"stroke-dasharray\"]) {\n                                addDashes(o, attrs[\"stroke-dasharray\"]);\n                            }\n                            break;\n                        case \"stroke-dasharray\":\n                            addDashes(o, value);\n                            break;\n                        case \"translation\":\n                            var xy = (value + E)[split](separator);\n                            xy[0] = +xy[0] || 0;\n                            xy[1] = +xy[1] || 0;\n                            if (rotxy) {\n                                rotxy[1] += xy[0];\n                                rotxy[2] += xy[1];\n                            }\n                            translate.call(o, xy[0], xy[1]);\n                            break;\n                        case \"scale\":\n                            xy = (value + E)[split](separator);\n                            o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, isNaN(toFloat(xy[2])) ? null : +xy[2], isNaN(toFloat(xy[3])) ? null : +xy[3]);\n                            break;\n                        case \"fill\":\n                            var isURL = (value + E).match(ISURL);\n                            if (isURL) {\n                                el = $(\"pattern\");\n                                var ig = $(\"image\");\n                                el.id = \"r\" + (R._id++)[toString](36);\n                                $(el, {x: 0, y: 0, patternUnits: \"userSpaceOnUse\", height: 1, width: 1});\n                                $(ig, {x: 0, y: 0});\n                                ig.setAttributeNS(o.paper.xlink, \"href\", isURL[1]);\n                                el[appendChild](ig);\n \n                                var img = doc.createElement(\"img\");\n                                img.style.cssText = \"position:absolute;left:-9999em;top-9999em\";\n                                img.onload = function () {\n                                    $(el, {width: this.offsetWidth, height: this.offsetHeight});\n                                    $(ig, {width: this.offsetWidth, height: this.offsetHeight});\n                                    doc.body.removeChild(this);\n                                    o.paper.safari();\n                                };\n                                doc.body[appendChild](img);\n                                img.src = isURL[1];\n                                o.paper.defs[appendChild](el);\n                                node.style.fill = \"url(#\" + el.id + \")\";\n                                $(node, {fill: \"url(#\" + el.id + \")\"});\n                                o.pattern = el;\n                                o.pattern && updatePosition(o);\n                                break;\n                            }\n                            if (!R.getRGB(value).error) {\n                                delete params.gradient;\n                                delete attrs.gradient;\n                                !R.is(attrs.opacity, \"undefined\") &&\n                                    R.is(params.opacity, \"undefined\") &&\n                                    $(node, {opacity: attrs.opacity});\n                                !R.is(attrs[\"fill-opacity\"], \"undefined\") &&\n                                    R.is(params[\"fill-opacity\"], \"undefined\") &&\n                                    $(node, {\"fill-opacity\": attrs[\"fill-opacity\"]});\n                            } else if ((({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != \"r\") && addGradientFill(node, value, o.paper)) {\n                                attrs.gradient = value;\n                                attrs.fill = \"none\";\n                                break;\n                            }\n                        case \"stroke\":\n                            node[setAttribute](att, R.getRGB(value).hex);\n                            break;\n                        case \"gradient\":\n                            (({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != \"r\") && addGradientFill(node, value, o.paper);\n                            break;\n                        case \"opacity\":\n                        case \"fill-opacity\":\n                            if (attrs.gradient) {\n                                var gradient = doc.getElementById(node.getAttribute(\"fill\")[rp](/^url\\(#|\\)$/g, E));\n                                if (gradient) {\n                                    var stops = gradient.getElementsByTagName(\"stop\");\n                                    stops[stops[length] - 1][setAttribute](\"stop-opacity\", value);\n                                }\n                                break;\n                            }\n                        default:\n                            att == \"font-size\" && (value = toInt(value, 10) + \"px\");\n                            var cssrule = att[rp](/(\\-.)/g, function (w) {\n                                return upperCase.call(w.substring(1));\n                            });\n                            node.style[cssrule] = value;\n                            // Need following line for Firefox\n                            node[setAttribute](att, value);\n                            break;\n                    }\n                }\n            }\n            \n            tuneText(o, params);\n            if (rotxy) {\n                o.rotate(rotxy.join(S));\n            } else {\n                toFloat(rot) && o.rotate(rot, true);\n            }\n        };\n        var leading = 1.2,\n        tuneText = function (el, params) {\n            if (el.type != \"text\" || !(params[has](\"text\") || params[has](\"font\") || params[has](\"font-size\") || params[has](\"x\") || params[has](\"y\"))) {\n                return;\n            }\n            var a = el.attrs,\n                node = el.node,\n                fontSize = node.firstChild ? toInt(doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue(\"font-size\"), 10) : 10;\n \n            if (params[has](\"text\")) {\n                a.text = params.text;\n                while (node.firstChild) {\n                    node.removeChild(node.firstChild);\n                }\n                var texts = (params.text + E)[split](\"\\n\");\n                for (var i = 0, ii = texts[length]; i < ii; i++) if (texts[i]) {\n                    var tspan = $(\"tspan\");\n                    i && $(tspan, {dy: fontSize * leading, x: a.x});\n                    tspan[appendChild](doc.createTextNode(texts[i]));\n                    node[appendChild](tspan);\n                }\n            } else {\n                texts = node.getElementsByTagName(\"tspan\");\n                for (i = 0, ii = texts[length]; i < ii; i++) {\n                    i && $(texts[i], {dy: fontSize * leading, x: a.x});\n                }\n            }\n            $(node, {y: a.y});\n            var bb = el.getBBox(),\n                dif = a.y - (bb.y + bb.height / 2);\n            dif && isFinite(dif) && $(node, {y: a.y + dif});\n        },\n        Element = function (node, svg) {\n            var X = 0,\n                Y = 0;\n            this[0] = node;\n            this.id = R._oid++;\n            this.node = node;\n            node.raphael = this;\n            this.paper = svg;\n            this.attrs = this.attrs || {};\n            this.transformations = []; // rotate, translate, scale\n            this._ = {\n                tx: 0,\n                ty: 0,\n                rt: {deg: 0, cx: 0, cy: 0},\n                sx: 1,\n                sy: 1\n            };\n            !svg.bottom && (svg.bottom = this);\n            this.prev = svg.top;\n            svg.top && (svg.top.next = this);\n            svg.top = this;\n            this.next = null;\n        };\n        Element[proto].rotate = function (deg, cx, cy) {\n            if (this.removed) {\n                return this;\n            }\n            if (deg == null) {\n                if (this._.rt.cx) {\n                    return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S);\n                }\n                return this._.rt.deg;\n            }\n            var bbox = this.getBBox();\n            deg = (deg + E)[split](separator);\n            if (deg[length] - 1) {\n                cx = toFloat(deg[1]);\n                cy = toFloat(deg[2]);\n            }\n            deg = toFloat(deg[0]);\n            if (cx != null) {\n                this._.rt.deg = deg;\n            } else {\n                this._.rt.deg += deg;\n            }\n            (cy == null) && (cx = null);\n            this._.rt.cx = cx;\n            this._.rt.cy = cy;\n            cx = cx == null ? bbox.x + bbox.width / 2 : cx;\n            cy = cy == null ? bbox.y + bbox.height / 2 : cy;\n            if (this._.rt.deg) {\n                this.transformations[0] = R.format(\"rotate({0} {1} {2})\", this._.rt.deg, cx, cy);\n                this.clip && $(this.clip, {transform: R.format(\"rotate({0} {1} {2})\", -this._.rt.deg, cx, cy)});\n            } else {\n                this.transformations[0] = E;\n                this.clip && $(this.clip, {transform: E});\n            }\n            $(this.node, {transform: this.transformations[join](S)});\n            return this;\n        };\n        Element[proto].hide = function () {\n            !this.removed && (this.node.style.display = \"none\");\n            return this;\n        };\n        Element[proto].show = function () {\n            !this.removed && (this.node.style.display = \"\");\n            return this;\n        };\n        Element[proto].remove = function () {\n            if (this.removed) {\n                return;\n            }\n            tear(this, this.paper);\n            this.node.parentNode.removeChild(this.node);\n            for (var i in this) {\n                delete this[i];\n            }\n            this.removed = true;\n        };\n        Element[proto].getBBox = function () {\n            if (this.removed) {\n                return this;\n            }\n            if (this.type == \"path\") {\n                return pathDimensions(this.attrs.path);\n            }\n            if (this.node.style.display == \"none\") {\n                this.show();\n                var hide = true;\n            }\n            var bbox = {};\n            try {\n                bbox = this.node.getBBox();\n            } catch(e) {\n                // Firefox 3.0.x plays badly here\n            } finally {\n                bbox = bbox || {};\n            }\n            if (this.type == \"text\") {\n                bbox = {x: bbox.x, y: Infinity, width: 0, height: 0};\n                for (var i = 0, ii = this.node.getNumberOfChars(); i < ii; i++) {\n                    var bb = this.node.getExtentOfChar(i);\n                    (bb.y < bbox.y) && (bbox.y = bb.y);\n                    (bb.y + bb.height - bbox.y > bbox.height) && (bbox.height = bb.y + bb.height - bbox.y);\n                    (bb.x + bb.width - bbox.x > bbox.width) && (bbox.width = bb.x + bb.width - bbox.x);\n                }\n            }\n            hide && this.hide();\n            return bbox;\n        };\n        Element[proto].attr = function (name, value) {\n            if (this.removed) {\n                return this;\n            }\n            if (name == null) {\n                var res = {};\n                for (var i in this.attrs) if (this.attrs[has](i)) {\n                    res[i] = this.attrs[i];\n                }\n                this._.rt.deg && (res.rotation = this.rotate());\n                (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale());\n                res.gradient && res.fill == \"none\" && (res.fill = res.gradient) && delete res.gradient;\n                return res;\n            }\n            if (value == null && R.is(name, \"string\")) {\n                if (name == \"translation\") {\n                    return translate.call(this);\n                }\n                if (name == \"rotation\") {\n                    return this.rotate();\n                }\n                if (name == \"scale\") {\n                    return this.scale();\n                }\n                if (name == \"fill\" && this.attrs.fill == \"none\" && this.attrs.gradient) {\n                    return this.attrs.gradient;\n                }\n                return this.attrs[name];\n            }\n            if (value == null && R.is(name, \"array\")) {\n                var values = {};\n                for (var j = 0, jj = name.length; j < jj; j++) {\n                    values[name[j]] = this.attr(name[j]);\n                }\n                return values;\n            }\n            if (value != null) {\n                var params = {};\n                params[name] = value;\n                setFillAndStroke(this, params);\n            } else if (name != null && R.is(name, \"object\")) {\n                setFillAndStroke(this, name);\n            }\n            return this;\n        };\n        Element[proto].toFront = function () {\n            if (this.removed) {\n                return this;\n            }\n            this.node.parentNode[appendChild](this.node);\n            var svg = this.paper;\n            svg.top != this && tofront(this, svg);\n            return this;\n        };\n        Element[proto].toBack = function () {\n            if (this.removed) {\n                return this;\n            }\n            if (this.node.parentNode.firstChild != this.node) {\n                this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);\n                toback(this, this.paper);\n                var svg = this.paper;\n            }\n            return this;\n        };\n        Element[proto].insertAfter = function (element) {\n            if (this.removed) {\n                return this;\n            }\n            var node = element.node;\n            if (node.nextSibling) {\n                node.parentNode.insertBefore(this.node, node.nextSibling);\n            } else {\n                node.parentNode[appendChild](this.node);\n            }\n            insertafter(this, element, this.paper);\n            return this;\n        };\n        Element[proto].insertBefore = function (element) {\n            if (this.removed) {\n                return this;\n            }\n            var node = element.node;\n            node.parentNode.insertBefore(this.node, node);\n            insertbefore(this, element, this.paper);\n            return this;\n        };\n        Element[proto].blur = function (size) {\n            // Experimental. No Safari support. Use it on your own risk.\n            var t = this;\n            if (+size !== 0) {\n                var fltr = $(\"filter\"),\n                    blur = $(\"feGaussianBlur\");\n                t.attrs.blur = size;\n                fltr.id = \"r\" + (R._id++)[toString](36);\n                $(blur, {stdDeviation: +size || 1.5});\n                fltr.appendChild(blur);\n                t.paper.defs.appendChild(fltr);\n                t._blur = fltr;\n                $(t.node, {filter: \"url(#\" + fltr.id + \")\"});\n            } else {\n                if (t._blur) {\n                    t._blur.parentNode.removeChild(t._blur);\n                    delete t._blur;\n                    delete t.attrs.blur;\n                }\n                t.node.removeAttribute(\"filter\");\n            }\n        };\n        var theCircle = function (svg, x, y, r) {\n            x = round(x);\n            y = round(y);\n            var el = $(\"circle\");\n            svg.canvas && svg.canvas[appendChild](el);\n            var res = new Element(el, svg);\n            res.attrs = {cx: x, cy: y, r: r, fill: \"none\", stroke: \"#000\"};\n            res.type = \"circle\";\n            $(el, res.attrs);\n            return res;\n        };\n        var theRect = function (svg, x, y, w, h, r) {\n            x = round(x);\n            y = round(y);\n            var el = $(\"rect\");\n            svg.canvas && svg.canvas[appendChild](el);\n            var res = new Element(el, svg);\n            res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: \"none\", stroke: \"#000\"};\n            res.type = \"rect\";\n            $(el, res.attrs);\n            return res;\n        };\n        var theEllipse = function (svg, x, y, rx, ry) {\n            x = round(x);\n            y = round(y);\n            var el = $(\"ellipse\");\n            svg.canvas && svg.canvas[appendChild](el);\n            var res = new Element(el, svg);\n            res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: \"none\", stroke: \"#000\"};\n            res.type = \"ellipse\";\n            $(el, res.attrs);\n            return res;\n        };\n        var theImage = function (svg, src, x, y, w, h) {\n            var el = $(\"image\");\n            $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: \"none\"});\n            el.setAttributeNS(svg.xlink, \"href\", src);\n            svg.canvas && svg.canvas[appendChild](el);\n            var res = new Element(el, svg);\n            res.attrs = {x: x, y: y, width: w, height: h, src: src};\n            res.type = \"image\";\n            return res;\n        };\n        var theText = function (svg, x, y, text) {\n            var el = $(\"text\");\n            $(el, {x: x, y: y, \"text-anchor\": \"middle\"});\n            svg.canvas && svg.canvas[appendChild](el);\n            var res = new Element(el, svg);\n            res.attrs = {x: x, y: y, \"text-anchor\": \"middle\", text: text, font: availableAttrs.font, stroke: \"none\", fill: \"#000\"};\n            res.type = \"text\";\n            setFillAndStroke(res, res.attrs);\n            return res;\n        };\n        var setSize = function (width, height) {\n            this.width = width || this.width;\n            this.height = height || this.height;\n            this.canvas[setAttribute](\"width\", this.width);\n            this.canvas[setAttribute](\"height\", this.height);\n            return this;\n        };\n        var create = function () {\n            var con = getContainer[apply](0, arguments),\n                container = con && con.container,\n                x = con.x,\n                y = con.y,\n                width = con.width,\n                height = con.height;\n            if (!container) {\n                throw new Error(\"SVG container not found.\");\n            }\n            var cnvs = $(\"svg\");\n            width = width || 512;\n            height = height || 342;\n            $(cnvs, {\n                xmlns: \"http://www.w3.org/2000/svg\",\n                version: 1.1,\n                width: width,\n                height: height\n            });\n            if (container == 1) {\n                cnvs.style.cssText = \"position:absolute;left:\" + x + \"px;top:\" + y + \"px\";\n                doc.body[appendChild](cnvs);\n            } else {\n                if (container.firstChild) {\n                    container.insertBefore(cnvs, container.firstChild);\n                } else {\n                    container[appendChild](cnvs);\n                }\n            }\n            container = new Paper;\n            container.width = width;\n            container.height = height;\n            container.canvas = cnvs;\n            plugins.call(container, container, R.fn);\n            container.clear();\n            return container;\n        };\n        Paper[proto].clear = function () {\n            var c = this.canvas;\n            while (c.firstChild) {\n                c.removeChild(c.firstChild);\n            }\n            this.bottom = this.top = null;\n            (this.desc = $(\"desc\"))[appendChild](doc.createTextNode(\"Created with Rapha\\xebl\"));\n            c[appendChild](this.desc);\n            c[appendChild](this.defs = $(\"defs\"));\n        };\n        Paper[proto].remove = function () {\n            this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);\n            for (var i in this) {\n                this[i] = removed(i);\n            }\n        };\n    }\n\n    // VML\n    if (R.vml) {\n        var map = {M: \"m\", L: \"l\", C: \"c\", Z: \"x\", m: \"t\", l: \"r\", c: \"v\", z: \"x\"},\n            bites = /([clmz]),?([^clmz]*)/gi,\n            val = /-?[^,\\s-]+/g,\n            coordsize = 1e3 + S + 1e3,\n            zoom = 10,\n            path2vml = function (path) {\n                var total =  /[ahqstv]/ig,\n                    command = pathToAbsolute;\n                (path + E).match(total) && (command = path2curve);\n                total = /[clmz]/g;\n                if (command == pathToAbsolute && !(path + E).match(total)) {\n                    var res = (path + E)[rp](bites, function (all, command, args) {\n                        var vals = [],\n                            isMove = lowerCase.call(command) == \"m\",\n                            res = map[command];\n                        args[rp](val, function (value) {\n                            if (isMove && vals[length] == 2) {\n                                res += vals + map[command == \"m\" ? \"l\" : \"L\"];\n                                vals = [];\n                            }\n                            vals[push](round(value * zoom));\n                        });\n                        return res + vals;\n                    });\n                    return res;\n                }\n                var pa = command(path), p, r;\n                res = [];\n                for (var i = 0, ii = pa[length]; i < ii; i++) {\n                    p = pa[i];\n                    r = lowerCase.call(pa[i][0]);\n                    r == \"z\" && (r = \"x\");\n                    for (var j = 1, jj = p[length]; j < jj; j++) {\n                        r += round(p[j] * zoom) + (j != jj - 1 ? \",\" : E);\n                    }\n                    res[push](r);\n                }\n                return res[join](S);\n            };\n        \n        R[toString] = function () {\n            return  \"Your browser doesn\\u2019t support SVG. Falling down to VML.\\nYou are running Rapha\\xebl \" + this.version;\n        };\n        thePath = function (pathString, vml) {\n            var g = createNode(\"group\");\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = vml.coordsize;\n            g.coordorigin = vml.coordorigin;\n            var el = createNode(\"shape\"), ol = el.style;\n            ol.width = vml.width + \"px\";\n            ol.height = vml.height + \"px\";\n            el.coordsize = coordsize;\n            el.coordorigin = vml.coordorigin;\n            g[appendChild](el);\n            var p = new Element(el, g, vml),\n                attr = {fill: \"none\", stroke: \"#000\"};\n            pathString && (attr.path = pathString);\n            p.isAbsolute = true;\n            p.type = \"path\";\n            p.path = [];\n            p.Path = E;\n            setFillAndStroke(p, attr);\n            vml.canvas[appendChild](g);\n            return p;\n        };\n        setFillAndStroke = function (o, params) {\n            o.attrs = o.attrs || {};\n            var node = o.node,\n                a = o.attrs,\n                s = node.style,\n                xy,\n                res = o;\n            for (var par in params) if (params[has](par)) {\n                a[par] = params[par];\n            }\n            params.href && (node.href = params.href);\n            params.title && (node.title = params.title);\n            params.target && (node.target = params.target);\n            params.cursor && (s.cursor = params.cursor);\n            \"blur\" in params && o.blur(params.blur);\n            if (params.path && o.type == \"path\") {\n                a.path = params.path;\n                node.path = path2vml(a.path);\n            }\n            if (params.rotation != null) {\n                o.rotate(params.rotation, true);\n            }\n            if (params.translation) {\n                xy = (params.translation + E)[split](separator);\n                translate.call(o, xy[0], xy[1]);\n                if (o._.rt.cx != null) {\n                    o._.rt.cx +=+ xy[0];\n                    o._.rt.cy +=+ xy[1];\n                    o.setBox(o.attrs, xy[0], xy[1]);\n                }\n            }\n            if (params.scale) {\n                xy = (params.scale + E)[split](separator);\n                o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null);\n            }\n            if (\"clip-rect\" in params) {\n                var rect = (params[\"clip-rect\"] + E)[split](separator);\n                if (rect[length] == 4) {\n                    rect[2] = +rect[2] + (+rect[0]);\n                    rect[3] = +rect[3] + (+rect[1]);\n                    var div = node.clipRect || doc.createElement(\"div\"),\n                        dstyle = div.style,\n                        group = node.parentNode;\n                    dstyle.clip = R.format(\"rect({1}px {2}px {3}px {0}px)\", rect);\n                    if (!node.clipRect) {\n                        dstyle.position = \"absolute\";\n                        dstyle.top = 0;\n                        dstyle.left = 0;\n                        dstyle.width = o.paper.width + \"px\";\n                        dstyle.height = o.paper.height + \"px\";\n                        group.parentNode.insertBefore(div, group);\n                        div[appendChild](group);\n                        node.clipRect = div;\n                    }\n                }\n                if (!params[\"clip-rect\"]) {\n                    node.clipRect && (node.clipRect.style.clip = E);\n                }\n            }\n            if (o.type == \"image\" && params.src) {\n                node.src = params.src;\n            }\n            if (o.type == \"image\" && params.opacity) {\n                node.filterOpacity = \" progid:DXImageTransform.Microsoft.Alpha(opacity=\" + (params.opacity * 100) + \")\";\n                s.filter = (node.filterMatrix || E) + (node.filterOpacity || E);\n            }\n            params.font && (s.font = params.font);\n            params[\"font-family\"] && (s.fontFamily = '\"' + params[\"font-family\"][split](\",\")[0][rp](/^['\"]+|['\"]+$/g, E) + '\"'); //'\n            params[\"font-size\"] && (s.fontSize = params[\"font-size\"]);\n            params[\"font-weight\"] && (s.fontWeight = params[\"font-weight\"]);\n            params[\"font-style\"] && (s.fontStyle = params[\"font-style\"]);\n            if (params.opacity != null || \n                params[\"stroke-width\"] != null ||\n                params.fill != null ||\n                params.stroke != null ||\n                params[\"stroke-width\"] != null ||\n                params[\"stroke-opacity\"] != null ||\n                params[\"fill-opacity\"] != null ||\n                params[\"stroke-dasharray\"] != null ||\n                params[\"stroke-miterlimit\"] != null ||\n                params[\"stroke-linejoin\"] != null ||\n                params[\"stroke-linecap\"] != null) {\n                node = o.shape || node;\n                var fill = (node.getElementsByTagName(\"fill\") && node.getElementsByTagName(\"fill\")[0]),\n                    newfill = false;\n                !fill && (newfill = fill = createNode(\"fill\"));\n                if (\"fill-opacity\" in params || \"opacity\" in params) {\n                    var opacity = ((+a[\"fill-opacity\"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1);\n                    opacity < 0 && (opacity = 0);\n                    opacity > 1 && (opacity = 1);\n                    fill.opacity = opacity;\n                }\n                params.fill && (fill.on = true);\n                if (fill.on == null || params.fill == \"none\") {\n                    fill.on = false;\n                }\n                if (fill.on && params.fill) {\n                    var isURL = params.fill.match(ISURL);\n                    if (isURL) {\n                        fill.src = isURL[1];\n                        fill.type = \"tile\";\n                    } else {\n                        fill.color = R.getRGB(params.fill).hex;\n                        fill.src = E;\n                        fill.type = \"solid\";\n                        if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || (params.fill + E).charAt() != \"r\") && addGradientFill(res, params.fill)) {\n                            a.fill = \"none\";\n                            a.gradient = params.fill;\n                        }\n                    }\n                }\n                newfill && node[appendChild](fill);\n                var stroke = (node.getElementsByTagName(\"stroke\") && node.getElementsByTagName(\"stroke\")[0]),\n                newstroke = false;\n                !stroke && (newstroke = stroke = createNode(\"stroke\"));\n                if ((params.stroke && params.stroke != \"none\") ||\n                    params[\"stroke-width\"] ||\n                    params[\"stroke-opacity\"] != null ||\n                    params[\"stroke-dasharray\"] ||\n                    params[\"stroke-miterlimit\"] ||\n                    params[\"stroke-linejoin\"] ||\n                    params[\"stroke-linecap\"]) {\n                    stroke.on = true;\n                }\n                (params.stroke == \"none\" || stroke.on == null || params.stroke == 0 || params[\"stroke-width\"] == 0) && (stroke.on = false);\n                stroke.on && params.stroke && (stroke.color = R.getRGB(params.stroke).hex);\n                opacity = ((+a[\"stroke-opacity\"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1);\n                var width = (toFloat(params[\"stroke-width\"]) || 1) * .75;\n                opacity < 0 && (opacity = 0);\n                opacity > 1 && (opacity = 1);\n                params[\"stroke-width\"] == null && (width = a[\"stroke-width\"]);\n                params[\"stroke-width\"] && (stroke.weight = width);\n                width && width < 1 && (opacity *= width) && (stroke.weight = 1);\n                stroke.opacity = opacity;\n                \n                params[\"stroke-linejoin\"] && (stroke.joinstyle = params[\"stroke-linejoin\"] || \"miter\");\n                stroke.miterlimit = params[\"stroke-miterlimit\"] || 8;\n                params[\"stroke-linecap\"] && (stroke.endcap = params[\"stroke-linecap\"] == \"butt\" ? \"flat\" : params[\"stroke-linecap\"] == \"square\" ? \"square\" : \"round\");\n                if (params[\"stroke-dasharray\"]) {\n                    var dasharray = {\n                        \"-\": \"shortdash\",\n                        \".\": \"shortdot\",\n                        \"-.\": \"shortdashdot\",\n                        \"-..\": \"shortdashdotdot\",\n                        \". \": \"dot\",\n                        \"- \": \"dash\",\n                        \"--\": \"longdash\",\n                        \"- .\": \"dashdot\",\n                        \"--.\": \"longdashdot\",\n                        \"--..\": \"longdashdotdot\"\n                    };\n                    stroke.dashstyle = dasharray[has](params[\"stroke-dasharray\"]) ? dasharray[params[\"stroke-dasharray\"]] : E;\n                }\n                newstroke && node[appendChild](stroke);\n            }\n            if (res.type == \"text\") {\n                s = res.paper.span.style;\n                a.font && (s.font = a.font);\n                a[\"font-family\"] && (s.fontFamily = a[\"font-family\"]);\n                a[\"font-size\"] && (s.fontSize = a[\"font-size\"]);\n                a[\"font-weight\"] && (s.fontWeight = a[\"font-weight\"]);\n                a[\"font-style\"] && (s.fontStyle = a[\"font-style\"]);\n                res.node.string && (res.paper.span.innerHTML = (res.node.string + E)[rp](/</g, \"&#60;\")[rp](/&/g, \"&#38;\")[rp](/\\n/g, \"<br>\"));\n                res.W = a.w = res.paper.span.offsetWidth;\n                res.H = a.h = res.paper.span.offsetHeight;\n                res.X = a.x;\n                res.Y = a.y + round(res.H / 2);\n \n                // text-anchor emulationm\n                switch (a[\"text-anchor\"]) {\n                    case \"start\":\n                        res.node.style[\"v-text-align\"] = \"left\";\n                        res.bbx = round(res.W / 2);\n                    break;\n                    case \"end\":\n                        res.node.style[\"v-text-align\"] = \"right\";\n                        res.bbx = -round(res.W / 2);\n                    break;\n                    default:\n                        res.node.style[\"v-text-align\"] = \"center\";\n                    break;\n                }\n            }\n        };\n        addGradientFill = function (o, gradient) {\n            o.attrs = o.attrs || {};\n            var attrs = o.attrs,\n                fill = o.node.getElementsByTagName(\"fill\"),\n                type = \"linear\",\n                fxfy = \".5 .5\";\n            o.attrs.gradient = gradient;\n            gradient = (gradient + E)[rp](radial_gradient, function (all, fx, fy) {\n                type = \"radial\";\n                if (fx && fy) {\n                    fx = toFloat(fx);\n                    fy = toFloat(fy);\n                    pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);\n                    fxfy = fx + S + fy;\n                }\n                return E;\n            });\n            gradient = gradient[split](/\\s*\\-\\s*/);\n            if (type == \"linear\") {\n                var angle = gradient.shift();\n                angle = -toFloat(angle);\n                if (isNaN(angle)) {\n                    return null;\n                }\n            }\n            var dots = parseDots(gradient);\n            if (!dots) {\n                return null;\n            }\n            o = o.shape || o.node;\n            fill = fill[0] || createNode(\"fill\");\n            if (dots[length]) {\n                fill.on = true;\n                fill.method = \"none\";\n                fill.type = (type == \"radial\") ? \"gradientradial\" : \"gradient\";\n                fill.color = dots[0].color;\n                fill.color2 = dots[dots[length] - 1].color;\n                var clrs = [];\n                for (var i = 0, ii = dots[length]; i < ii; i++) {\n                    dots[i].offset && clrs[push](dots[i].offset + S + dots[i].color);\n                }\n                fill.colors && (fill.colors.value = clrs[length] ? clrs[join](\",\") : \"0% \" + fill.color);\n                if (type == \"radial\") {\n                    fill.focus = \"100%\";\n                    fill.focussize = fxfy;\n                    fill.focusposition = fxfy;\n                } else {\n                    fill.angle = (270 - angle) % 360;\n                }\n            }\n            return 1;\n        };\n        Element = function (node, group, vml) {\n            var Rotation = 0,\n                RotX = 0,\n                RotY = 0,\n                Scale = 1;\n            this[0] = node;\n            this.id = R._oid++;\n            this.node = node;\n            node.raphael = this;\n            this.X = 0;\n            this.Y = 0;\n            this.attrs = {};\n            this.Group = group;\n            this.paper = vml;\n            this._ = {\n                tx: 0,\n                ty: 0,\n                rt: {deg:0},\n                sx: 1,\n                sy: 1\n            };\n            !vml.bottom && (vml.bottom = this);\n            this.prev = vml.top;\n            vml.top && (vml.top.next = this);\n            vml.top = this;\n            this.next = null;\n        };\n        Element[proto].rotate = function (deg, cx, cy) {\n            if (this.removed) {\n                return this;\n            }\n            if (deg == null) {\n                if (this._.rt.cx) {\n                    return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S);\n                }\n                return this._.rt.deg;\n            }\n            deg = (deg + E)[split](separator);\n            if (deg[length] - 1) {\n                cx = toFloat(deg[1]);\n                cy = toFloat(deg[2]);\n            }\n            deg = toFloat(deg[0]);\n            if (cx != null) {\n                this._.rt.deg = deg;\n            } else {\n                this._.rt.deg += deg;\n            }\n            cy == null && (cx = null);\n            this._.rt.cx = cx;\n            this._.rt.cy = cy;\n            this.setBox(this.attrs, cx, cy);\n            this.Group.style.rotation = this._.rt.deg;\n            // gradient fix for rotation. TODO\n            // var fill = (this.shape || this.node).getElementsByTagName(\"fill\");\n            // fill = fill[0] || {};\n            // var b = ((360 - this._.rt.deg) - 270) % 360;\n            // !R.is(fill.angle, \"undefined\") && (fill.angle = b);\n            return this;\n        };\n        Element[proto].setBox = function (params, cx, cy) {\n            if (this.removed) {\n                return this;\n            }\n            var gs = this.Group.style,\n                os = (this.shape && this.shape.style) || this.node.style;\n            params = params || {};\n            for (var i in params) if (params[has](i)) {\n                this.attrs[i] = params[i];\n            }\n            cx = cx || this._.rt.cx;\n            cy = cy || this._.rt.cy;\n            var attr = this.attrs,\n                x,\n                y,\n                w,\n                h;\n            switch (this.type) {\n                case \"circle\":\n                    x = attr.cx - attr.r;\n                    y = attr.cy - attr.r;\n                    w = h = attr.r * 2;\n                    break;\n                case \"ellipse\":\n                    x = attr.cx - attr.rx;\n                    y = attr.cy - attr.ry;\n                    w = attr.rx * 2;\n                    h = attr.ry * 2;\n                    break;\n                case \"rect\":\n                case \"image\":\n                    x = +attr.x;\n                    y = +attr.y;\n                    w = attr.width || 0;\n                    h = attr.height || 0;\n                    break;\n                case \"text\":\n                    this.textpath.v = [\"m\", round(attr.x), \", \", round(attr.y - 2), \"l\", round(attr.x) + 1, \", \", round(attr.y - 2)][join](E);\n                    x = attr.x - round(this.W / 2);\n                    y = attr.y - this.H / 2;\n                    w = this.W;\n                    h = this.H;\n                    break;\n                case \"path\":\n                    if (!this.attrs.path) {\n                        x = 0;\n                        y = 0;\n                        w = this.paper.width;\n                        h = this.paper.height;\n                    } else {\n                        var dim = pathDimensions(this.attrs.path);\n                        x = dim.x;\n                        y = dim.y;\n                        w = dim.width;\n                        h = dim.height;\n                    }\n                    break;\n                default:\n                    x = 0;\n                    y = 0;\n                    w = this.paper.width;\n                    h = this.paper.height;\n                    break;\n            }\n            cx = (cx == null) ? x + w / 2 : cx;\n            cy = (cy == null) ? y + h / 2 : cy;\n            var left = cx - this.paper.width / 2,\n                top = cy - this.paper.height / 2, t;\n            gs.left != (t = left + \"px\") && (gs.left = t);\n            gs.top != (t = top + \"px\") && (gs.top = t);\n            this.X = this.type == \"path\" ? -left : x;\n            this.Y = this.type == \"path\" ? -top : y;\n            this.W = w;\n            this.H = h;\n            if (this.type == \"path\") {\n                os.left != (t = -left * zoom + \"px\") && (os.left = t);\n                os.top != (t = -top * zoom + \"px\") && (os.top = t);\n            } else if (this.type == \"text\") {\n                os.left != (t = -left + \"px\") && (os.left = t);\n                os.top != (t = -top + \"px\") && (os.top = t);\n            } else {\n                gs.width != (t = this.paper.width + \"px\") && (gs.width = t);\n                gs.height != (t = this.paper.height + \"px\") && (gs.height = t);\n                os.left != (t = x - left + \"px\") && (os.left = t);\n                os.top != (t = y - top + \"px\") && (os.top = t);\n                os.width != (t = w + \"px\") && (os.width = t);\n                os.height != (t = h + \"px\") && (os.height = t);\n                var arcsize = (+params.r || 0) / mmin(w, h);\n                if (this.type == \"rect\" && this.arcsize.toFixed(4) != arcsize.toFixed(4) && (arcsize || this.arcsize)) {\n                    // We should replace element with the new one\n                    var o = createNode(\"roundrect\"),\n                        a = {},\n                        ii = this.events && this.events[length];\n                    i = 0;\n                    o.arcsize = arcsize;\n                    o.raphael = this;\n                    this.Group[appendChild](o);\n                    this.Group.removeChild(this.node);\n                    this[0] = this.node = o;\n                    this.arcsize = arcsize;\n                    for (i in attr) {\n                        a[i] = attr[i];\n                    }\n                    delete a.scale;\n                    this.attr(a);\n                    if (this.events) for (; i < ii; i++) {\n                        this.events[i].unbind = addEvent(this.node, this.events[i].name, this.events[i].f, this);\n                    }\n                }\n            }\n        };\n        Element[proto].hide = function () {\n            !this.removed && (this.Group.style.display = \"none\");\n            return this;\n        };\n        Element[proto].show = function () {\n            !this.removed && (this.Group.style.display = \"block\");\n            return this;\n        };\n        Element[proto].getBBox = function () {\n            if (this.removed) {\n                return this;\n            }\n            if (this.type == \"path\") {\n                return pathDimensions(this.attrs.path);\n            }\n            return {\n                x: this.X + (this.bbx || 0),\n                y: this.Y,\n                width: this.W,\n                height: this.H\n            };\n        };\n        Element[proto].remove = function () {\n            if (this.removed) {\n                return;\n            }\n            tear(this, this.paper);\n            this.node.parentNode.removeChild(this.node);\n            this.Group.parentNode.removeChild(this.Group);\n            this.shape && this.shape.parentNode.removeChild(this.shape);\n            for (var i in this) {\n                delete this[i];\n            }\n            this.removed = true;\n        };\n        Element[proto].attr = function (name, value) {\n            if (this.removed) {\n                return this;\n            }\n            if (name == null) {\n                var res = {};\n                for (var i in this.attrs) if (this.attrs[has](i)) {\n                    res[i] = this.attrs[i];\n                }\n                this._.rt.deg && (res.rotation = this.rotate());\n                (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale());\n                res.gradient && res.fill == \"none\" && (res.fill = res.gradient) && delete res.gradient;\n                return res;\n            }\n            if (value == null && R.is(name, \"string\")) {\n                if (name == \"translation\") {\n                    return translate.call(this);\n                }\n                if (name == \"rotation\") {\n                    return this.rotate();\n                }\n                if (name == \"scale\") {\n                    return this.scale();\n                }\n                if (name == \"fill\" && this.attrs.fill == \"none\" && this.attrs.gradient) {\n                    return this.attrs.gradient;\n                }\n                return this.attrs[name];\n            }\n            if (this.attrs && value == null && R.is(name, \"array\")) {\n                var ii, values = {};\n                for (i = 0, ii = name[length]; i < ii; i++) {\n                    values[name[i]] = this.attr(name[i]);\n                }\n                return values;\n            }\n            var params;\n            if (value != null) {\n                params = {};\n                params[name] = value;\n            }\n            value == null && R.is(name, \"object\") && (params = name);\n            if (params) {\n                if (params.text && this.type == \"text\") {\n                    this.node.string = params.text;\n                }\n                setFillAndStroke(this, params);\n                if (params.gradient && (({circle: 1, ellipse: 1})[has](this.type) || (params.gradient + E).charAt() != \"r\")) {\n                    addGradientFill(this, params.gradient);\n                }\n                (this.type != \"path\" || this._.rt.deg) && this.setBox(this.attrs);\n            }\n            return this;\n        };\n        Element[proto].toFront = function () {\n            !this.removed && this.Group.parentNode[appendChild](this.Group);\n            this.paper.top != this && tofront(this, this.paper);\n            return this;\n        };\n        Element[proto].toBack = function () {\n            if (this.removed) {\n                return this;\n            }\n            if (this.Group.parentNode.firstChild != this.Group) {\n                this.Group.parentNode.insertBefore(this.Group, this.Group.parentNode.firstChild);\n                toback(this, this.paper);\n            }\n            return this;\n        };\n        Element[proto].insertAfter = function (element) {\n            if (this.removed) {\n                return this;\n            }\n            if (element.Group.nextSibling) {\n                element.Group.parentNode.insertBefore(this.Group, element.Group.nextSibling);\n            } else {\n                element.Group.parentNode[appendChild](this.Group);\n            }\n            insertafter(this, element, this.paper);\n            return this;\n        };\n        Element[proto].insertBefore = function (element) {\n            if (this.removed) {\n                return this;\n            }\n            element.Group.parentNode.insertBefore(this.Group, element.Group);\n            insertbefore(this, element, this.paper);\n            return this;\n        };\n        var blurregexp = / progid:\\S+Blur\\([^\\)]+\\)/g;\n        Element[proto].blur = function (size) {\n            var s = this.node.style,\n                f = s.filter;\n            f = f.replace(blurregexp, \"\");\n            if (+size !== 0) {\n                this.attrs.blur = size;\n                s.filter = f + \" progid:DXImageTransform.Microsoft.Blur(pixelradius=\" + (+size || 1.5) + \")\";\n                s.margin = Raphael.format(\"-{0}px 0 0 -{0}px\", Math.round(+size || 1.5));\n            } else {\n                s.filter = f;\n                s.margin = 0;\n                delete this.attrs.blur;\n            }\n        };\n \n        theCircle = function (vml, x, y, r) {\n            var g = createNode(\"group\"),\n                o = createNode(\"oval\"),\n                ol = o.style;\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = coordsize;\n            g.coordorigin = vml.coordorigin;\n            g[appendChild](o);\n            var res = new Element(o, g, vml);\n            res.type = \"circle\";\n            setFillAndStroke(res, {stroke: \"#000\", fill: \"none\"});\n            res.attrs.cx = x;\n            res.attrs.cy = y;\n            res.attrs.r = r;\n            res.setBox({x: x - r, y: y - r, width: r * 2, height: r * 2});\n            vml.canvas[appendChild](g);\n            return res;\n        };\n        theRect = function (vml, x, y, w, h, r) {\n            var g = createNode(\"group\"),\n                o = createNode(\"roundrect\"),\n                arcsize = (+r || 0) / (mmin(w, h));\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = coordsize;\n            g.coordorigin = vml.coordorigin;\n            g[appendChild](o);\n            o.arcsize = arcsize;\n            var res = new Element(o, g, vml);\n            res.type = \"rect\";\n            setFillAndStroke(res, {stroke: \"#000\"});\n            res.arcsize = arcsize;\n            res.setBox({x: x, y: y, width: w, height: h, r: r});\n            vml.canvas[appendChild](g);\n            return res;\n        };\n        theEllipse = function (vml, x, y, rx, ry) {\n            var g = createNode(\"group\"),\n                o = createNode(\"oval\"),\n                ol = o.style;\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = coordsize;\n            g.coordorigin = vml.coordorigin;\n            g[appendChild](o);\n            var res = new Element(o, g, vml);\n            res.type = \"ellipse\";\n            setFillAndStroke(res, {stroke: \"#000\"});\n            res.attrs.cx = x;\n            res.attrs.cy = y;\n            res.attrs.rx = rx;\n            res.attrs.ry = ry;\n            res.setBox({x: x - rx, y: y - ry, width: rx * 2, height: ry * 2});\n            vml.canvas[appendChild](g);\n            return res;\n        };\n        theImage = function (vml, src, x, y, w, h) {\n            var g = createNode(\"group\"),\n                o = createNode(\"image\"),\n                ol = o.style;\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = coordsize;\n            g.coordorigin = vml.coordorigin;\n            o.src = src;\n            g[appendChild](o);\n            var res = new Element(o, g, vml);\n            res.type = \"image\";\n            res.attrs.src = src;\n            res.attrs.x = x;\n            res.attrs.y = y;\n            res.attrs.w = w;\n            res.attrs.h = h;\n            res.setBox({x: x, y: y, width: w, height: h});\n            vml.canvas[appendChild](g);\n            return res;\n        };\n        theText = function (vml, x, y, text) {\n            var g = createNode(\"group\"),\n                el = createNode(\"shape\"),\n                ol = el.style,\n                path = createNode(\"path\"),\n                ps = path.style,\n                o = createNode(\"textpath\");\n            g.style.cssText = \"position:absolute;left:0;top:0;width:\" + vml.width + \"px;height:\" + vml.height + \"px\";\n            g.coordsize = coordsize;\n            g.coordorigin = vml.coordorigin;\n            path.v = R.format(\"m{0},{1}l{2},{1}\", round(x * 10), round(y * 10), round(x * 10) + 1);\n            path.textpathok = true;\n            ol.width = vml.width;\n            ol.height = vml.height;\n            o.string = text + E;\n            o.on = true;\n            el[appendChild](o);\n            el[appendChild](path);\n            g[appendChild](el);\n            var res = new Element(o, g, vml);\n            res.shape = el;\n            res.textpath = path;\n            res.type = \"text\";\n            res.attrs.text = text;\n            res.attrs.x = x;\n            res.attrs.y = y;\n            res.attrs.w = 1;\n            res.attrs.h = 1;\n            setFillAndStroke(res, {font: availableAttrs.font, stroke: \"none\", fill: \"#000\"});\n            res.setBox();\n            vml.canvas[appendChild](g);\n            return res;\n        };\n        setSize = function (width, height) {\n            var cs = this.canvas.style;\n            width == +width && (width += \"px\");\n            height == +height && (height += \"px\");\n            cs.width = width;\n            cs.height = height;\n            cs.clip = \"rect(0 \" + width + \" \" + height + \" 0)\";\n            return this;\n        };\n        var createNode;\n        doc.createStyleSheet().addRule(\".rvml\", \"behavior:url(#default#VML)\");\n        try {\n            !doc.namespaces.rvml && doc.namespaces.add(\"rvml\", \"urn:schemas-microsoft-com:vml\");\n            createNode = function (tagName) {\n                return doc.createElement('<rvml:' + tagName + ' class=\"rvml\">');\n            };\n        } catch (e) {\n            createNode = function (tagName) {\n                return doc.createElement('<' + tagName + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"rvml\">');\n            };\n        }\n        create = function () {\n            var con = getContainer[apply](0, arguments),\n                container = con.container,\n                height = con.height,\n                s,\n                width = con.width,\n                x = con.x,\n                y = con.y;\n            if (!container) {\n                throw new Error(\"VML container not found.\");\n            }\n            var res = new Paper,\n                c = res.canvas = doc.createElement(\"div\"),\n                cs = c.style;\n            width = width || 512;\n            height = height || 342;\n            width == +width && (width += \"px\");\n            height == +height && (height += \"px\");\n            res.width = 1e3;\n            res.height = 1e3;\n            res.coordsize = zoom * 1e3 + S + zoom * 1e3;\n            res.coordorigin = \"0 0\";\n            res.span = doc.createElement(\"span\");\n            res.span.style.cssText = \"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;\";\n            c[appendChild](res.span);\n            cs.cssText = R.format(\"width:{0};height:{1};position:absolute;clip:rect(0 {0} {1} 0);overflow:hidden\", width, height);\n            if (container == 1) {\n                doc.body[appendChild](c);\n                cs.left = x + \"px\";\n                cs.top = y + \"px\";\n            } else {\n                container.style.width = width;\n                container.style.height = height;\n                if (container.firstChild) {\n                    container.insertBefore(c, container.firstChild);\n                } else {\n                    container[appendChild](c);\n                }\n            }\n            plugins.call(res, res, R.fn);\n            return res;\n        };\n        Paper[proto].clear = function () {\n            this.canvas.innerHTML = E;\n            this.span = doc.createElement(\"span\");\n            this.span.style.cssText = \"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;\";\n            this.canvas[appendChild](this.span);\n            this.bottom = this.top = null;\n        };\n        Paper[proto].remove = function () {\n            this.canvas.parentNode.removeChild(this.canvas);\n            for (var i in this) {\n                this[i] = removed(i);\n            }\n            return true;\n        };\n    }\n \n    // rest\n    // Safari or Chrome (WebKit) rendering bug workaround method\n    if ((/^Apple|^Google/).test(win.navigator.vendor) && !(win.navigator.userAgent.indexOf(\"Version/4.0\") + 1)) {\n        Paper[proto].safari = function () {\n            var rect = this.rect(-99, -99, this.width + 99, this.height + 99);\n            win.setTimeout(function () {rect.remove();});\n        };\n    } else {\n        Paper[proto].safari = function () {};\n    }\n \n    // Events\n    var addEvent = (function () {\n        if (doc.addEventListener) {\n            return function (obj, type, fn, element) {\n                var f = function (e) {\n                    return fn.call(element, e);\n                };\n                obj.addEventListener(type, f, false);\n                return function () {\n                    obj.removeEventListener(type, f, false);\n                    return true;\n                };\n            };\n        } else if (doc.attachEvent) {\n            return function (obj, type, fn, element) {\n                var f = function (e) {\n                    return fn.call(element, e || win.event);\n                };\n                obj.attachEvent(\"on\" + type, f);\n                var detacher = function () {\n                    obj.detachEvent(\"on\" + type, f);\n                    return true;\n                };\n                return detacher;\n            };\n        }\n    })();\n    for (var i = events[length]; i--;) {\n        (function (eventName) {\n            Element[proto][eventName] = function (fn) {\n                if (R.is(fn, \"function\")) {\n                    this.events = this.events || [];\n                    this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node, eventName, fn, this)});\n                }\n                return this;\n            };\n            Element[proto][\"un\" + eventName] = function (fn) {\n                var events = this.events,\n                    l = events[length];\n                while (l--) if (events[l].name == eventName && events[l].f == fn) {\n                    events[l].unbind();\n                    events.splice(l, 1);\n                    !events.length && delete this.events;\n                    return this;\n                }\n                return this;\n            };\n        })(events[i]);\n    }\n    Element[proto].hover = function (f_in, f_out) {\n        return this.mouseover(f_in).mouseout(f_out);\n    };\n    Element[proto].unhover = function (f_in, f_out) {\n        return this.unmouseover(f_in).unmouseout(f_out);\n    };\n    Paper[proto].circle = function (x, y, r) {\n        return theCircle(this, x || 0, y || 0, r || 0);\n    };\n    Paper[proto].rect = function (x, y, w, h, r) {\n        return theRect(this, x || 0, y || 0, w || 0, h || 0, r || 0);\n    };\n    Paper[proto].ellipse = function (x, y, rx, ry) {\n        return theEllipse(this, x || 0, y || 0, rx || 0, ry || 0);\n    };\n    Paper[proto].path = function (pathString) {\n        pathString && !R.is(pathString, \"string\") && !R.is(pathString[0], \"array\") && (pathString += E);\n        return thePath(R.format[apply](R, arguments), this);\n    };\n    Paper[proto].image = function (src, x, y, w, h) {\n        return theImage(this, src || \"about:blank\", x || 0, y || 0, w || 0, h || 0);\n    };\n    Paper[proto].text = function (x, y, text) {\n        return theText(this, x || 0, y || 0, text || E);\n    };\n    Paper[proto].set = function (itemsArray) {\n        arguments[length] > 1 && (itemsArray = Array[proto].splice.call(arguments, 0, arguments[length]));\n        return new Set(itemsArray);\n    };\n    Paper[proto].setSize = setSize;\n    Paper[proto].top = Paper[proto].bottom = null;\n    Paper[proto].raphael = R;\n    function x_y() {\n        return this.x + S + this.y;\n    }\n    Element[proto].scale = function (x, y, cx, cy) {\n        if (x == null && y == null) {\n            return {\n                x: this._.sx,\n                y: this._.sy,\n                toString: x_y\n            };\n        }\n        y = y || x;\n        !+y && (y = x);\n        var dx,\n            dy,\n            dcx,\n            dcy,\n            a = this.attrs;\n        if (x != 0) {\n            var bb = this.getBBox(),\n                rcx = bb.x + bb.width / 2,\n                rcy = bb.y + bb.height / 2,\n                kx = x / this._.sx,\n                ky = y / this._.sy;\n            cx = (+cx || cx == 0) ? cx : rcx;\n            cy = (+cy || cy == 0) ? cy : rcy;\n            var dirx = ~~(x / math.abs(x)),\n                diry = ~~(y / math.abs(y)),\n                s = this.node.style,\n                ncx = cx + (rcx - cx) * kx,\n                ncy = cy + (rcy - cy) * ky;\n            switch (this.type) {\n                case \"rect\":\n                case \"image\":\n                    var neww = a.width * dirx * kx,\n                        newh = a.height * diry * ky;\n                    this.attr({\n                        height: newh,\n                        r: a.r * mmin(dirx * kx, diry * ky),\n                        width: neww,\n                        x: ncx - neww / 2,\n                        y: ncy - newh / 2\n                    });\n                    break;\n                case \"circle\":\n                case \"ellipse\":\n                    this.attr({\n                        rx: a.rx * dirx * kx,\n                        ry: a.ry * diry * ky,\n                        r: a.r * mmin(dirx * kx, diry * ky),\n                        cx: ncx,\n                        cy: ncy\n                    });\n                    break;\n                case \"path\":\n                    var path = pathToRelative(a.path),\n                        skip = true;\n                    for (var i = 0, ii = path[length]; i < ii; i++) {\n                        var p = path[i],\n                            P0 = upperCase.call(p[0]);\n                        if (P0 == \"M\" && skip) {\n                            continue;\n                        } else {\n                            skip = false;\n                        }\n                        if (P0 == \"A\") {\n                            p[path[i][length] - 2] *= kx;\n                            p[path[i][length] - 1] *= ky;\n                            p[1] *= dirx * kx;\n                            p[2] *= diry * ky;\n                            p[5] = +!(dirx + diry ? !+p[5] : +p[5]);\n                        } else if (P0 == \"H\") {\n                            for (var j = 1, jj = p[length]; j < jj; j++) {\n                                p[j] *= kx;\n                            }\n                        } else if (P0 == \"V\") {\n                            for (j = 1, jj = p[length]; j < jj; j++) {\n                                p[j] *= ky;\n                            }\n                         } else {\n                            for (j = 1, jj = p[length]; j < jj; j++) {\n                                p[j] *= (j % 2) ? kx : ky;\n                            }\n                        }\n                    }\n                    var dim2 = pathDimensions(path);\n                    dx = ncx - dim2.x - dim2.width / 2;\n                    dy = ncy - dim2.y - dim2.height / 2;\n                    path[0][1] += dx;\n                    path[0][2] += dy;\n                    this.attr({path: path});\n                break;\n            }\n            if (this.type in {text: 1, image:1} && (dirx != 1 || diry != 1)) {\n                if (this.transformations) {\n                    this.transformations[2] = \"scale(\"[concat](dirx, \",\", diry, \")\");\n                    this.node[setAttribute](\"transform\", this.transformations[join](S));\n                    dx = (dirx == -1) ? -a.x - (neww || 0) : a.x;\n                    dy = (diry == -1) ? -a.y - (newh || 0) : a.y;\n                    this.attr({x: dx, y: dy});\n                    a.fx = dirx - 1;\n                    a.fy = diry - 1;\n                } else {\n                    this.node.filterMatrix = \" progid:DXImageTransform.Microsoft.Matrix(M11=\"[concat](dirx,\n                        \", M12=0, M21=0, M22=\", diry,\n                        \", Dx=0, Dy=0, sizingmethod='auto expand', filtertype='bilinear')\");\n                    s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E);\n                }\n            } else {\n                if (this.transformations) {\n                    this.transformations[2] = E;\n                    this.node[setAttribute](\"transform\", this.transformations[join](S));\n                    a.fx = 0;\n                    a.fy = 0;\n                } else {\n                    this.node.filterMatrix = E;\n                    s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E);\n                }\n            }\n            a.scale = [x, y, cx, cy][join](S);\n            this._.sx = x;\n            this._.sy = y;\n        }\n        return this;\n    };\n    Element[proto].clone = function () {\n        var attr = this.attr();\n        delete attr.scale;\n        delete attr.translation;\n        return this.paper[this.type]().attr(attr);\n    };\n    var getPointAtSegmentLength = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {\n        var len = 0,\n            old;\n        for (var i = 0; i < 1.001; i+=.001) {\n            var dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i);\n            i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));\n            if (len >= length) {\n                return dot;\n            }\n            old = dot;\n        }\n    }),\n    getLengthFactory = function (istotal, subpath) {\n        return function (path, length, onlystart) {\n            path = path2curve(path);\n            var x, y, p, l, sp = \"\", subpaths = {}, point,\n                len = 0;\n            for (var i = 0, ii = path.length; i < ii; i++) {\n                p = path[i];\n                if (p[0] == \"M\") {\n                    x = +p[1];\n                    y = +p[2];\n                } else {\n                    l = segmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);\n                    if (len + l > length) {\n                        if (subpath && !subpaths.start) {\n                            point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);\n                            sp += [\"C\", point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];\n                            if (onlystart) {return sp;}\n                            subpaths.start = sp;\n                            sp = [\"M\", point.x, point.y + \"C\", point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]][join]();\n                            len += l;\n                            x = +p[5];\n                            y = +p[6];\n                            continue;\n                        }\n                        if (!istotal && !subpath) {\n                            point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);\n                            return {x: point.x, y: point.y, alpha: point.alpha};\n                        }\n                    }\n                    len += l;\n                    x = +p[5];\n                    y = +p[6];\n                }\n                sp += p;\n            }\n            subpaths.end = sp;\n            point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], 1);\n            point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});\n            return point;\n        };\n    },\n    segmentLength = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {\n        var old = {x: 0, y: 0},\n            len = 0;\n        for (var i = 0; i < 1.01; i+=.01) {\n            var dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i);\n            i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));\n            old = dot;\n        }\n        return len;\n    });\n    var getTotalLength = getLengthFactory(1),\n        getPointAtLength = getLengthFactory(),\n        getSubpathsAtLength = getLengthFactory(0, 1);\n    Element[proto].getTotalLength = function () {\n        if (this.type != \"path\") {return;}\n        return getTotalLength(this.attrs.path);\n    };\n    Element[proto].getPointAtLength = function (length) {\n        if (this.type != \"path\") {return;}\n        return getPointAtLength(this.attrs.path, length);\n    };\n    Element[proto].getSubpath = function (from, to) {\n        if (this.type != \"path\") {return;}\n        if (math.abs(this.getTotalLength() - to) < 1e-6) {\n            return getSubpathsAtLength(this.attrs.path, from).end;\n        }\n        var a = getSubpathsAtLength(this.attrs.path, to, 1);\n        return from ? getSubpathsAtLength(a, from).end : a;\n    };\n\n    // animation easing formulas\n    R.easing_formulas = {\n        linear: function (n) {\n            return n;\n        },\n        \"<\": function (n) {\n            return pow(n, 3);\n        },\n        \">\": function (n) {\n            return pow(n - 1, 3) + 1;\n        },\n        \"<>\": function (n) {\n            n = n * 2;\n            if (n < 1) {\n                return pow(n, 3) / 2;\n            }\n            n -= 2;\n            return (pow(n, 3) + 2) / 2;\n        },\n        backIn: function (n) {\n            var s = 1.70158;\n            return n * n * ((s + 1) * n - s);\n        },\n        backOut: function (n) {\n            n = n - 1;\n            var s = 1.70158;\n            return n * n * ((s + 1) * n + s) + 1;\n        },\n        elastic: function (n) {\n            if (n == 0 || n == 1) {\n                return n;\n            }\n            var p = .3,\n                s = p / 4;\n            return pow(2, -10 * n) * math.sin((n - s) * (2 * math.PI) / p) + 1;\n        },\n        bounce: function (n) {\n            var s = 7.5625,\n                p = 2.75,\n                l;\n            if (n < (1 / p)) {\n                l = s * n * n;\n            } else {\n                if (n < (2 / p)) {\n                    n -= (1.5 / p);\n                    l = s * n * n + .75;\n                } else {\n                    if (n < (2.5 / p)) {\n                        n -= (2.25 / p);\n                        l = s * n * n + .9375;\n                    } else {\n                        n -= (2.625 / p);\n                        l = s * n * n + .984375;\n                    }\n                }\n            }\n            return l;\n        }\n    };\n \n    var animationElements = {length : 0},\n        animation = function () {\n            var Now = +new Date;\n            for (var l in animationElements) if (l != \"length\" && animationElements[has](l)) {\n                var e = animationElements[l];\n                if (e.stop || e.el.removed) {\n                    delete animationElements[l];\n                    animationElements[length]--;\n                    continue;\n                }\n                var time = Now - e.start,\n                    ms = e.ms,\n                    easing = e.easing,\n                    from = e.from,\n                    diff = e.diff,\n                    to = e.to,\n                    t = e.t,\n                    prev = e.prev || 0,\n                    that = e.el,\n                    callback = e.callback,\n                    set = {},\n                    now;\n                if (time < ms) {\n                    var pos = R.easing_formulas[easing] ? R.easing_formulas[easing](time / ms) : time / ms;\n                    for (var attr in from) if (from[has](attr)) {\n                        switch (availableAnimAttrs[attr]) {\n                            case \"along\":\n                                now = pos * ms * diff[attr];\n                                to.back && (now = to.len - now);\n                                var point = getPointAtLength(to[attr], now);\n                                that.translate(diff.sx - diff.x || 0, diff.sy - diff.y || 0);\n                                diff.x = point.x;\n                                diff.y = point.y;\n                                that.translate(point.x - diff.sx, point.y - diff.sy);\n                                to.rot && that.rotate(diff.r + point.alpha, point.x, point.y);\n                                break;\n                            case \"number\":\n                                now = +from[attr] + pos * ms * diff[attr];\n                                break;\n                            case \"colour\":\n                                now = \"rgb(\" + [\n                                    upto255(round(from[attr].r + pos * ms * diff[attr].r)),\n                                    upto255(round(from[attr].g + pos * ms * diff[attr].g)),\n                                    upto255(round(from[attr].b + pos * ms * diff[attr].b))\n                                ][join](\",\") + \")\";\n                                break;\n                            case \"path\":\n                                now = [];\n                                for (var i = 0, ii = from[attr][length]; i < ii; i++) {\n                                    now[i] = [from[attr][i][0]];\n                                    for (var j = 1, jj = from[attr][i][length]; j < jj; j++) {\n                                        now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];\n                                    }\n                                    now[i] = now[i][join](S);\n                                }\n                                now = now[join](S);\n                                break;\n                            case \"csv\":\n                                switch (attr) {\n                                    case \"translation\":\n                                        var x = diff[attr][0] * (time - prev),\n                                            y = diff[attr][1] * (time - prev);\n                                        t.x += x;\n                                        t.y += y;\n                                        now = x + S + y;\n                                    break;\n                                    case \"rotation\":\n                                        now = +from[attr][0] + pos * ms * diff[attr][0];\n                                        from[attr][1] && (now += \",\" + from[attr][1] + \",\" + from[attr][2]);\n                                    break;\n                                    case \"scale\":\n                                        now = [+from[attr][0] + pos * ms * diff[attr][0], +from[attr][1] + pos * ms * diff[attr][1], (2 in to[attr] ? to[attr][2] : E), (3 in to[attr] ? to[attr][3] : E)][join](S);\n                                    break;\n                                    case \"clip-rect\":\n                                        now = [];\n                                        i = 4;\n                                        while (i--) {\n                                            now[i] = +from[attr][i] + pos * ms * diff[attr][i];\n                                        }\n                                    break;\n                                }\n                                break;\n                        }\n                        set[attr] = now;\n                    }\n                    that.attr(set);\n                    that._run && that._run.call(that);\n                } else {\n                    if (to.along) {\n                        point = getPointAtLength(to.along, to.len * !to.back);\n                        that.translate(diff.sx - (diff.x || 0) + point.x - diff.sx, diff.sy - (diff.y || 0) + point.y - diff.sy);\n                        to.rot && that.rotate(diff.r + point.alpha, point.x, point.y);\n                    }\n                    (t.x || t.y) && that.translate(-t.x, -t.y);\n                    to.scale && (to.scale = to.scale + E);\n                    that.attr(to);\n                    delete animationElements[l];\n                    animationElements[length]--;\n                    that.in_animation = null;\n                    R.is(callback, \"function\") && callback.call(that);\n                }\n                e.prev = time;\n            }\n            R.svg && that && that.paper.safari();\n            animationElements[length] && win.setTimeout(animation);\n        },\n        upto255 = function (color) {\n            return color > 255 ? 255 : (color < 0 ? 0 : color);\n        },\n        translate = function (x, y) {\n            if (x == null) {\n                return {x: this._.tx, y: this._.ty, toString: x_y};\n            }\n            this._.tx += +x;\n            this._.ty += +y;\n            switch (this.type) {\n                case \"circle\":\n                case \"ellipse\":\n                    this.attr({cx: +x + this.attrs.cx, cy: +y + this.attrs.cy});\n                    break;\n                case \"rect\":\n                case \"image\":\n                case \"text\":\n                    this.attr({x: +x + this.attrs.x, y: +y + this.attrs.y});\n                    break;\n                case \"path\":\n                    var path = pathToRelative(this.attrs.path);\n                    path[0][1] += +x;\n                    path[0][2] += +y;\n                    this.attr({path: path});\n                break;\n            }\n            return this;\n        };\n    Element[proto].animateWith = function (element, params, ms, easing, callback) {\n        animationElements[element.id] && (params.start = animationElements[element.id].start);\n        return this.animate(params, ms, easing, callback);\n    };\n    Element[proto].animateAlong = along();\n    Element[proto].animateAlongBack = along(1);\n    function along(isBack) {\n        return function (path, ms, rotate, callback) {\n            var params = {back: isBack};\n            R.is(rotate, \"function\") ? (callback = rotate) : (params.rot = rotate);\n            path && path.constructor == Element && (path = path.attrs.path);\n            path && (params.along = path);\n            return this.animate(params, ms, callback);\n        };\n    }\n    Element[proto].onAnimation = function (f) {\n        this._run = f || 0;\n        return this;\n    };\n    Element[proto].animate = function (params, ms, easing, callback) {\n        if (R.is(easing, \"function\") || !easing) {\n            callback = easing || null;\n        }\n        var from = {},\n            to = {},\n            diff = {};\n        for (var attr in params) if (params[has](attr)) {\n            if (availableAnimAttrs[has](attr)) {\n                from[attr] = this.attr(attr);\n                (from[attr] == null) && (from[attr] = availableAttrs[attr]);\n                to[attr] = params[attr];\n                switch (availableAnimAttrs[attr]) {\n                    case \"along\":\n                        var len = getTotalLength(params[attr]),\n                            point = getPointAtLength(params[attr], len * !!params.back),\n                            bb = this.getBBox();\n                        diff[attr] = len / ms;\n                        diff.tx = bb.x;\n                        diff.ty = bb.y;\n                        diff.sx = point.x;\n                        diff.sy = point.y;\n                        to.rot = params.rot;\n                        to.back = params.back;\n                        to.len = len;\n                        params.rot && (diff.r = toFloat(this.rotate()) || 0);\n                        break;\n                    case \"number\":\n                        diff[attr] = (to[attr] - from[attr]) / ms;\n                        break;\n                    case \"colour\":\n                        from[attr] = R.getRGB(from[attr]);\n                        var toColour = R.getRGB(to[attr]);\n                        diff[attr] = {\n                            r: (toColour.r - from[attr].r) / ms,\n                            g: (toColour.g - from[attr].g) / ms,\n                            b: (toColour.b - from[attr].b) / ms\n                        };\n                        break;\n                    case \"path\":\n                        var pathes = path2curve(from[attr], to[attr]);\n                        from[attr] = pathes[0];\n                        var toPath = pathes[1];\n                        diff[attr] = [];\n                        for (var i = 0, ii = from[attr][length]; i < ii; i++) {\n                            diff[attr][i] = [0];\n                            for (var j = 1, jj = from[attr][i][length]; j < jj; j++) {\n                                diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;\n                            }\n                        }\n                        break;\n                    case \"csv\":\n                        var values = (params[attr] + E)[split](separator),\n                            from2 = (from[attr] + E)[split](separator);\n                        switch (attr) {\n                            case \"translation\":\n                                from[attr] = [0, 0];\n                                diff[attr] = [values[0] / ms, values[1] / ms];\n                            break;\n                            case \"rotation\":\n                                from[attr] = (from2[1] == values[1] && from2[2] == values[2]) ? from2 : [0, values[1], values[2]];\n                                diff[attr] = [(values[0] - from[attr][0]) / ms, 0, 0];\n                            break;\n                            case \"scale\":\n                                params[attr] = values;\n                                from[attr] = (from[attr] + E)[split](separator);\n                                diff[attr] = [(values[0] - from[attr][0]) / ms, (values[1] - from[attr][1]) / ms, 0, 0];\n                            break;\n                            case \"clip-rect\":\n                                from[attr] = (from[attr] + E)[split](separator);\n                                diff[attr] = [];\n                                i = 4;\n                                while (i--) {\n                                    diff[attr][i] = (values[i] - from[attr][i]) / ms;\n                                }\n                            break;\n                        }\n                        to[attr] = values;\n                }\n            }\n        }\n        this.stop();\n        this.in_animation = 1;\n        animationElements[this.id] = {\n            start: params.start || +new Date,\n            ms: ms,\n            easing: easing,\n            from: from,\n            diff: diff,\n            to: to,\n            el: this,\n            callback: callback,\n            t: {x: 0, y: 0}\n        };\n        ++animationElements[length] == 1 && animation();\n        return this;\n    };\n    Element[proto].stop = function () {\n        animationElements[this.id] && animationElements[length]--;\n        delete animationElements[this.id];\n        return this;\n    };\n    Element[proto].translate = function (x, y) {\n        return this.attr({translation: x + \" \" + y});\n    };\n    Element[proto][toString] = function () {\n        return \"Rapha\\xebl\\u2019s object\";\n    };\n    R.ae = animationElements;\n \n    // Set\n    var Set = function (items) {\n        this.items = [];\n        this[length] = 0;\n        if (items) {\n            for (var i = 0, ii = items[length]; i < ii; i++) {\n                if (items[i] && (items[i].constructor == Element || items[i].constructor == Set)) {\n                    this[this.items[length]] = this.items[this.items[length]] = items[i];\n                    this[length]++;\n                }\n            }\n        }\n    };\n    Set[proto][push] = function () {\n        var item,\n            len;\n        for (var i = 0, ii = arguments[length]; i < ii; i++) {\n            item = arguments[i];\n            if (item && (item.constructor == Element || item.constructor == Set)) {\n                len = this.items[length];\n                this[len] = this.items[len] = item;\n                this[length]++;\n            }\n        }\n        return this;\n    };\n    Set[proto].pop = function () {\n        delete this[this[length]--];\n        return this.items.pop();\n    };\n    for (var method in Element[proto]) if (Element[proto][has](method)) {\n        Set[proto][method] = (function (methodname) {\n            return function () {\n                for (var i = 0, ii = this.items[length]; i < ii; i++) {\n                    this.items[i][methodname][apply](this.items[i], arguments);\n                }\n                return this;\n            };\n        })(method);\n    }\n    Set[proto].attr = function (name, value) {\n        if (name && R.is(name, \"array\") && R.is(name[0], \"object\")) {\n            for (var j = 0, jj = name[length]; j < jj; j++) {\n                this.items[j].attr(name[j]);\n            }\n        } else {\n            for (var i = 0, ii = this.items[length]; i < ii; i++) {\n                this.items[i].attr(name, value);\n            }\n        }\n        return this;\n    };\n    Set[proto].animate = function (params, ms, easing, callback) {\n        (R.is(easing, \"function\") || !easing) && (callback = easing || null);\n        var len = this.items[length],\n            i = len,\n            set = this,\n            collector;\n        callback && (collector = function () {\n            !--len && callback.call(set);\n        });\n        this.items[--i].animate(params, ms, easing || collector, collector);\n        while (i--) {\n            this.items[i].animateWith(this.items[len - 1], params, ms, easing || collector, collector);\n        }\n        return this;\n    };\n    Set[proto].insertAfter = function (el) {\n        var i = this.items[length];\n        while (i--) {\n            this.items[i].insertAfter(el);\n        }\n        return this;\n    };\n    Set[proto].getBBox = function () {\n        var x = [],\n            y = [],\n            w = [],\n            h = [];\n        for (var i = this.items[length]; i--;) {\n            var box = this.items[i].getBBox();\n            x[push](box.x);\n            y[push](box.y);\n            w[push](box.x + box.width);\n            h[push](box.y + box.height);\n        }\n        x = mmin[apply](0, x);\n        y = mmin[apply](0, y);\n        return {\n            x: x,\n            y: y,\n            width: mmax[apply](0, w) - x,\n            height: mmax[apply](0, h) - y\n        };\n    };\n    Set[proto].clone = function (s) {\n        s = new Set;\n        for (var i = 0, ii = this.items[length]; i < ii; i++) {\n            s[push](this.items[i].clone());\n        }\n        return s;\n    };\n\n    R.registerFont = function (font) {\n        if (!font.face) {\n            return font;\n        }\n        this.fonts = this.fonts || {};\n        var fontcopy = {\n                w: font.w,\n                face: {},\n                glyphs: {}\n            },\n            family = font.face[\"font-family\"];\n        for (var prop in font.face) if (font.face[has](prop)) {\n            fontcopy.face[prop] = font.face[prop];\n        }\n        if (this.fonts[family]) {\n            this.fonts[family][push](fontcopy);\n        } else {\n            this.fonts[family] = [fontcopy];\n        }\n        if (!font.svg) {\n            fontcopy.face[\"units-per-em\"] = toInt(font.face[\"units-per-em\"], 10);\n            for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {\n                var path = font.glyphs[glyph];\n                fontcopy.glyphs[glyph] = {\n                    w: path.w,\n                    k: {},\n                    d: path.d && \"M\" + path.d[rp](/[mlcxtrv]/g, function (command) {\n                            return {l: \"L\", c: \"C\", x: \"z\", t: \"m\", r: \"l\", v: \"c\"}[command] || \"M\";\n                        }) + \"z\"\n                };\n                if (path.k) {\n                    for (var k in path.k) if (path[has](k)) {\n                        fontcopy.glyphs[glyph].k[k] = path.k[k];\n                    }\n                }\n            }\n        }\n        return font;\n    };\n    Paper[proto].getFont = function (family, weight, style, stretch) {\n        stretch = stretch || \"normal\";\n        style = style || \"normal\";\n        weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;\n        var font = R.fonts[family];\n        if (!font) {\n            var name = new RegExp(\"(^|\\\\s)\" + family[rp](/[^\\w\\d\\s+!~.:_-]/g, E) + \"(\\\\s|$)\", \"i\");\n            for (var fontName in R.fonts) if (R.fonts[has](fontName)) {\n                if (name.test(fontName)) {\n                    font = R.fonts[fontName];\n                    break;\n                }\n            }\n        }\n        var thefont;\n        if (font) {\n            for (var i = 0, ii = font[length]; i < ii; i++) {\n                thefont = font[i];\n                if (thefont.face[\"font-weight\"] == weight && (thefont.face[\"font-style\"] == style || !thefont.face[\"font-style\"]) && thefont.face[\"font-stretch\"] == stretch) {\n                    break;\n                }\n            }\n        }\n        return thefont;\n    };\n    Paper[proto].print = function (x, y, string, font, size, origin) {\n        origin = origin || \"middle\"; // baseline|middle\n        var out = this.set(),\n            letters = (string + E)[split](E),\n            shift = 0,\n            path = E,\n            scale;\n        R.is(font, \"string\") && (font = this.getFont(font));\n        if (font) {\n            scale = (size || 16) / font.face[\"units-per-em\"];\n            var bb = font.face.bbox.split(separator),\n                top = +bb[0],\n                height = +bb[1] + (origin == \"baseline\" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);\n            for (var i = 0, ii = letters[length]; i < ii; i++) {\n                var prev = i && font.glyphs[letters[i - 1]] || {},\n                    curr = font.glyphs[letters[i]];\n                shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) : 0;\n                curr && curr.d && out[push](this.path(curr.d).attr({fill: \"#000\", stroke: \"none\", translation: [shift, 0]}));\n            }\n            out.scale(scale, scale, top, height).translate(x - top, y - height);\n        }\n        return out;\n    };\n\n    var formatrg = /\\{(\\d+)\\}/g;\n    R.format = function (token, array) {\n        var args = R.is(array, \"array\") ? [0][concat](array) : arguments;\n        token && R.is(token, \"string\") && args[length] - 1 && (token = token[rp](formatrg, function (str, i) {\n            return args[++i] == null ? E : args[i];\n        }));\n        return token || E;\n    };\n    R.ninja = function () {\n        oldRaphael.was ? (Raphael = oldRaphael.is) : delete Raphael;\n        return R;\n    };\n    R.el = Element[proto];\n    return R;\n})();"
  },
  {
    "path": "src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/yui-min.js",
    "content": "/*\nCopyright (c) 2010, Yahoo! Inc. All rights reserved.\nCode licensed under the BSD License:\nhttp://developer.yahoo.com/yui/license.html\nversion: 3.1.0\nbuild: 2026\n*/\nif(typeof YUI===\"undefined\"){var YUI=function(F,E,D,C,A){var B=this,J=arguments,I,G=J.length,H=(typeof YUI_config!==\"undefined\")&&YUI_config;if(!(B instanceof YUI)){return new YUI(F,E,D,C,A);}else{B._init();if(H){B._config(H);}for(I=0;I<G;I++){B._config(J[I]);}B._setup();return B;}};}(function(){var L,B,M=\"3.1.0\",K=\"http://yui.yahooapis.com/\",P=\"yui3-js-enabled\",I=function(){},G=Array.prototype.slice,N={\"io.xdrReady\":1,\"io.xdrResponse\":1,\"SWF.eventHandler\":1},F=(typeof window!=\"undefined\"),E=(F)?window:null,R=(F)?E.document:null,D=R&&R.documentElement,A=D&&D.className,C={},H=new Date().getTime(),J=function(V,U,T,S){if(V&&V.addEventListener){V.addEventListener(U,T,S);}else{if(V&&V.attachEvent){V.attachEvent(\"on\"+U,T);}}},Q=function(V,U,T,S){if(V&&V.removeEventListener){V.removeEventListener(U,T,S);}else{if(V&&V.detachEvent){V.detachEvent(\"on\"+U,T);}}},O=function(){YUI.Env.windowLoaded=true;YUI.Env.DOMReady=true;if(F){Q(window,\"load\",O);}};if(D&&A.indexOf(P)==-1){if(A){A+=\" \";}A+=P;D.className=A;}if(M.indexOf(\"@\")>-1){M=\"3.0.0\";}YUI.prototype={_config:function(Y){Y=Y||{};var T,V,W,U=this.config,X=U.modules,S=U.groups;for(V in Y){T=Y[V];if(X&&V==\"modules\"){for(W in T){X[W]=T[W];}}else{if(S&&V==\"groups\"){for(W in T){S[W]=T[W];}}else{if(V==\"win\"){U[V]=T.contentWindow||T;U.doc=U[V].document;}else{U[V]=T;}}}}},_init:function(){var U,V=this,S=YUI.Env,T=V.Env;V.version=M;if(!T){V.Env={mods:{},base:K,cdn:K+M+\"/build/\",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_guidp:\"y\",_loaded:{},getBase:function(c,a){var W,X,Z,d,Y;X=(R&&R.getElementsByTagName(\"script\"))||[];for(Z=0;Z<X.length;Z=Z+1){d=X[Z].src;if(d){Y=d.match(c);W=Y&&Y[1];if(W){U=Y[2];Y=d.match(a);if(Y&&Y[3]){W=Y[1]+Y[3];}break;}}}return W||T.cdn;}};T=V.Env;T._loaded[M]={};if(S&&V!==YUI){T._yidx=++S._yidx;T._guidp=(\"yui_\"+M+\"_\"+T._yidx+\"_\"+H).replace(/\\./g,\"_\");}V.id=V.stamp(V);C[V.id]=V;}V.constructor=YUI;V.config=V.config||{win:E,doc:R,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true};V.config.base=YUI.config.base||V.Env.getBase(/^(.*)yui\\/yui([\\.\\-].*)js(\\?.*)?$/,/^(.*\\?)(.*\\&)(.*)yui\\/yui[\\.\\-].*js(\\?.*)?$/);V.config.loaderPath=YUI.config.loaderPath||\"loader/loader\"+(U||\"-min.\")+\"js\";},_setup:function(X){var T,W=this,S=[],V=YUI.Env.mods,U=W.config.core||[\"get\",\"intl-base\",\"loader\",\"yui-log\",\"yui-later\",\"yui-throttle\"];for(T=0;T<U.length;T++){if(V[U[T]]){S.push(U[T]);}}W.use(\"yui-base\");W.use.apply(W,S);},applyTo:function(Y,X,U){if(!(X in N)){this.log(X+\": applyTo not allowed\",\"warn\",\"yui\");return null;}var T=C[Y],W,S,V;if(T){W=X.split(\".\");S=T;for(V=0;V<W.length;V=V+1){S=S[W[V]];if(!S){this.log(\"applyTo not found: \"+X,\"warn\",\"yui\");}}return S.apply(T,U);}return null;},add:function(T,V,S,U){U=U||{};YUI.Env.mods[T]={name:T,fn:V,version:S,details:U};return this;},_attach:function(S,W){var Y,V,b,T,a,U,c=YUI.Env.mods,X=this.Env._attached,Z=S.length;for(Y=0;Y<Z;Y++){V=S[Y];b=c[V];if(!X[V]&&b){X[V]=true;T=b.details;a=T.requires;U=T.use;if(a){this._attach(this.Array(a));}if(b.fn){b.fn(this,V);}if(U){this._attach(this.Array(U));}}}},use:function(){if(!this.Array){this._attach([\"yui-base\"]);}var i,c,j,T=this,k=YUI.Env,U=G.call(arguments,0),V=k.mods,S=T.Env,Z=S._used,g=k._loaderQueue,m=U[0],W=U[U.length-1],b=T.Array,l=T.config,a=l.bootstrap,h=[],e=[],X=l.fetchCSS,f=function(o){e.push(o);if(Z[o]){return;}var Y=V[o],p,n;if(Y){Z[o]=true;p=Y.details.requires;n=Y.details.use;}else{if(!k._loaded[M][o]){h.push(o);}else{Z[o]=true;}}if(p){b.each(b(p),f);}if(n){b.each(b(n),f);}},d=function(q){var o=q||{success:true,msg:\"not dynamic\"},p,n,Y,r=o.data;T._loading=false;if(r){Y=h.concat();h=[];T.Array.each(r,f);n=h.length;if(n){if(h.sort().join()==Y.sort().join()){n=false;}}}if(n&&r){p=r.concat();p.push(function(){T._attach(r);if(W){W(T,o);}});T._loading=false;T.use.apply(T,p);}else{if(r){T._attach(r);}if(W){W(T,o);}}if(T._useQueue&&T._useQueue.size()&&!T._loading){T.use.apply(T,T._useQueue.next());}};if(T._loading){T._useQueue=T._useQueue||new T.Queue();T._useQueue.add(U);return T;}if(typeof W===\"function\"){U.pop();}else{W=null;}if(m===\"*\"){U=T.Object.keys(V);}if(T.Loader){c=new T.Loader(l);c.require(U);c.ignoreRegistered=true;c.calculate(null,(X)?null:\"js\");U=c.sorted;}b.each(U,f);i=h.length;if(i){h=T.Object.keys(b.hash(h));i=h.length;}if(a&&i&&T.Loader){T._loading=true;c=new T.Loader(l);c.onEnd=d;c.context=T;c.attaching=U;c.data=U;c.require((X)?h:U);c.insert(null,(X)?null:\"js\");}else{if(a&&i&&T.Get&&!S.bootstrapped){T._loading=true;U=b(arguments,0,true);j=function(){T._loading=false;g.running=false;S.bootstrapped=true;T._attach([\"loader\"]);T.use.apply(T,U);};if(k._bootstrapping){g.add(j);}else{k._bootstrapping=true;T.Get.script(l.base+l.loaderPath,{onEnd:j});}}else{if(i){T.message(\"Requirement NOT loaded: \"+h,\"warn\",\"yui\");}T._attach(e);d();}}return T;},namespace:function(){var S=arguments,W=null,U,T,V;for(U=0;U<S.length;U=U+1){V=(\"\"+S[U]).split(\".\");W=this;for(T=(V[0]==\"YAHOO\")?1:0;T<V.length;T=T+1){W[V[T]]=W[V[T]]||{};W=W[V[T]];}}return W;},log:I,message:I,error:function(T,S){if(this.config.throwFail){throw (S||new Error(T));}else{this.message(T,\"error\");}return this;},guid:function(S){var T=this.Env._guidp+(++this.Env._uidx);return(S)?(S+T):T;},stamp:function(U,V){if(!U){return U;}var S=(typeof U===\"string\")?U:U._yuid;if(!S){S=this.guid();if(!V){try{U._yuid=S;}catch(T){S=null;}}}return S;}};L=YUI.prototype;for(B in L){YUI[B]=L[B];}YUI._init();if(F){J(window,\"load\",O);}else{O();}YUI.Env.add=J;YUI.Env.remove=Q;if(typeof exports==\"object\"){exports.YUI=YUI;}})();YUI.add(\"yui-base\",function(B){(function(){B.Lang=B.Lang||{};var R=B.Lang,G=\"array\",I=\"boolean\",D=\"date\",M=\"error\",S=\"function\",H=\"number\",K=\"null\",F=\"object\",O=\"regexp\",N=\"string\",C=Object.prototype.toString,P=\"undefined\",E={\"undefined\":P,\"number\":H,\"boolean\":I,\"string\":N,\"[object Function]\":S,\"[object RegExp]\":O,\"[object Array]\":G,\"[object Date]\":D,\"[object Error]\":M},J=/^\\s+|\\s+$/g,Q=\"\";R.isArray=function(L){return R.type(L)===G;};R.isBoolean=function(L){return typeof L===I;\n};R.isFunction=function(L){return R.type(L)===S;};R.isDate=function(L){return R.type(L)===D&&L.toString()!==\"Invalid Date\"&&!isNaN(L);};R.isNull=function(L){return L===null;};R.isNumber=function(L){return typeof L===H&&isFinite(L);};R.isObject=function(U,T){var L=typeof U;return(U&&(L===F||(!T&&(L===S||R.isFunction(U)))))||false;};R.isString=function(L){return typeof L===N;};R.isUndefined=function(L){return typeof L===P;};R.trim=function(L){try{return L.replace(J,Q);}catch(T){return L;}};R.isValue=function(T){var L=R.type(T);switch(L){case H:return isFinite(T);case K:case P:return false;default:return !!(L);}};R.type=function(L){return E[typeof L]||E[C.call(L)]||(L?F:K);};})();(function(){var C=B.Lang,D=Array.prototype,E=\"length\",F=function(M,K,I){var J=(I)?2:F.test(M),H,G,N=K||0;if(J){try{return D.slice.call(M,N);}catch(L){G=[];H=M.length;for(;N<H;N++){G.push(M[N]);}return G;}}else{return[M];}};B.Array=F;F.test=function(I){var G=0;if(C.isObject(I)){if(C.isArray(I)){G=1;}else{try{if((E in I)&&!I.tagName&&!I.alert&&!I.apply){G=2;}}catch(H){}}}return G;};F.each=(D.forEach)?function(G,H,I){D.forEach.call(G||[],H,I||B);return B;}:function(H,J,K){var G=(H&&H.length)||0,I;for(I=0;I<G;I=I+1){J.call(K||B,H[I],I,H);}return B;};F.hash=function(I,H){var L={},G=I.length,K=H&&H.length,J;for(J=0;J<G;J=J+1){if(I[J]){L[I[J]]=(K&&K>J)?H[J]:true;}}return L;};F.indexOf=(D.indexOf)?function(G,H){return D.indexOf.call(G,H);}:function(G,I){for(var H=0;H<G.length;H=H+1){if(G[H]===I){return H;}}return -1;};F.numericSort=function(H,G){return(H-G);};F.some=(D.some)?function(G,H,I){return D.some.call(G,H,I);}:function(H,J,K){var G=H.length,I;for(I=0;I<G;I=I+1){if(J.call(K,H[I],I,H)){return true;}}return false;};})();function A(){this._init();this.add.apply(this,arguments);}A.prototype={_init:function(){this._q=[];},next:function(){return this._q.shift();},last:function(){return this._q.pop();},add:function(){B.Array.each(B.Array(arguments,0,true),function(C){this._q.push(C);},this);return this;},size:function(){return this._q.length;}};B.Queue=A;YUI.Env._loaderQueue=YUI.Env._loaderQueue||new A();(function(){var D=B.Lang,C=\"__\",E=function(H,G){var F=G.toString;if(D.isFunction(F)&&F!=Object.prototype.toString){H.toString=F;}};B.merge=function(){var G=arguments,I={},H,F=G.length;for(H=0;H<F;H=H+1){B.mix(I,G[H],true);}return I;};B.mix=function(F,O,H,N,L,M){if(!O||!F){return F||B;}if(L){switch(L){case 1:return B.mix(F.prototype,O.prototype,H,N,0,M);case 2:B.mix(F.prototype,O.prototype,H,N,0,M);break;case 3:return B.mix(F,O.prototype,H,N,0,M);case 4:return B.mix(F.prototype,O,H,N,0,M);default:}}var K=M&&D.isArray(F),J,I,G;if(N&&N.length){for(J=0,I=N.length;J<I;++J){G=N[J];if(O.hasOwnProperty(G)){if(M&&D.isObject(F[G],true)){B.mix(F[G],O[G]);}else{if(!K&&(H||!(G in F))){F[G]=O[G];}else{if(K){F.push(O[G]);}}}}}}else{for(J in O){if(O.hasOwnProperty(J)){if(M&&D.isObject(F[J],true)){B.mix(F[J],O[J],H,N,0,true);}else{if(!K&&(H||!(J in F))){F[J]=O[J];}else{if(K){F.push(O[J]);}}}}}if(B.UA.ie){E(F,O);}}return F;};B.cached=function(H,F,G){F=F||{};return function(K,J){var I=(J)?Array.prototype.join.call(arguments,C):K;if(!(I in F)||(G&&F[I]==G)){F[I]=H.apply(H,arguments);}return F[I];};};})();(function(){B.Object=function(H){var G=function(){};G.prototype=H;return new G();};var E=B.Object,F=function(H,G){return H&&H.hasOwnProperty&&H.hasOwnProperty(G);},D=undefined,C=function(K,J){var I=(J===2),G=(I)?0:[],H;for(H in K){if(F(K,H)){if(I){G++;}else{G.push((J)?K[H]:H);}}}return G;};E.keys=function(G){return C(G);};E.values=function(G){return C(G,1);};E.size=function(G){return C(G,2);};E.hasKey=F;E.hasValue=function(H,G){return(B.Array.indexOf(E.values(H),G)>-1);};E.owns=F;E.each=function(K,J,L,I){var H=L||B,G;for(G in K){if(I||F(K,G)){J.call(H,K[G],G,K);}}return B;};E.some=function(K,J,L,I){var H=L||B,G;for(G in K){if(I||F(K,G)){if(J.call(H,K[G],G,K)){return true;}}}return false;};E.getValue=function(K,J){if(!B.Lang.isObject(K)){return D;}var H,I=B.Array(J),G=I.length;for(H=0;K!==D&&H<G;H++){K=K[I[H]];}return K;};E.setValue=function(M,K,L){var G,J=B.Array(K),I=J.length-1,H=M;if(I>=0){for(G=0;H!==D&&G<I;G++){H=H[J[G]];}if(H!==D){H[J[G]]=L;}else{return D;}}return M;};})();B.UA=function(){var F=function(K){var L=0;return parseFloat(K.replace(/\\./g,function(){return(L++==1)?\"\":\".\";}));},G=B.config.win,J=G&&G.navigator,I={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,caja:J&&J.cajaVersion,secure:false,os:null},E=J&&J.userAgent,H=G&&G.location,D=H&&H.href,C;I.secure=D&&(D.toLowerCase().indexOf(\"https\")===0);if(E){if((/windows|win32/i).test(E)){I.os=\"windows\";}else{if((/macintosh/i).test(E)){I.os=\"macintosh\";}else{if((/rhino/i).test(E)){I.os=\"rhino\";}}}if((/KHTML/).test(E)){I.webkit=1;}C=E.match(/AppleWebKit\\/([^\\s]*)/);if(C&&C[1]){I.webkit=F(C[1]);if(/ Mobile\\//.test(E)){I.mobile=\"Apple\";}else{C=E.match(/NokiaN[^\\/]*|Android \\d\\.\\d|webOS\\/\\d\\.\\d/);if(C){I.mobile=C[0];}}C=E.match(/Chrome\\/([^\\s]*)/);if(C&&C[1]){I.chrome=F(C[1]);}else{C=E.match(/AdobeAIR\\/([^\\s]*)/);if(C){I.air=C[0];}}}if(!I.webkit){C=E.match(/Opera[\\s\\/]([^\\s]*)/);if(C&&C[1]){I.opera=F(C[1]);C=E.match(/Opera Mini[^;]*/);if(C){I.mobile=C[0];}}else{C=E.match(/MSIE\\s([^;]*)/);if(C&&C[1]){I.ie=F(C[1]);}else{C=E.match(/Gecko\\/([^\\s]*)/);if(C){I.gecko=1;C=E.match(/rv:([^\\s\\)]*)/);if(C&&C[1]){I.gecko=F(C[1]);}}}}}}return I;}();},\"3.1.0\");YUI.add(\"get\",function(A){(function(){var C=A.UA,B=A.Lang,E=\"text/javascript\",F=\"text/css\",D=\"stylesheet\";A.Get=function(){var M,N,J,L={},K=0,U,W=function(a,X,b){var Y=b||A.config.win,c=Y.document,e=c.createElement(a),Z;for(Z in X){if(X[Z]&&X.hasOwnProperty(Z)){e.setAttribute(Z,X[Z]);}}return e;},T=function(Y,Z,X){var a={id:A.guid(),type:F,rel:D,href:Y};if(X){A.mix(a,X);}return W(\"link\",a,Z);},S=function(Y,Z,X){var a={id:A.guid(),type:E};if(X){A.mix(a,X);}a.src=Y;return W(\"script\",a,Z);},P=function(Y,Z,X){return{tId:Y.tId,win:Y.win,data:Y.data,nodes:Y.nodes,msg:Z,statusText:X,purge:function(){N(this.tId);}};},O=function(b,a,X){var Y=L[b],Z;\nif(Y&&Y.onEnd){Z=Y.context||Y;Y.onEnd.call(Z,P(Y,a,X));}},V=function(a,Z){var X=L[a],Y;if(X.timer){clearTimeout(X.timer);}if(X.onFailure){Y=X.context||X;X.onFailure.call(Y,P(X,Z));}O(a,Z,\"failure\");},I=function(a){var X=L[a],Z,Y;if(X.timer){clearTimeout(X.timer);}X.finished=true;if(X.aborted){Z=\"transaction \"+a+\" was aborted\";V(a,Z);return;}if(X.onSuccess){Y=X.context||X;X.onSuccess.call(Y,P(X));}O(a,Z,\"OK\");},Q=function(Z){var X=L[Z],Y;if(X.onTimeout){Y=X.context||X;X.onTimeout.call(Y,P(X));}O(Z,\"timeout\",\"timeout\");},H=function(Z,c){var Y=L[Z],b,g,f,e,a,X,i;if(Y.timer){clearTimeout(Y.timer);}if(Y.aborted){b=\"transaction \"+Z+\" was aborted\";V(Z,b);return;}if(c){Y.url.shift();if(Y.varName){Y.varName.shift();}}else{Y.url=(B.isString(Y.url))?[Y.url]:Y.url;if(Y.varName){Y.varName=(B.isString(Y.varName))?[Y.varName]:Y.varName;}}g=Y.win;f=g.document;e=f.getElementsByTagName(\"head\")[0];if(Y.url.length===0){I(Z);return;}X=Y.url[0];if(!X){Y.url.shift();return H(Z);}if(Y.timeout){Y.timer=setTimeout(function(){Q(Z);},Y.timeout);}if(Y.type===\"script\"){a=S(X,g,Y.attributes);}else{a=T(X,g,Y.attributes);}J(Y.type,a,Z,X,g,Y.url.length);Y.nodes.push(a);if(Y.insertBefore){i=M(Y.insertBefore,Z);if(i){i.parentNode.insertBefore(a,i);}}else{e.appendChild(a);}if((C.webkit||C.gecko)&&Y.type===\"css\"){H(Z,X);}},G=function(){if(U){return;}U=true;var X,Y;for(X in L){if(L.hasOwnProperty(X)){Y=L[X];if(Y.autopurge&&Y.finished){N(Y.tId);delete L[X];}}}U=false;},R=function(Y,X,Z){Z=Z||{};var d=\"q\"+(K++),a,c=Z.purgethreshold||A.Get.PURGE_THRESH;if(K%c===0){G();}L[d]=A.merge(Z,{tId:d,type:Y,url:X,finished:false,nodes:[]});a=L[d];a.win=a.win||A.config.win;a.context=a.context||a;a.autopurge=(\"autopurge\" in a)?a.autopurge:(Y===\"script\")?true:false;a.attributes=a.attributes||{};var b=Z.charset||a.attributes.charset;if(b){a.attributes.charset=b;}setTimeout(function(){H(d);},0);return{tId:d};};J=function(Z,e,d,Y,c,b,X){var a=X||H;if(C.ie){e.onreadystatechange=function(){var f=this.readyState;if(\"loaded\"===f||\"complete\"===f){e.onreadystatechange=null;a(d,Y);}};}else{if(C.webkit){if(Z===\"script\"){e.addEventListener(\"load\",function(){a(d,Y);});}}else{e.onload=function(){a(d,Y);};e.onerror=function(f){V(d,f+\": \"+Y);};}}};M=function(X,a){var Y=L[a],Z=(B.isString(X))?Y.win.document.getElementById(X):X;if(!Z){V(a,\"target node not found: \"+X);}return Z;};N=function(c){var Y,a,g,e,j,b,Z,f,X=L[c];if(X){Y=X.nodes;a=Y.length;g=X.win.document;e=g.getElementsByTagName(\"head\")[0];if(X.insertBefore){j=M(X.insertBefore,c);if(j){e=j.parentNode;}}for(b=0;b<a;b=b+1){Z=Y[b];if(Z.clearAttributes){Z.clearAttributes();}else{for(f in Z){if(Z.hasOwnProperty(f)){delete Z[f];}}}e.removeChild(Z);}}X.nodes=[];};return{PURGE_THRESH:20,_finalize:function(X){setTimeout(function(){I(X);},0);},abort:function(Y){var Z=(B.isString(Y))?Y:Y.tId,X=L[Z];if(X){X.aborted=true;}},script:function(X,Y){return R(\"script\",X,Y);},css:function(X,Y){return R(\"css\",X,Y);}};}();})();},\"3.1.0\");YUI.add(\"intl-base\",function(B){var A=/[, ]/;B.mix(B.namespace(\"Intl\"),{lookupBestLang:function(G,H){var F,I,C,E;function D(K){var J;for(J=0;J<H.length;J+=1){if(K.toLowerCase()===H[J].toLowerCase()){return H[J];}}}if(B.Lang.isString(G)){G=G.split(A);}for(F=0;F<G.length;F+=1){I=G[F];if(!I||I===\"*\"){continue;}while(I.length>0){C=D(I);if(C){return C;}else{E=I.lastIndexOf(\"-\");if(E>=0){I=I.substring(0,E);if(E>=2&&I.charAt(E-2)===\"-\"){I=I.substring(0,E-2);}}else{break;}}}}return\"\";}});},\"3.1.0\",{requires:[\"yui-base\"]});YUI.add(\"yui-log\",function(A){(function(){var E,D=A,F=\"yui:log\",B=\"undefined\",C={debug:1,info:1,warn:1,error:1};D.log=function(I,Q,G,O){var K,N,L,J,M,H=D,P=H.config;if(P.debug){if(G){N=P.logExclude;L=P.logInclude;if(L&&!(G in L)){K=1;}else{if(N&&(G in N)){K=1;}}}if(!K){if(P.useBrowserConsole){J=(G)?G+\": \"+I:I;if(H.Lang.isFunction(P.logFn)){P.logFn(I,Q,G);}else{if(typeof console!=B&&console.log){M=(Q&&console[Q]&&(Q in C))?Q:\"log\";console[M](J);}else{if(typeof opera!=B){opera.postError(J);}}}}if(H.fire&&!O){if(!E){H.publish(F,{broadcast:2});E=1;}H.fire(F,{msg:I,cat:Q,src:G});}}}return H;};D.message=function(){return D.log.apply(D,arguments);};})();},\"3.1.0\",{requires:[\"yui-base\"]});YUI.add(\"yui-later\",function(A){(function(){var B=A.Lang,C=function(K,E,L,G,H){K=K||0;E=E||{};var F=L,J=A.Array(G),I,D;if(B.isString(L)){F=E[L];}if(!F){}I=function(){F.apply(E,J);};D=(H)?setInterval(I,K):setTimeout(I,K);return{id:D,interval:H,cancel:function(){if(this.interval){clearInterval(D);}else{clearTimeout(D);}}};};A.later=C;B.later=C;})();},\"3.1.0\",{requires:[\"yui-base\"]});YUI.add(\"yui-throttle\",function(Y){\n/* Based on work by Simon Willison: http://gist.github.com/292562 */\nvar throttle=function(fn,ms){ms=(ms)?ms:(Y.config.throttleTime||150);if(ms===-1){return(function(){fn.apply(null,arguments);});}var last=(new Date()).getTime();return(function(){var now=(new Date()).getTime();if(now-last>ms){last=now;fn.apply(null,arguments);}});};Y.throttle=throttle;},\"3.1.0\",{requires:[\"yui-base\"]});YUI.add(\"yui\",function(A){},\"3.1.0\",{use:[\"yui-base\",\"get\",\"intl-base\",\"yui-log\",\"yui-later\",\"yui-throttle\"]});"
  },
  {
    "path": "src/contrib/monitoring/JMX-RESOURCES",
    "content": "\nResources for monitoring ZooKeeper using JMX\n--------------------------------------------\n\nJMX/REST Bridge  \n---------------\n\nhttp://code.google.com/p/polarrose-jmx-rest-bridge/ \n\n\"Simple Java Web Application that exposes JMX servers through HTTP. This was written so that external tools can easily query JMX attributes of Java applications. More specifically, this was written to allow Cacti to generate fancy graphs of ActiveMQ instances.\"\n\nJMXetric\n--------\n\nhttp://code.google.com/p/jmxetric/\n\n\"JMXetric is a 100% java, configurable JVM agent that periodically polls MBean attributes and reports their values to Ganglia.\"\n\njmxquery\n--------\n\nhttp://code.google.com/p/jmxquery/\n\n\"a plugin for nagios to check jmx\"\n\ncheck_jmx\n---------\n\nhttp://exchange.nagios.org/directory/Plugins/Java-Applications-and-Servers/check_jmx/details\n\n\njmx2snmp\n--------\n\nhttp://github.com/tcurdt/jmx2snmp\n\nExpose application JMX properties via SNMP\n\n"
  },
  {
    "path": "src/contrib/monitoring/README",
    "content": "\nTools and Recipes for ZooKeeper Monitoring\n------------------------------------------\n\nHow To Monitor\n--------------\n\nA ZooKeeper cluster can be monitored in two ways:\n 1. by using the 'mntr' 4letterword command\n 2. by using JMX to query the MBeans \n\nThis repo contains tools and recipes for monitoring ZooKeeper using the first method. \n\nCheck the file JMX-RESOURCE for some links to resources that could help you monitor a ZooKeeper cluster using the JMX interface. \n\nRequirements\n------------\n\nZooKeeper 3.4.0 or later or you can apply ZOOKEEPER-744 patch over the latest 3.3.x release.\nThe server should understand the 'mntr' 4letterword command. \n\n$ echo 'mntr' | nc localhost 2181\nzk_version  3.4.0--1, built on 06/19/2010 15:07 GMT\nzk_avg_latency  141\nzk_max_latency  1788\nzk_min_latency  0\nzk_packets_received 385466\nzk_packets_sent 435364\nzk_outstanding_requests 0\nzk_server_state follower\nzk_znode_count  5\nzk_watch_count  0\nzk_ephemerals_count 0\nzk_approximate_data_size    41\nzk_open_file_descriptor_count   20\nzk_max_file_descriptor_count    1024\n\nPython 2.6 (maybe it works on previous version but it's not tested yet).\n\nIn a nutshell\n-------------\n\nAll you need is check_zookeeper.py It has no external dependencies. \n\n\n*** On Nagios call the script like this:\n\n./check_zookeeper.py -o nagios -s \"<server-or-list-of-servers>\" -k <key> -w <warning> -c <critical>\n\n\n*** On Cacti define a custom data input method using the script like this:\n\n./check_zookeeper.py -o cacti -s \"<list-of-servers>\" -k <key> --leader\n\n-- outputs a single value for the given key fetched from the cluster leader\n\nOR \n\n./check_zookeeper.py -o cacti -s \"<list-of-servers>\" -k <key> \n\n-- outputs multiple values on for each cluster node\nex: localhost_2182:0  localhost_2183:0  localhost_2181:0  localhost_2184:0  localhost_2185:0\n\n*** On Ganglia:\n\ninstall the plugin found in the ganglia/ subfolder OR\n\n./check_zookeeper.py -o ganglia -s \"<current-zookeeper-node>\"\n\nit will use gmetric to send zookeeper node status data.\n\n\nCheck the subfolders for configuration details and samples for each platform.\n\nLicense\n-------\n\nApache License 2.0 or later.\n\nZooKeeper 4letterwords Commands\n-------------------------------\n\nhttp://zookeeper.apache.org/docs/current/zookeeperAdmin.html#sc_zkCommands\n\n"
  },
  {
    "path": "src/contrib/monitoring/cacti/README",
    "content": "Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nRecipes for ZooKeeper monitoring using Cacti\n--------------------------------------------\n\nCacti install guide: https://help.ubuntu.com/community/Cacti\n\nCacti Manual: http://www.cacti.net/downloads/docs/html/\nPDF version: http://www.cacti.net/downloads/docs/pdf/manual.pdf \n\nCheck Chapter 16: Simplest Method of Going from Script to Graph\n    http://www.cacti.net/downloads/docs/html/how_to.html#SCRIPT_TO_GRAPH\n\nWARNING: I have wrote these instructions while installing and configuring the plugin on my desktop computer running Ubuntu 9.10. I've installed Cacti using apt-get.\n\nWARNING: I'm going to make the assumption that you know how to work with Cacti and how to setup Data Input Methods for custom scripts. I'm also going to assume that you have already installed Cacti and everything works as expected.\n\nYou can extend the Cacti's data gathering functionality through external scripts. Cacti comes with a number of scripts out of the box wich are localted in the scripts/ directory. \n\n\nThe check_zookeeper.py script can be used a  custom data input method for Cacti.\n\nSingle value (check cluster status by sending queries to the leader):\n---------------------------------------------------------------------\n\npython <path_cacti>scripts/check_zookeeper.py -s \"localhost:2181,localhost:2182,localhost:2183,localhost:2184,localhost:2185\" -k <key> -o cacti --leader\n\nWhen you will call the script this way it will about a single value representing the value attached to this <key>.\n\n\nMultiple values (one for each cluster node):\n--------------------------------------------\n\npython <path_cacti>scripts/check_zookeeper.py -s \"localhost:2181,localhost:2182,localhost:2183,localhost:2184,localhost:2185\" -k <key> -o cacti\n\nOutput:\nlocalhost_2182:0  localhost_2183:0  localhost_2181:0  localhost_2184:0  localhost_2185:0\n\n\nTBD: Step by step guide\n\n\n"
  },
  {
    "path": "src/contrib/monitoring/check_zookeeper.py",
    "content": "#! /usr/bin/env python\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\" Check Zookeeper Cluster\n\nGeneric monitoring script that could be used with multiple platforms (Ganglia, Nagios, Cacti).\n\nIt requires ZooKeeper 3.4.0 or greater. The script needs the 'mntr' 4letter word \ncommand (patch ZOOKEEPER-744) that was now commited to the trunk.\nThe script also works with ZooKeeper 3.3.x but in a limited way.\n\"\"\"\n\nimport sys\nimport socket\nimport logging\nimport re\nimport subprocess\n\nfrom StringIO import StringIO\nfrom optparse import OptionParser, OptionGroup\n\n__version__ = (0, 1, 0)\n\nlog = logging.getLogger()\nlogging.basicConfig(level=logging.ERROR)\n\nclass NagiosHandler(object):\n\n    @classmethod\n    def register_options(cls, parser):\n        group = OptionGroup(parser, 'Nagios specific options')\n\n        group.add_option('-w', '--warning', dest='warning')\n        group.add_option('-c', '--critical', dest='critical')\n\n        parser.add_option_group(group)\n\n    def analyze(self, opts, cluster_stats):\n        try:\n            warning = int(opts.warning)\n            critical = int(opts.critical)\n\n        except (TypeError, ValueError):\n            print >>sys.stderr, 'Invalid values for \"warning\" and \"critical\".'\n            return 2\n\n        if opts.key is None:\n            print >>sys.stderr, 'You should specify a key name.'\n            return 2\n\n        warning_state, critical_state, values = [], [], []\n        for host, stats in cluster_stats.items():\n            if opts.key in stats:\n\n                value = stats[opts.key]\n                values.append('%s=%s;%s;%s' % (host, value, warning, critical))\n\n                if warning >= value > critical or warning <= value < critical:\n                    warning_state.append(host)\n\n                elif (warning < critical and critical <= value) or (warning > critical and critical >= value):\n                    critical_state.append(host)\n\n        if not values:\n            # Zookeeper may be down, not serving requests or we may have a bad configuration\n            print 'Critical, %s not found' % opts.key\n            return 2\n\n        values = ' '.join(values)\n        if critical_state:\n            print 'Critical \"%s\" %s!|%s' % (opts.key, ', '.join(critical_state), values)\n            return 2\n        \n        elif warning_state:\n            print 'Warning \"%s\" %s!|%s' % (opts.key, ', '.join(warning_state), values)\n            return 1\n\n        else:\n            print 'Ok \"%s\"!|%s' % (opts.key, values)\n            return 0\n\nclass CactiHandler(object):\n\n    @classmethod\n    def register_options(cls, parser):\n        group = OptionGroup(parser, 'Cacti specific options')\n        \n        group.add_option('-l', '--leader', dest='leader', \n            action=\"store_true\", help=\"only query the cluster leader\")\n\n        parser.add_option_group(group)\n\n    def analyze(self, opts, cluster_stats):\n        if opts.key is None:\n            print >>sys.stderr, 'The key name is mandatory.'\n            return 1\n\n        if opts.leader is True:\n            try:\n                leader = [x for x in cluster_stats.values() \\\n                    if x.get('zk_server_state', '') == 'leader'][0] \n\n            except IndexError:\n                print >>sys.stderr, 'No leader found.'\n                return 3\n\n            if opts.key in leader:\n                print leader[opts.key]\n                return 0\n\n            else:\n                print >>sys.stderr, 'Unknown key: \"%s\"' % opts.key\n                return 2\n        else:\n            for host, stats in cluster_stats.items():\n                if opts.key not in stats: \n                    continue\n\n                host = host.replace(':', '_')\n                print '%s:%s' % (host, stats[opts.key]),\n\n\nclass GangliaHandler(object):\n\n    @classmethod\n    def register_options(cls, parser):\n        group = OptionGroup(parser, 'Ganglia specific options')\n\n        group.add_option('-g', '--gmetric', dest='gmetric', \n            default='/usr/bin/gmetric', help='ganglia gmetric binary '\\\n            'location: /usr/bin/gmetric')\n\n        parser.add_option_group(group)\n\n    def call(self, *args, **kwargs):\n        subprocess.call(*args, **kwargs)\n\n    def analyze(self, opts, cluster_stats):\n        if len(cluster_stats) != 1:\n            print >>sys.stderr, 'Only allowed to monitor a single node.'\n            return 1\n\n        for host, stats in cluster_stats.items():\n            for k, v in stats.items():\n                try:\n                    self.call([opts.gmetric, '-n', k, '-v', str(int(v)), '-t', 'uint32'])\n                except (TypeError, ValueError):\n                    pass\n\nclass ZooKeeperServer(object):\n\n    def __init__(self, host='localhost', port='2181', timeout=1):\n        self._address = (host, int(port))\n        self._timeout = timeout\n\n    def get_stats(self):\n        \"\"\" Get ZooKeeper server stats as a map \"\"\"\n        data = self._send_cmd('mntr')\n        stat = self._parse_stat(self._send_cmd('stat'))\n        if data:\n            mntr = self._parse(data)\n            missing = ['zk_zxid', 'zk_zxid_counter', 'zk_zxid_epoch']\n            for m in missing:\n                if m in stat:\n                    mntr[m] = stat[m]\n            return mntr\n        else:\n            return stat\n\n    def _create_socket(self):\n        return socket.socket()\n\n    def _send_cmd(self, cmd):\n        \"\"\" Send a 4letter word command to the server \"\"\"\n        s = self._create_socket()\n        s.settimeout(self._timeout)\n\n        s.connect(self._address)\n        s.send(cmd)\n\n        data = s.recv(2048)\n        s.close()\n\n        return data\n\n    def _parse(self, data):\n        \"\"\" Parse the output from the 'mntr' 4letter word command \"\"\"\n        h = StringIO(data)\n        \n        result = {}\n        for line in h.readlines():\n            try:\n                key, value = self._parse_line(line)\n                result[key] = value\n            except ValueError:\n                pass # ignore broken lines\n\n        return result\n\n    def _parse_stat(self, data):\n        \"\"\" Parse the output from the 'stat' 4letter word command \"\"\"\n        h = StringIO(data)\n\n        result = {}\n        \n        version = h.readline()\n        if version:\n            result['zk_version'] = version[version.index(':')+1:].strip()\n\n        # skip all lines until we find the empty one\n        while h.readline().strip(): pass\n\n        for line in h.readlines():\n            m = re.match('Latency min/avg/max: (\\d+)/(\\d+)/(\\d+)', line)\n            if m is not None:\n                result['zk_min_latency'] = int(m.group(1))\n                result['zk_avg_latency'] = int(m.group(2))\n                result['zk_max_latency'] = int(m.group(3))\n                continue\n\n            m = re.match('Received: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_received'] = int(m.group(1))\n                continue\n\n            m = re.match('Sent: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_sent'] = int(m.group(1))\n                continue\n\n            m = re.match('Outstanding: (\\d+)', line)\n            if m is not None:\n                result['zk_outstanding_requests'] = int(m.group(1))\n                continue\n\n            m = re.match('Mode: (.*)', line)\n            if m is not None:\n                result['zk_server_state'] = m.group(1)\n                continue\n\n            m = re.match('Node count: (\\d+)', line)\n            if m is not None:\n                result['zk_znode_count'] = int(m.group(1))\n                continue\n\n            m = re.match('Zxid: (0x[0-9a-fA-F]+)', line)\n            if m is not None:\n                result['zk_zxid']         = m.group(1)\n                result['zk_zxid_counter'] = int(m.group(1), 16) & int('0xffffffff', 16) # lower 32 bits\n                result['zk_zxid_epoch']   = int(m.group(1), 16) >>32 # high 32 bits\n                continue\n\n        return result \n\n    def _parse_line(self, line):\n        try:\n            key, value = map(str.strip, line.split('\\t'))\n        except ValueError:\n            raise ValueError('Found invalid line: %s' % line)\n\n        if not key:\n            raise ValueError('The key is mandatory and should not be empty')\n\n        try:\n            value = int(value)\n        except (TypeError, ValueError):\n            pass\n\n        return key, value\n\ndef main():\n    opts, args = parse_cli()\n\n    cluster_stats = get_cluster_stats(opts.servers)\n    if opts.output is None:\n        dump_stats(cluster_stats)\n        return 0\n\n    handler = create_handler(opts.output)\n    if handler is None:\n        log.error('undefined handler: %s' % opts.output)\n        sys.exit(1)\n\n    return handler.analyze(opts, cluster_stats)\n\ndef create_handler(name):\n    \"\"\" Return an instance of a platform specific analyzer \"\"\"\n    try:\n        return globals()['%sHandler' % name.capitalize()]()\n    except KeyError:\n        return None\n\ndef get_all_handlers():\n    \"\"\" Get a list containing all the platform specific analyzers \"\"\"\n    return [NagiosHandler, CactiHandler, GangliaHandler]\n\ndef dump_stats(cluster_stats):\n    \"\"\" Dump cluster statistics in an user friendly format \"\"\"\n    for server, stats in cluster_stats.items():\n        print 'Server:', server\n\n        for key, value in stats.items():\n            print \"%30s\" % key, ' ', value\n        print\n\ndef get_cluster_stats(servers):\n    \"\"\" Get stats for all the servers in the cluster \"\"\"\n    stats = {}\n    for host, port in servers:\n        try:\n            zk = ZooKeeperServer(host, port)\n            stats[\"%s:%s\" % (host, port)] = zk.get_stats()\n\n        except socket.error, e:\n            # ignore because the cluster can still work even \n            # if some servers fail completely\n\n            # this error should be also visible in a variable\n            # exposed by the server in the statistics\n\n            logging.info('unable to connect to server '\\\n                '\"%s\" on port \"%s\"' % (host, port))\n\n    return stats\n\n\ndef get_version():\n    return '.'.join(map(str, __version__))\n\n\ndef parse_cli():\n    parser = OptionParser(usage='./check_zookeeper.py <options>', version=get_version())\n\n    parser.add_option('-s', '--servers', dest='servers', \n        help='a list of SERVERS', metavar='SERVERS')\n\n    parser.add_option('-o', '--output', dest='output', \n        help='output HANDLER: nagios, ganglia, cacti', metavar='HANDLER')\n\n    parser.add_option('-k', '--key', dest='key')\n\n    for handler in get_all_handlers():\n        handler.register_options(parser)\n\n    opts, args = parser.parse_args()\n\n    if opts.servers is None:\n        parser.error('The list of servers is mandatory')\n\n    opts.servers = [s.split(':') for s in opts.servers.split(',')]\n\n    return (opts, args)\n\n\nif __name__ == '__main__':\n    sys.exit(main())\n\n"
  },
  {
    "path": "src/contrib/monitoring/ganglia/README",
    "content": "Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nRecipes for ZooKeeper monitoring using Ganglia\n----------------------------------------------\n\nGanglia Install guide: http://sourceforge.net/apps/trac/ganglia/wiki/Ganglia%203.1.x%20Installation%20and%20Configuration \n\nGmond configuration: http://sourceforge.net/apps/trac/ganglia/wiki/Gmond%203.1.x%20General%20Configuration \n\nWARNING: I have wrote these instructions while installing and configuring the plugin on my desktop computer running Ubuntu 9.10. I've installed Ganglia using apt-get.\n\nWARNING: I'm going to make the assumption that you know how to work with Ganglia. I'm also going to assume that you have already installed Gangli and everything works as expected.\n\nYou can monitoring ZooKeeper using Ganglia in two ways:\n\n1. Using a python module:\n\n    WARNING! The python module only works with Ganglia 3.1.x \n\n    a. enable python modules: you can find instructions in modpython.confg\n    b. copy zookeeper.pyconf in /etc/ganglia/conf.d/\n    c. copy zookeeper_ganglia.py in /usr/lib/ganglia/python_plugins\n    d. restart the ganglia-monitor\n\n    This is the recommended way!\n\n2. OR Using check_zookeeper.py and gmetric:\n\n    Monitoring ZooKeeper using Ganglia is a simple as calling:\n\n    ./check_zookeeper.py -o ganglia -s localhost:2181 \n\n    on each of the ZooKeeper cluster nodes. I'm making the assumption that you have already configured gmond and installed gmetric on each node.\n\n"
  },
  {
    "path": "src/contrib/monitoring/ganglia/modpython.conf",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License. */\n\n/* Update gmond.conf */\n\nmodules {\n  module {\n    name = \"python_module\"\n    path = \"/usr/lib/ganglia/modpython.so\"\n    params = \"/usr/lib/ganglia/python_modules\"\n  }\n}\n\ninclude ('/etc/ganglia/conf.d/*.pyconf')\n\n"
  },
  {
    "path": "src/contrib/monitoring/ganglia/zookeeper.pyconf",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License. */\n\n/* Update /etc/ganglia/gmond.conf with the content of this file.  */\n\n/* ATTENTION: Change the host and the port to meet your setup. */\n\nmodules {\n  module {\n    name = \"zookeeper_ganglia\"\n    language = \"python\"\n    param host { value = \"127.0.0.1\" }\n    param port { value = 2181 }\n  }\n}\n\ncollection_group {\n  collect_every = 20\n  time_threshold = 60\n  metric { name = \"zk_avg_latency\" }\n  metric { name = \"zk_max_latency\" }\n  metric { name = \"zk_min_latency\" }\n  metric { name = \"zk_packets_received\" }\n  metric { name = \"zk_packets_sent\" }\n  metric { name = \"zk_outstanding_requests\" }\n  metric { name = \"zk_znode_count\" }\n  metric { name = \"zk_watch_count\" }\n  metric { name = \"zk_ephemerals_count\" }\n  metric { name = \"zk_approximate_data_size\" }\n  metric { name = \"zk_open_file_descriptor_count\" }\n  metric { name = \"zk_max_file_descriptor_count\" }\n  metric { name = \"zk_followers\" }\n  metric { name = \"zk_synced_followers\" }\n  metric { name = \"zk_pending_syncs\" }\n}\n\n"
  },
  {
    "path": "src/contrib/monitoring/ganglia/zookeeper_ganglia.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\" Python Ganglia Module for ZooKeeper monitoring \n\nInspired by: http://gist.github.com/448007\n\nCopy this file to /usr/lib/ganglia/python_plugins\n\n\"\"\"\n\nimport sys\nimport socket\nimport time\nimport re\n\nfrom StringIO import StringIO\n\nTIME_BETWEEN_QUERIES = 20\n\nclass ZooKeeperServer(object):\n\n    def __init__(self, host='localhost', port='2181', timeout=1):\n        self._address = (host, int(port))\n        self._timeout = timeout\n\n    def get_stats(self):\n        \"\"\" Get ZooKeeper server stats as a map \"\"\"\n        data = self._send_cmd('mntr')\n        if data:\n            return self._parse(data)\n        else:\n            data = self._send_cmd('stat')\n            return self._parse_stat(data)\n\n    def _create_socket(self):\n        return socket.socket()\n\n    def _send_cmd(self, cmd):\n        \"\"\" Send a 4letter word command to the server \"\"\"\n        s = self._create_socket()\n        s.settimeout(self._timeout)\n\n        s.connect(self._address)\n        s.send(cmd)\n\n        data = s.recv(2048)\n        s.close()\n\n        return data\n\n    def _parse(self, data):\n        \"\"\" Parse the output from the 'mntr' 4letter word command \"\"\"\n        h = StringIO(data)\n        \n        result = {}\n        for line in h.readlines():\n            try:\n                key, value = self._parse_line(line)\n                result[key] = value\n            except ValueError:\n                pass # ignore broken lines\n\n        return result\n\n    def _parse_stat(self, data):\n        \"\"\" Parse the output from the 'stat' 4letter word command \"\"\"\n        h = StringIO(data)\n\n        result = {}\n        \n        version = h.readline()\n        if version:\n            result['zk_version'] = version[version.index(':')+1:].strip()\n\n        # skip all lines until we find the empty one\n        while h.readline().strip(): pass\n\n        for line in h.readlines():\n            m = re.match('Latency min/avg/max: (\\d+)/(\\d+)/(\\d+)', line)\n            if m is not None:\n                result['zk_min_latency'] = int(m.group(1))\n                result['zk_avg_latency'] = int(m.group(2))\n                result['zk_max_latency'] = int(m.group(3))\n                continue\n\n            m = re.match('Received: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_received'] = int(m.group(1))\n                continue\n\n            m = re.match('Sent: (\\d+)', line)\n            if m is not None:\n                result['zk_packets_sent'] = int(m.group(1))\n                continue\n\n            m = re.match('Outstanding: (\\d+)', line)\n            if m is not None:\n                result['zk_outstanding_requests'] = int(m.group(1))\n                continue\n\n            m = re.match('Mode: (.*)', line)\n            if m is not None:\n                result['zk_server_state'] = m.group(1)\n                continue\n\n            m = re.match('Node count: (\\d+)', line)\n            if m is not None:\n                result['zk_znode_count'] = int(m.group(1))\n                continue\n\n        return result \n\n    def _parse_line(self, line):\n        try:\n            key, value = map(str.strip, line.split('\\t'))\n        except ValueError:\n            raise ValueError('Found invalid line: %s' % line)\n\n        if not key:\n            raise ValueError('The key is mandatory and should not be empty')\n\n        try:\n            value = int(value)\n        except (TypeError, ValueError):\n            pass\n\n        return key, value\n\ndef metric_handler(name):\n    if time.time() - metric_handler.timestamp > TIME_BETWEEN_QUERIES:\n        zk = ZooKeeperServer(metric_handler.host, metric_handler.port, 5)\n        try:\n            metric_handler.info = zk.get_stats()\n        except Exception, e:\n            print >>sys.stderr, e\n            metric_handler.info = {}\n\n    return metric_handler.info.get(name, 0)\n\ndef metric_init(params=None):\n    params = params or {}\n\n    metric_handler.host = params.get('host', 'localhost')\n    metric_handler.port = int(params.get('port', 2181))\n    metric_handler.timestamp = 0\n\n    metrics = {\n        'zk_avg_latency': {'units': 'ms'},\n        'zk_max_latency': {'units': 'ms'},\n        'zk_min_latency': {'units': 'ms'},\n        'zk_packets_received': {\n            'units': 'packets',\n            'slope': 'positive'\n        },\n        'zk_packets_sent': {\n            'units': 'packets',\n            'slope': 'positive'\n        },\n        'zk_outstanding_requests': {'units': 'connections'},\n        'zk_znode_count': {'units': 'znodes'},\n        'zk_watch_count': {'units': 'watches'},\n        'zk_ephemerals_count': {'units': 'znodes'},\n        'zk_approximate_data_size': {'units': 'bytes'},\n        'zk_open_file_descriptor_count': {'units': 'descriptors'},\n        'zk_max_file_descriptor_count': {'units': 'descriptors'},\n        'zk_followers': {'units': 'nodes'},\n        'zk_synced_followers': {'units': 'nodes'},\n        'zk_pending_syncs': {'units': 'syncs'}\n    }\n    metric_handler.descriptors = {}\n    for name, updates in metrics.iteritems():\n        descriptor = {\n            'name': name,\n            'call_back': metric_handler,\n            'time_max': 90,\n            'value_type': 'int',\n            'units': '',\n            'slope': 'both',\n            'format': '%d',\n            'groups': 'zookeeper',\n        }\n        descriptor.update(updates)\n        metric_handler.descriptors[name] = descriptor\n\n    return metric_handler.descriptors.values()\n\ndef metric_cleanup():\n    pass\n\n\nif __name__ == '__main__':\n    ds = metric_init({'host':'localhost', 'port': '2181'})\n    for d in ds:\n        print \"%s=%s\" % (d['name'], metric_handler(d['name']))\n\n\n"
  },
  {
    "path": "src/contrib/monitoring/nagios/README.txt",
    "content": "Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nConfiguration Recipe for monitoring ZooKeeper using Nagios\n----------------------------------------------------------\n\nI will start by making the assumption that you already have an working Nagios install.\n\nWARNING: I have wrote these instructions while installing and configuring the plugin on my desktop computer running Ubuntu 9.10. I've installed Nagios using apt-get.\n\nWARNING: You should customize the config files as suggested in order to match your Nagios and Zookeeper install. \n\nWARNING: This README assumes you know how to configure Nagios and how it works. \n\nWARNING: You should customize the warning and critical levels on service checks to meet your own needs. \n\n1. Install the plugin\n\n$ cp check_zookeeper.py /usr/lib/nagios/plugins/\n\n2. Install the new commands\n\n$ cp zookeeper.cfg /etc/nagios-plugins/config\n\n3. Update the list of servers in zookeeper.cfg for the command 'check_zookeeper' and update the port for the command 'check_zk_node' (default: 2181)\n\n4. Create a virtual host in Nagios used for monitoring the cluster as a whole -OR-  Create a hostgroup named 'zookeeper-servers' and add all the zookeeper cluster nodes. \n\n5. Define service checks like I have ilustrated bellow or just use the provided definitions.\n\ndefine service {\n    use         generic-service\n    host_name   zookeeper-cluster\n    service_description ...\n    check_command check_zookeeper!<exported-var>!<warning-level>!<critical-level>\n}\n\ndefine service {\n    hostgroup_name  zookeeper-servers                    \n    use generic-service                                  \n    service_description ZK_Open_File_Descriptors_Count   \n    check_command check_zk_node!<exported-var>!<warning-level>!<critical-level>\n}\n\nEx: \n\na. check the number of open file descriptors\n\ndefine service{\n        use         generic-service\n        host_name   zookeeper-cluster\n        service_description ZK_Open_File_Descriptor_Count\n        check_command check_zookeeper!zk_open_file_descriptor_count!500!800\n}\n\nb. check the number of ephemerals nodes\n\ndefine service {\n        use generic-service\n        host_name localhost\n        service_description ZK_Ephemerals_Count\n        check_command check_zookeeper!zk_ephemerals_count!10000!100000\n}\n\nc. check the number of open file descriptors for each host in the group\n\ndefine service {\n    hostgroup_name  zookeeper-servers                    \n    use generic-service                                  \n    service_description ZK_Open_File_Descriptors_Count   \n    check_command check_zk_node!zk_open_file_descriptor_count!500!800\n}\n\n"
  },
  {
    "path": "src/contrib/monitoring/nagios/hostgroups.cfg",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# A group containing all the ZooKeeper nodes\n\ndefine hostgroup {\n    hostgroup_name zookeeper-servers\n    alias ZooKeeper Servers\n    members localhost\n}\n\n\n"
  },
  {
    "path": "src/contrib/monitoring/nagios/services.cfg",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# ZooKeeper Node specific services\n\ndefine service {\n    hostgroup_name  zookeeper-servers\n    use generic-service\n    service_description ZK_Open_File_Descriptors_Count\n    check_command check_zk_node!zk_open_file_descriptor_count!500!800\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Ephemerals_Count\n    check_command check_zk_node!zk_ephemerals_count!10000!100000\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Avg_Latency\n    check_command check_zk_node!zk_avg_latency!500!1000\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Max_Latency\n    check_command check_zk_node!zk_max_latency!1000!2000\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Min_Latency\n    check_command check_zk_node!zk_min_latency!500!1000\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Outstanding_Requests\n    check_command check_zk_node!zk_outstanding_requests!20!50\n}\n\ndefine service {\n    hostgroup_name zookeeper-servers\n    use generic-service\n    service_description ZK_Watch_Count\n    check_command check_zk_node!zk_watch_count!100!500\n}\n\n"
  },
  {
    "path": "src/contrib/monitoring/nagios/zookeeper.cfg",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# 'check_zookeeper' command definition\ndefine command {\n    command_name check_zookeeper\n    command_line /usr/lib/nagios/plugins/check_zookeeper.py -s \"localhost:2181,localhost:2182,localhost:2183\" -o nagios -k '$ARG1$' -w '$ARG2$' -c '$ARG3$'\n    # ATTENTION: you should update the list of servers defined above\n}\n\n# 'check_zk_node' command definition\ndefine command {\n    command_name check_zk_node\n    command_line /usr/lib/nagios/plugins/check_zookeeper.py -s $HOSTADDRESS$:2181 -o nagios -k '$ARG1$' -w '$ARG2$' -c '$ARG3$'\n    # ATTENTION: you should update the port. default: 2181\n}\n\n"
  },
  {
    "path": "src/contrib/monitoring/test.py",
    "content": "#! /usr/bin/env python\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport unittest\nimport socket\nimport sys\n\nfrom StringIO import StringIO\n\nfrom check_zookeeper import ZooKeeperServer, NagiosHandler, CactiHandler, GangliaHandler\n\nZK_MNTR_OUTPUT = \"\"\"zk_version\\t3.4.0--1, built on 06/19/2010 15:07 GMT\nzk_avg_latency\\t1\nzk_max_latency\\t132\nzk_min_latency\\t0\nzk_packets_received\\t640\nzk_packets_sent\\t639\nzk_outstanding_requests\\t0\nzk_server_state\\tfollower\nzk_znode_count\\t4\nzk_watch_count\\t0\nzk_ephemerals_count\\t0\nzk_approximate_data_size\\t27\nzk_open_file_descriptor_count\\t22\nzk_max_file_descriptor_count\\t1024\n\"\"\"\n\nZK_MNTR_OUTPUT_WITH_BROKEN_LINES = \"\"\"zk_version\\t3.4.0\nzk_avg_latency\\t23\nbroken-line\n\n\"\"\"\n\nZK_STAT_OUTPUT = \"\"\"Zookeeper version: 3.3.0-943314, built on 05/11/2010 22:20 GMT\nClients:\n /0:0:0:0:0:0:0:1:34564[0](queued=0,recved=1,sent=0)\n\nLatency min/avg/max: 0/40/121\nReceived: 11\nSent: 10\nOutstanding: 0\nZxid: 0x700000003\nMode: follower\nNode count: 4\n\"\"\"\n\nclass SocketMock(object):\n    def __init__(self):\n        self.sent = []\n\n    def settimeout(self, timeout):\n        self.timeout = timeout\n\n    def connect(self, address):\n        self.address = address\n\n    def send(self, data):\n        self.sent.append(data)\n        return len(data)\n\n    def recv(self, size):\n        return ZK_MNTR_OUTPUT[:size]\n\n    def close(self): pass\n\nclass ZK33xSocketMock(SocketMock):\n    def __init__(self):\n        SocketMock.__init__(self)\n        self.got_stat_cmd = False\n\n    def recv(self, size):\n        if 'stat' in self.sent:\n            return ZK_STAT_OUTPUT[:size]\n        else:\n            return ''\n\nclass UnableToConnectSocketMock(SocketMock):\n    def connect(self, _):\n        raise socket.error('[Errno 111] Connection refused')\n\ndef create_server_mock(socket_class):\n    class ZooKeeperServerMock(ZooKeeperServer):\n        def _create_socket(self):\n            return socket_class()\n    return ZooKeeperServerMock()\n\nclass TestCheckZookeeper(unittest.TestCase):\n\n    def setUp(self):\n        self.zk = ZooKeeperServer()\n    \n    def test_parse_valid_line(self):\n        key, value = self.zk._parse_line('something\\t5')\n\n        self.assertEqual(key, 'something')\n        self.assertEqual(value, 5)\n\n    def test_parse_line_raises_exception_on_invalid_output(self):\n        invalid_lines = ['something', '', 'a\\tb\\tc', '\\t1']\n        for line in invalid_lines:\n            self.assertRaises(ValueError, self.zk._parse_line, line)\n\n    def test_parser_on_valid_output(self):\n        data = self.zk._parse(ZK_MNTR_OUTPUT)\n\n        self.assertEqual(len(data), 14)\n        self.assertEqual(data['zk_znode_count'], 4)\n        \n    def test_parse_should_ignore_invalid_lines(self):\n        data = self.zk._parse(ZK_MNTR_OUTPUT_WITH_BROKEN_LINES)\n\n        self.assertEqual(len(data), 2)\n\n    def test_parse_stat_valid_output(self):\n        data = self.zk._parse_stat(ZK_STAT_OUTPUT)\n\n        result = {\n            'zk_version' : '3.3.0-943314, built on 05/11/2010 22:20 GMT',\n            'zk_min_latency' : 0,\n            'zk_avg_latency' : 40,\n            'zk_max_latency' : 121,\n            'zk_packets_received': 11,\n            'zk_packets_sent': 10,\n            'zk_server_state': 'follower',\n            'zk_znode_count': 4\n        }\n        for k, v in result.iteritems():\n            self.assertEqual(v, data[k])\n\n    def test_recv_valid_output(self):\n        zk = create_server_mock(SocketMock)\n\n        data = zk.get_stats()\n        self.assertEqual(len(data), 14)\n        self.assertEqual(data['zk_znode_count'], 4)\n\n    def test_socket_unable_to_connect(self):\n        zk = create_server_mock(UnableToConnectSocketMock)\n\n        self.assertRaises(socket.error, zk.get_stats)\n\n    def test_use_stat_cmd_if_mntr_is_not_available(self):\n        zk = create_server_mock(ZK33xSocketMock)\n\n        data = zk.get_stats()\n        self.assertEqual(data['zk_version'], '3.3.0-943314, built on 05/11/2010 22:20 GMT')\n\nclass HandlerTestCase(unittest.TestCase):\n    \n    def setUp(self):\n        try:\n            sys._stdout\n        except:\n            sys._stdout = sys.stdout\n        \n        sys.stdout = StringIO()\n\n    def tearDown(self):\n        sys.stdout = sys._stdout\n\n    def output(self):\n        sys.stdout.seek(0)\n        return sys.stdout.read()\n\n\nclass TestNagiosHandler(HandlerTestCase):\n\n    def _analyze(self, w, c, k, stats):\n        class Opts(object):\n            warning = w\n            critical = c\n            key = k\n\n        return NagiosHandler().analyze(Opts(), {'localhost:2181':stats})\n\n    def test_ok_status(self):\n        r = self._analyze(10, 20, 'a', {'a': 5})\n\n        self.assertEqual(r, 0)\n        self.assertEqual(self.output(), 'Ok \"a\"!|localhost:2181=5;10;20\\n')\n\n        r = self._analyze(20, 10, 'a', {'a': 30})\n        self.assertEqual(r, 0)\n\n    def test_warning_status(self):\n        r = self._analyze(10, 20, 'a', {'a': 15})\n        self.assertEqual(r, 1)\n        self.assertEqual(self.output(), \n            'Warning \"a\" localhost:2181!|localhost:2181=15;10;20\\n')\n\n        r = self._analyze(20, 10, 'a', {'a': 15})\n        self.assertEqual(r, 1)\n\n    def test_critical_status(self):\n        r = self._analyze(10, 20, 'a', {'a': 30})\n        self.assertEqual(r, 2)\n        self.assertEqual(self.output(),\n            'Critical \"a\" localhost:2181!|localhost:2181=30;10;20\\n')\n\n        r = self._analyze(20, 10, 'a', {'a': 5})\n        self.assertEqual(r, 2)\n\n    def test_check_a_specific_key_on_all_hosts(self):\n        class Opts(object):\n            warning = 10\n            critical = 20\n            key = 'latency'\n\n        r = NagiosHandler().analyze(Opts(), {\n            's1:2181': {'latency': 5},\n            's2:2181': {'latency': 15},\n            's3:2181': {'latency': 35},\n        })\n        self.assertEqual(r, 2)\n        self.assertEqual(self.output(), \n            'Critical \"latency\" s3:2181!|s1:2181=5;10;20 '\\\n            's3:2181=35;10;20 s2:2181=15;10;20\\n')\n\nclass TestCactiHandler(HandlerTestCase):\n    class Opts(object):\n        key = 'a'\n        leader = False\n\n        def __init__(self, leader=False):\n            self.leader = leader\n\n    def test_output_values_for_all_hosts(self):\n        r = CactiHandler().analyze(TestCactiHandler.Opts(), {\n            's1:2181':{'a':1},\n            's2:2181':{'a':2, 'b':3}\n        })\n        self.assertEqual(r, None)\n        self.assertEqual(self.output(), 's1_2181:1 s2_2181:2')\n    \n    def test_output_single_value_for_leader(self):\n        r = CactiHandler().analyze(TestCactiHandler.Opts(leader=True), {\n            's1:2181': {'a':1, 'zk_server_state': 'leader'},\n            's2:2181': {'a':2}\n        })\n        self.assertEqual(r, 0)\n        self.assertEqual(self.output(), '1\\n')\n\n\nclass TestGangliaHandler(unittest.TestCase):\n\n    class TestableGangliaHandler(GangliaHandler):\n        def __init__(self):\n            GangliaHandler.__init__(self)\n            self.cli_calls = []\n    \n        def call(self, cli):\n            self.cli_calls.append(' '.join(cli))\n            \n    def test_send_single_metric(self):\n        class Opts(object):\n            @property\n            def gmetric(self): return '/usr/bin/gmetric'\n        opts = Opts()\n        \n        h = TestGangliaHandler.TestableGangliaHandler()\n        h.analyze(opts, {'localhost:2181':{'latency':10}})\n\n        cmd = \"%s -n latency -v 10 -t uint32\" % opts.gmetric\n        assert cmd in h.cli_calls\n\nif __name__ == '__main__':\n    unittest.main()\n\n"
  },
  {
    "path": "src/contrib/rest/NOTICE.txt",
    "content": "This contrib module includes software developed under the\nCOMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0\n\nThis contrib depends on binary only jar libraries developed at:\n\nhttps://jersey.dev.java.net/\nhttps://grizzly.dev.java.net/\n"
  },
  {
    "path": "src/contrib/rest/README.txt",
    "content": "\nZooKeeper REST implementation using Jersey JAX-RS.\n--------------------------------------------------\n\nThis is an implementation of version 2 of the ZooKeeper REST spec.\n\nNote: This interface is currently experimental, may change at any time,\netc... In general you should be using the Java/C client bindings to access\nthe ZooKeeper server.\n\nThis REST ZooKeeper gateway is useful because most of the languages\nhave built-in support for working with HTTP based protocols.\n\nSee SPEC.txt for details on the REST binding.\n\nQuickstart:\n-----------\n\n1) start a zookeeper server on localhost port 2181\n\n2) run \"ant run\"\n\n3) use a REST client to access the data (see below for more details)\n\n  curl http://localhost:9998/znodes/v1/\n\nor use the provided src/python scripts \n\n  zk_dump_tree.py\n\n\nTests:\n----------\n\n1) the full testsuite can be run via \"ant test\" target\n2) the python client library also contains a test suite\n\nExamples Using CURL\n-------------------\n\nFirst review the spec SPEC.txt in this directory.\n\n#get the root node data\ncurl http://localhost:9998/znodes/v1/\n\n#get children of the root node\ncurl http://localhost:9998/znodes/v1/?view=children\n\n#get \"/cluster1/leader\" as xml (default is json)\ncurl -H'Accept: application/xml' http://localhost:9998/znodes/v1/cluster1/leader\n\n#get the data as text\ncurl -w \"\\n%{http_code}\\n\" \"http://localhost:9998/znodes/v1/cluster1/leader?dataformat=utf8\"\n\n#set a node (data.txt contains the ascii text you want to set on the node)\ncurl -T data.txt -w \"\\n%{http_code}\\n\" \"http://localhost:9998/znodes/v1/cluster1/leader?dataformat=utf8\"\n\n#create a node\ncurl -d \"data1\" -H'Content-Type: application/octet-stream' -w \"\\n%{http_code}\\n\" \"http://localhost:9998/znodes/v1/?op=create&name=cluster2&dataformat=utf8\"\n\ncurl -d \"data2\" -H'Content-Type: application/octet-stream' -w \"\\n%{http_code}\\n\" \"http://localhost:9998/znodes/v1/cluster2?op=create&name=leader&dataformat=utf8\"\n\n#create a new session\ncurl -d \"\" -H'Content-Type: application/octet-stream' -w \"\\n%{http_code}\\n\" \"http://localhost:9998/sessions/v1/?op=create&expire=10\"\n\n#session heartbeat\ncurl -X \"PUT\" -H'Content-Type: application/octet-stream' -w \"\\n%{http_code}\\n\" \"http://localhost:9998/sessions/v1/02dfdcc8-8667-4e53-a6f8-ca5c2b495a72\"\n\n#delete a session\ncurl -X \"DELETE\" -H'Content-Type: application/octet-stream' -w \"\\n%{http_code}\\n\" \"http://localhost:9998/sessions/v1/02dfdcc8-8667-4e53-a6f8-ca5c2b495a72\"\n\n\n"
  },
  {
    "path": "src/contrib/rest/SPEC.txt",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nA REST HTTP gateway for ZooKeeper\n=================================\n\nSpecification Version: 2\n\nZooKeeper is meant to enable distributed coordination and also store\nsystem configuration and other relatively small amounts of information\nthat must be stored in a persistent and consistent manner. The\ninformation stored in ZooKeeper is meant to be highly available to a\nlarge number of nodes in a distributed-computing cluster.\n\nZooKeeper offers a client-side library that supports rich semantics\nthat include strict ordering guarantees on operations, the creation of\nephemeral znodes, and the ability to watch for changes to state.\nHowever, where clients need simple \"CRUD\" (create, read, update,\ndelete) operations, the ZooKeeper libraries can be cumbersome, both to\nthe programmers who have to use them (who are increasingly used to\nREST-style APIs), and to the operators who have to deploy and update\nthem (for whom deploying and updating client libraries can be very\npainful).\n\nIt turns out that most languages comes with client libraries for HTTP\nthat are easy and familiar to program against, and deployed as part of\nthe language runtime. Thus, for simple CRUD clients, an HTTP gateway\nwould be a less cumbersome interface than the ZooKeeper library.\n\nThis document describes a gatway for using HTTP to interact with a\nZooKeeper repository.\n\nBinding ZooKeeper to HTTP\n-------------------------\n\nEncoding\n--------\n\nUTF-8 unless otherwise noted\n\nPaths\n-----\n\nA ZooKeeper paths are mapped to IRIs and URIs as follows. ZK paths\nare converted to IRIs by simply percent-encoding any characters in the\nZK path that are not allowed in IRI paths. ZK paths are converted to\nURIs by mapping them first to IRIs, then converting to URIs in the\nstandard way.\n\nGoing from URIs and IRIs is the reverse of the above but for one\ndifference: any \".\" and \"..\" segments in an IRI or URI must be folded\nbefore conversion. (Fortunately, ZK does not allow \".\" and \"..\"\nsegments in its paths.)\n\nZK and IRIs recommend the same practices when it comes to Unicode\nnormalization: ultimately, normalization is left to application\ndesigners, but both recommend that application designers use NFC as a\nbest practice.\n\nRoot\n----\n\nThe following examples assume that the ZooKeeper znode heirarchy is\nbound to the root of the HTTP servers namespace. This may not be the\ncase in practice however, the gateway may bind to some prefix, for\nexample the URL for accessing /a/b/c may be:\n\n  http://localhost/zookeeper/znodes/v1/a/b/c\n\nThis is perfectly valid. Users of the REST service should be aware of\nthis fact and code their clients to support any root (in this case\n\"/zookeeper\" on the server localhost).\n\n\nBasics: GET, PUT, HEAD, and DELETE\n----------------------------------\n\nHTTP's GET, PUT, HEAD, and DELETE operations map naturally to\nZooKeeper's \"get,\" \"set,\" \"exists,\" and \"delete\" operations.\n\nZooKeeper znodes have a version number that changes each time the\nznode's value is updated. This number is returned by \"get,\" \"set,\" and\n\"exists\" operations. The \"set\" and \"delete\" operations optionally take\na version number. If one is supplied, then \"set\" or \"delete\" will fail\nif the current version of the znode doesn't match the version-number\nsupplied in the call. This mechanism supports atomic read-modify-write\ncycles. Set/delete requests may include an optional parameter\n\"version\" which defaults to no version check.\n\n\nGetting ZooKeeper children\n--------------------------\n\nWe overload the GET method to return the children of a ZooKeeper. In\nparticular, the GET method takes an optional parameter \"view\" which\ncould be set to one of type values, either \"data\" or \"children\". The\ndefault is \"data\". Thus, to get the children of a znode named\n\"/a/b/c\", then the GET request should start:\n\n  GET /znodes/v1/a/b/c?view=children HTTP/1.1\n\nIf the requested view is \"data\", then the data of a znode is returned\nas described in the previous section. If the requested view is\n\"children\", then a list of children is returned in either an XML\ndocument, or in a JSON object. (The default is JSON, but this can be\ncontrolled changed by setting the Accept header.)\n\n\nCreating a ZooKeeper session\n----------------------------\n\nIn order to be able to create ephemeral nodes you first need to start\na new session.\n\n  POST /sessions/v1?op=create&expire=<SECONDS> HTTP/1.1\n\nIf the session creation is successful, then a 201 code will be returned.\n\nA session is just an UUID that you can pass around as a parameter and\nthe REST server will foward your request on the attached persistent \nconnection.\n\nKeeping a session alive\n-----------------------\n\nTo keep a session alive you must send hearbeat requests:\n\n  PUT /sessions/v1/<SESSION-UUID> HTTP/1.1\n\nClosing a ZooKeeper session\n---------------------------\n\nYou can close a connection by sending a DELETE request.\n\n  DELETE /sessions/v1/<SESSION-UUID> HTTP/1.1\n\nIf you don't close a session it will automatically expire after\nthe amount of time you specified on creation. \n\nCreating a ZooKeeper znode\n--------------------------\n\nWe use the POST method to create a ZooKeeper znode. For example, to\ncreate a znode named \"c\" under a parent named \"/a/b\", then the POST\nrequest should start:\n\n  POST /znodes/v1/a/b?op=create&name=c HTTP/1.1\n\nIf the creation is successful, then a 201 code will be returned. If\nit fails, then a number of different codes might be returned\n(documented in a later subsection).\n\nZooKeeper's create operation has a flag that tells the server to\nappend a sequence-number to the client-supplied znode-name in order to\nmake the znode-name unique. If you set this flag and ask to create a\nznode named \"/a/b/c\", and a znode named \"/a/b\" already exists, then\n\"create\" will create a znode named \"/a/b/c-#\" instead, where \"#\" is and\ninteger required to generate a unique name in for format %10d.\n\nTo obtain this behavior, an additional \"sequence=true\" parameter\nshould be added to the parameters of the POST. (Note that \"sequence\"\nis an optional parameter, that defaults to \"false\"; this default may\nbe provided explicitly if desired.)\n\nOn success the actual path of the created znode will be returned.\n\nIf you want to create an ephemeral node you need to specify an\nadditional \"ephemeral=true\" parameter. (Note that \"ephemeral\" is an optional\nparameter, that defaults to \"false\")\n\n(Note: ZooKeeper also allows the client to set ACLs for the\nnewly-created znode. This feature is not currently supported by the\nHTTP gateway to ZooKeeper.)\n\n\nContent types and negotiation\n-----------------------------\n\nZooKeeper REST gateway implementations may support three content-types\nfor request and response messages:\n\n* application/octet-stream\n\n  HEAD   - returns nothing (note below: status = 204)\n  GET    - returns the znode data as an octet-stream\n  PUT    - send binary data, returns nothing\n  POST   - send binary data, returns the name of the znode\n  DELETE - returns nothing\n\n  For PUT and HEAD some other content-type (i.e. JSON or XML) must be\n  used to access the Stat information of a znode.\n\n* application/json, application/javascript & application/xml\n\n  HEAD   - returns nothing\n  GET    - returns a STAT or CHILD structure\n  PUT    - send binary data, returns a STAT structure (sans data field)\n  POST   - send binary data, returns a PATH structure\n  DELETE - returns nothing\n\n  (structures defined below)\n\n  Results returning DATA may include an optional \"dataformat\"\n  parameter which has two possible values; base64 (default) or\n  utf8. This allows the caller to control the format of returned data\n  and may simplify usage -- for example cat'ing results to the command\n  line with something like curl, or accessing a url through a browser.\n  Care should be exercised however, if utf8 is used on non character\n  data errors may result.\n\n  \"application/javascript\" requests may include an optional \"callback\"\n  parameter. The response is wrapped in a callback method of your\n  choice. e.g. appending &callback=foo to your request will result in\n  a response body of: foo(...). Callbacks may only contain\n  alphanumeric characters and underscores.\n\nPATH\n  path : string\n  uri: string\n\n  path is the full path to the znode as seen by ZooKeeper\n\n  uri is the full URI of the znode as seen by the REST server, does not\n  include any query parameters (i.e. it's the path to the REST resource)\n\nSESSION\n  id : string UUID\n  uri : string\n\nCHILD\n  PATH\n  child_uri_template: string\n  children : [ string* ]\n\n  The children list of strings contains only the name of the child\n  znodes, not the full path.\n\n  child_uri_template is a template for URI of child znodes as seen by the\n  REST server. e.g. \"http://localhost:9998/znodes/v1/foo/{child}\", where\n  foo is the parent node, and {child} can be substituted with the name\n  of each child in the children array in order to access that resource.\n  This template is provided to simplify child access.\n    \nSTAT\n  PATH\n  encoding : value of \"base64\" or \"utf8\"\n  data     : base64 or utf8 encoded string\n  stat :\n    czxid          : number\n    mzxid          : number\n    ctime          : number\n    mtime          : number\n    version        : number\n    cversion       : number\n    aversion       : number\n    ephemeralOwner : number\n    datalength     : number\n    numChildren    : number\n    pzxid          : number\n\n\nError Codes\n-----------\n\nThe ZooKeeper gateway uses HTTP response codes as follows:\n\n   * 200 (Success) - ZOK for \"get\" \"set\" \"delete\", \"yes\" case of \"exists\" (json/xml)\n   * 201 (Created) - ZOK for \"create\"\n   * 204 (No Content) - ZOK for \"yes\" case of \"exists\" (octet)\n   * 400 (Bad Request) - ZINVALIDACL, ZBADARGUMENTS, version param not a number\n   * 401 (Unauthorized) - ZAUTHFAILED\n   * 404 (Not Found) - ZOK for \"no\" case of \"exists;\" ZNONODE for \"get,\" \"set,\" and \"delete\"\n   * 409 (Conflict) - ZNODEEXISTS, ZNONODE for \"create,\" ZNOTEMPTY, \n   * 412 (Precondition Failed) - ZBADVERSION\n   * 415 (Unsupported Media Type) - if content-type of PUT or POST is not \"application/octet-stream\"\n   * 500 (Internal Server Error) - Failure in gateway code\n   * 501 (Not Implemented) - HTTP method other than GET, PUT, HEAD, DELETE\n   * 502 (Bad Gateway) - All other ZooKeeper error codes\n   * 503 (Service Unavailable) - ZSESSIONEXPIRED, ZCONNECTIONLOSS, (gateway will try to reestablish the connection, but will not hold the request waiting...)\n   * 504 (Gateway Timeout) - ZOPERATIONTIMEOUT, or ZooKeeper does not return in a timely manner\n\nNote that these are the codes used by the HTTP-to-Gateway software\nitself. Depending on how this software is configured into a Web\nserver, the resulting Web Server might behave differently, e.g., it\nmight do redirection, check other headers, etc.\n\nError Messages\n--------------\n\nError messages are returned to the caller, format is dependent on the\nformat requested in the call. \n\n* application/octet-stream\n\n  A string containing the error message. It should include the request\n  and information detailing the reason for the error.\n\n* application/json\n\n  { \"request\":\"GET /a/b/c\", \"message\":\"Node doesn't exist\" }\n\n* application/xml\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n  <request>GET /a/b/c</request>\n  <message>Node doesn't exist</message>\n</error>\n\n\nBinding ZooKeeper to an HTTP server\n-----------------------------------\n\nIt might be sage to assume that everyone is happy to run an Apache\nserver, and thus write a \"mod_zookeeper\" for Apache that works only\nfor the Apache Web Server. However, different operational\nenvironments prefer different Web Servers, and it would be nice to\nsupport more than one Web server.\n\nIssues:\n\n   * Configuration.\n\n   * Defining a root: Need to provide a URL alias and associate it\n     with a server. Need to be able to map different aliases to\n     different servers (implemented via multiple ZK connections).\n\n   * Sharing connection across multiple processes.\n\n   * Asynchronous.\n\n   * Adaptors.\n\n   * Code re-use.\n\n\nAuthentication -- TBD, not currently supported\n\n...the config file should contain authentication material for the gateway\n\n...the config file should contain an ACL list to be passed along to \"create\"\n\n...would we ever want to authenticate each request to ZooKeeper?...\n"
  },
  {
    "path": "src/contrib/rest/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"rest\" default=\"jar\">\n  <import file=\"../build-contrib.xml\"/>\n\n\t<property name=\"test.build.dir\" value=\"${build.test}\" />\n    <property name=\"test.src.dir\" value=\"src/test\"/>\n    <property name=\"test.log.dir\" value=\"${test.build.dir}/logs\" />\n    <property name=\"test.data.dir\" value=\"${test.build.dir}/data\" />\n    <property name=\"test.data.upgrade.dir\" value=\"${test.data.dir}/upgrade\" />\n    <property name=\"test.tmp.dir\" value=\"${test.build.dir}/tmp\" />\n    <property name=\"test.output\" value=\"no\" />\n    <property name=\"test.timeout\" value=\"900000\" />\n    <property name=\"test.junit.output.format\" value=\"plain\" />\n    <property name=\"test.junit.fork.mode\" value=\"perTest\" />\n    <property name=\"test.junit.printsummary\" value=\"yes\" />\n    <property name=\"test.junit.haltonfailure\" value=\"no\" />\n    <property name=\"test.junit.maxmem\" value=\"512m\" />\n\n    <!-- ====================================================== -->\n    <!-- Macro definitions                                      -->\n    <!-- ====================================================== -->\n    <macrodef name=\"macro_tar\" description=\"Worker Macro for tar\">\n      <attribute name=\"param.destfile\"/>\n      <element name=\"param.listofitems\"/>\n      <sequential>\n        <tar compression=\"gzip\" longfile=\"gnu\"\n             destfile=\"@{param.destfile}\">\n          <param.listofitems/>\n        </tar>\n      </sequential>\n    </macrodef>\n\n  <target name=\"package\" depends=\"jar\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${dist.dir}${package.share}/contrib/${name}\"/>\n    <copy todir=\"${dist.dir}${package.share}/contrib/${name}\">\n      <fileset dir=\"${build.dir}\">\n        <include name=\"zookeeper-${version}-${name}.jar\" />\n      </fileset>\n    </copy>\n    <copy todir=\"${dist.dir}${package.share}/contrib/${name}/lib\">\n      <fileset dir=\"${build.dir}/lib\" />\n    </copy>\n    <copy todir=\"${dist.dir}${package.share}/contrib/${name}/conf\">\n      <fileset dir=\"conf\" />\n    </copy>\n  </target>\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\"\n              value=\"${build.dir}/zookeeper-${version}-${name}.jar\"/>\n  </target>\n\n  <target name=\"compile\" depends=\"ivy-retrieve,zookeeperbuildcontrib.compile\"/>\n\n  <target name=\"test\"\n          depends=\"compile-test,test-init,test-category,test-start,junit.run,test-stop\" />\n\n\t<target name=\"compile-test\" depends=\"ivy-retrieve-test,compile\">\n  \t\t<property name=\"target.jdk\" value=\"${ant.java.version}\" />\t\n\t\t<property name=\"src.test.local\" location=\"${basedir}/src/test\" />\n\t\t<mkdir dir=\"${build.test}\"/>\n\t\t<javac srcdir=\"${src.test.local}\" \n\t\t\tdestdir=\"${build.test}\" \n\t\t\ttarget=\"${target.jdk}\" \n\t\t\tdebug=\"on\" >\n\t\t\t<classpath refid=\"classpath\" />\n\t\t</javac>\n\t</target>\n\t\n    <target name=\"test-init\" depends=\"jar,compile-test\">\n        <delete dir=\"${test.log.dir}\" />\n        <delete dir=\"${test.tmp.dir}\" />\n        <delete dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.tmp.dir}\" />\n        <mkdir dir=\"${test.data.dir}\" />\n    </target>\n\n    <target name=\"test-start\">\n      <exec executable=\"${test.src.dir}/zkServer.sh\">\n        <arg value=\"startClean\"/>\n      </exec>\n    </target>\n\n    <target name=\"test-stop\">\n      <exec executable=\"${test.src.dir}/zkServer.sh\">\n        <arg value=\"stop\"/>\n      </exec>\n    </target>\n\n\t<target name=\"test-category\">\n         <property name=\"test.category\" value=\"\"/>\n    </target>\n\n\t<target name=\"junit.run\">\n\t\t<echo message=\"${test.src.dir}\" />\n        <junit showoutput=\"${test.output}\"\n               printsummary=\"${test.junit.printsummary}\"\n               haltonfailure=\"${test.junit.haltonfailure}\"\n               fork=\"yes\"\n               forkmode=\"${test.junit.fork.mode}\"\n               maxmemory=\"${test.junit.maxmem}\"\n               dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n          <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n          <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n          <sysproperty key=\"log4j.configuration\"\n                    value=\"file:${basedir}/conf/log4j.properties\" />\n          <classpath refid=\"classpath\"/>\n          <classpath>\n             <pathelement path=\"${build.test}\" />\n          </classpath>\n          <formatter type=\"${test.junit.output.format}\" />\n          <batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n              <fileset dir=\"${test.src.dir}\"\n                     includes=\"**/*${test.category}Test.java\"/>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n              <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n          </batchtest>\n       </junit>\n       <fail if=\"tests.failed\">Tests failed!</fail>\n    </target>\n\n  <target name=\"jar\" depends=\"checkMainCompiled, setjarname, compile\">\n    <echo message=\"contrib: ${name}\"/>\n    <jar jarfile=\"${jarname}\">\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset dir=\"${build.classes}\"/>\n      <fileset dir=\"${build.test}\"/>\n    </jar>\n  </target>\n\n  <target name=\"run\" depends=\"jar\">\n    <echo message=\"contrib: ${name}\"/>\n    <java classname=\"org.apache.zookeeper.server.jersey.RestMain\" fork=\"true\">\n      <classpath>\n        <pathelement path=\"${jarname}\" />\n        <fileset dir=\"${build.dir}/lib\" includes=\"*.jar\"/>\n        <fileset dir=\"${zk.root}/build\" includes=\"zookeeper-*.jar\"/>\n        <pathelement path=\"${zk.root}/src/contrib/${name}/conf\" />\n        <fileset dir=\"${zk.root}/src/java/lib\">\n          <include name=\"**/*.jar\" />\n        </fileset>\n      </classpath>\n    </java>\n  </target>\n\n  <target name=\"tar\" depends=\"clean, jar\">\n    <echo message=\"building tar.gz: ${name}\" />\n    <macro_tar param.destfile=\"${build.dir}/zookeeper-${version}-${name}.tar.gz\">\n      <param.listofitems>\n        <tarfileset dir=\"${build.dir}/lib\" prefix=\"lib\" includes=\"**/*.jar\" />\n        <tarfileset file=\"${build.dir}/zookeeper-*-rest.jar\" />\n        <tarfileset dir=\"${zk.root}/build\" includes=\"zookeeper-*.jar\" prefix=\"lib\" />\n        <tarfileset dir=\"${zk.root}/src/contrib/${name}/conf\" prefix=\"conf\" />\n        <tarfileset dir=\"${zk.root}/src/java/lib\" prefix=\"lib\" includes=\"**/*.jar\" />\n        <tarfileset file=\"${zk.root}/src/contrib/${name}/rest.sh\" />\n      </param.listofitems>\n    </macro_tar>\n  </target>\n\n</project>\n\n"
  },
  {
    "path": "src/contrib/rest/conf/keys/README",
    "content": "\nIn order to generate .jks (java keystore files) you need to use keytool.\n\nThe password for the existing .jks is \"123456\" (without quotes).\n\nSome tutorials:\n - http://www.mobilefish.com/tutorials/java/java_quickguide_keytool.html\n\n"
  },
  {
    "path": "src/contrib/rest/conf/log4j.properties",
    "content": "#\n# \n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n#   http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# \n#\n\n#\n# ZooKeeper Logging Configuration\n#\n\n# Format is \"<default threshold> (, <appender>)+\n\n# DEFAULT: console appender only\nlog4j.rootLogger=INFO, CONSOLE\n\n# Example with rolling log file\n#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE\n\n# Example with rolling log file and tracing\n#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE\n\n#\n# Log INFO level and above messages to the console\n#\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.Threshold=INFO\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p - [%t:%C{1}@%L] - %m%n\n\n#\n# Add ROLLINGFILE to rootLogger to get log file output\n#    Log DEBUG level and above messages to a log file\nlog4j.appender.ROLLINGFILE=org.apache.log4j.ConsoleAppender\nlog4j.appender.ROLLINGFILE.Threshold=DEBUG\nlog4j.appender.ROLLINGFILE.File=bookkeeper.log\nlog4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} - %-5p - [%t:%C{1}@%L] - %m%n\n\n# Max log file size of 10MB\nlog4j.appender.ROLLINGFILE.MaxFileSize=10MB\n# uncomment the next line to limit number of backup files\n#log4j.appender.ROLLINGFILE.MaxBackupIndex=10\n\n#\n# Add TRACEFILE to rootLogger to get log file output\n#    Log DEBUG level and above messages to a log file\nlog4j.appender.TRACEFILE=org.apache.log4j.FileAppender\nlog4j.appender.TRACEFILE.Threshold=TRACE\nlog4j.appender.TRACEFILE.File=bookkeeper_trace.log\n\nlog4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout\n### Notice we are including log4j's NDC here (%x)\nlog4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L][%x] - %m%n\n"
  },
  {
    "path": "src/contrib/rest/conf/rest.properties",
    "content": "#\n# \n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n#   http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# \n#\n\n#\n# ZooKeeper REST Gateway Configuration file\n#\n\nrest.port = 9998\n\n#\n# Endpoint definition\n#\n\n# plain configuration <context-path>;<host-port>\nrest.endpoint.1 = /;localhost:2181,localhost:2182\n\n# ... or chrooted to /zookeeper\n# rest.endpoint.1 = /;localhost:2181,localhost:2182/zookeeper\n\n# HTTP Basic authentication for this endpoint\n# rest.endpoint.1.http.auth = root:root1\n\n# create -e /a data digest:'demo:ojnHEyje6F33LLzGVzg+yatf4Fc=':cdrwa\n# any session on this endpoint will use authentication\n# rest.endpoint.1.zk.digest = demo:test\n\n# you can easily generate the ACL using Python:\n# import sha; sha.sha('demo:test').digest().encode('base64').strip()\n\n#\n# ... you can define as many endpoints as you wish\n#\n\n# rest.endpoint.2 = /restricted;localhost:2181\n# rest.endpoint.2.http.auth = admin:pass\n\n# rest.endpoint.3 = /cluster1;localhost:2181,localhost:2182\n# ** you should configure one end-point for each ZooKeeper cluster\n# etc.\n\n# Global HTTP Basic Authentication \n# You should also enable HTTPS-only access\n# The authentication credentials are sent as plain text\n\n# rest.http.auth = guest:guest1\n\n# Uncomment the lines bellow to allow https-only access\n\n# rest.ssl = true\n# rest.ssl.jks = keys/rest.jks\n# rest.ssl.jks.pass = 123456\n "
  },
  {
    "path": "src/contrib/rest/ivy.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<ivy-module version=\"2.0\"\n            xmlns:e=\"http://ant.apache.org/ivy/extra\">\n\n  <info organisation=\"org.apache.zookeeper\"\n        module=\"${name}\" revision=\"${version}\">\n    <license name=\"Apache 2.0\"/>\n    <ivyauthor name=\"Apache ZooKeeper\" url=\"http://zookeeper.apache.org\"/>\n    <description>ZooKeeper REST</description>\n  </info>\n\n  <configurations defaultconfmapping=\"default\">\n    <conf name=\"default\"/>\n    <conf name=\"test\"/>\n  </configurations>\n\n  <dependencies>\n    <dependency org=\"org.slf4j\" name=\"slf4j-api\" rev=\"1.6.1\"/>\n    <dependency org=\"org.slf4j\" name=\"slf4j-log4j12\" rev=\"1.6.1\" transitive=\"false\"/>\n  \n    <!-- transitive false turns off dependency checking, log4j deps seem borked -->\n    <dependency org=\"log4j\" name=\"log4j\" rev=\"1.2.15\" transitive=\"false\"/>\n    <dependency org=\"asm\" name=\"asm\" rev=\"3.1\" />\n    <dependency org=\"com.sun.grizzly\" name=\"grizzly-servlet-webserver\" rev=\"1.9.8\" />\n    <dependency org=\"com.sun.jersey\" name=\"jersey-server\" rev=\"1.1.5.1\" />\n    <dependency org=\"com.sun.jersey\" name=\"jersey-json\" rev=\"1.1.5.1\" />\n\n    <dependency org=\"junit\" name=\"junit\" rev=\"4.8.1\" conf=\"test->default\"/>\n    <dependency org=\"com.sun.jersey\" name=\"jersey-client\" rev=\"1.1.5.1\" conf=\"test->default\"/>\n  </dependencies>\n\n</ivy-module>\n"
  },
  {
    "path": "src/contrib/rest/rest.sh",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#\n# If this scripted is run out of /usr/bin or some other system bin directory\n# it should be linked to and not copied. Things like java jar files are found\n# relative to the canonical path of this script.\n#\n\n# Only follow symlinks if readlink supports it\nif readlink -f \"$0\" > /dev/null 2>&1\nthen\n  ZKREST=`readlink -f \"$0\"`\nelse\n  ZKREST=\"$0\"\nfi\nZKREST_HOME=`dirname \"$ZKREST\"`\n\nif $cygwin\nthen\n    # cygwin has a \"kill\" in the shell itself, gets confused\n    KILL=/bin/kill\nelse\n    KILL=kill\nfi\n\nif [ -z $ZKREST_PIDFILE ]\n    then ZKREST_PIDFILE=$ZKREST_HOME/server.pid\nfi\n\nZKREST_MAIN=org.apache.zookeeper.server.jersey.RestMain\n\nZKREST_CONF=$ZKREST_HOME/conf\nZKREST_LOG=$ZKREST_HOME/zkrest.log\n\nCLASSPATH=\"$ZKREST_CONF:$CLASSPATH\"\n\nfor i in \"$ZKREST_HOME\"/lib/*.jar\ndo\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\nfor i in \"$ZKREST_HOME\"/zookeeper-*.jar\ndo\n    CLASSPATH=\"$i:$CLASSPATH\"\ndone\n\ncase $1 in\nstart)\n    echo  \"Starting ZooKeeper REST Gateway ... \"\n    java  -cp \"$CLASSPATH\" $JVMFLAGS $ZKREST_MAIN >$ZKREST_LOG 2>&1 &\n    /bin/echo -n $! > \"$ZKREST_PIDFILE\"\n    echo STARTED\n    ;;\nstop)\n    echo \"Stopping ZooKeeper REST Gateway ... \"\n    if [ ! -f \"$ZKREST_PIDFILE\" ]\n    then\n    echo \"error: could not find file $ZKREST_PIDFILE\"\n    exit 1\n    else\n    $KILL -9 $(cat \"$ZKREST_PIDFILE\")\n    rm \"$ZKREST_PIDFILE\"\n    echo STOPPED\n    fi\n    ;;\nrestart)\n    shift\n    \"$0\" stop ${@}\n    sleep 3\n    \"$0\" start ${@}\n    ;;\n*)\n    echo \"Usage: $0 {start|stop|restart}\" >&2\n\nesac\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/RestMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URISyntaxException;\nimport java.net.URL;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.jersey.cfg.Credentials;\nimport org.apache.zookeeper.server.jersey.cfg.Endpoint;\nimport org.apache.zookeeper.server.jersey.cfg.RestCfg;\nimport org.apache.zookeeper.server.jersey.filters.HTTPBasicAuth;\n\nimport com.sun.grizzly.SSLConfig;\nimport com.sun.grizzly.http.embed.GrizzlyWebServer;\nimport com.sun.grizzly.http.servlet.ServletAdapter;\nimport com.sun.jersey.spi.container.servlet.ServletContainer;\n\n/**\n * Demonstration of how to run the REST service using Grizzly\n */\npublic class RestMain {\n\n   private static Logger LOG = LoggerFactory.getLogger(RestMain.class);\n\n   private GrizzlyWebServer gws;\n   private RestCfg cfg;\n\n   public RestMain(RestCfg cfg) {\n       this.cfg = cfg;\n   }\n\n   public void start() throws IOException {\n       System.out.println(\"Starting grizzly ...\");\n\n       boolean useSSL = cfg.useSSL();\n       gws = new GrizzlyWebServer(cfg.getPort(), \"/tmp/23cxv45345/2131xc2/\", useSSL);\n       // BUG: Grizzly needs a doc root if you are going to register multiple adapters\n\n       for (Endpoint e : cfg.getEndpoints()) {\n           ZooKeeperService.mapContext(e.getContext(), e);\n           gws.addGrizzlyAdapter(createJerseyAdapter(e), new String[] { e\n                   .getContext() });\n       }\n       \n       if (useSSL) {\n           System.out.println(\"Starting SSL ...\");\n           String jks = cfg.getJKS(\"keys/rest.jks\");\n           String jksPassword = cfg.getJKSPassword();\n\n           SSLConfig sslConfig = new SSLConfig();\n           URL resource = getClass().getClassLoader().getResource(jks);\n           if (resource == null) {\n               LOG.error(\"Unable to find the keystore file: \" + jks);\n               System.exit(2);\n           }\n           try {\n               sslConfig.setKeyStoreFile(new File(resource.toURI())\n                       .getAbsolutePath());\n           } catch (URISyntaxException e1) {\n               LOG.error(\"Unable to load keystore: \" + jks, e1);\n               System.exit(2);\n           }\n           sslConfig.setKeyStorePass(jksPassword);\n           gws.setSSLConfig(sslConfig);\n       }\n\n       gws.start();\n   }\n\n   public void stop() {\n       gws.stop();\n       ZooKeeperService.closeAll();\n   }\n\n   private ServletAdapter createJerseyAdapter(Endpoint e) {\n       ServletAdapter jersey = new ServletAdapter();\n\n       jersey.setServletInstance(new ServletContainer());\n       jersey.addInitParameter(\"com.sun.jersey.config.property.packages\",\n               \"org.apache.zookeeper.server.jersey.resources\");\n       jersey.setContextPath(e.getContext());\n\n       Credentials c = Credentials.join(e.getCredentials(), cfg\n               .getCredentials());\n       if (!c.isEmpty()) {\n           jersey.addFilter(new HTTPBasicAuth(c), e.getContext()\n                   + \"-basic-auth\", null);\n       }\n\n       return jersey;\n   }\n\n   /**\n    * The entry point for starting the server\n    * \n    */\n   public static void main(String[] args) throws Exception {\n       RestCfg cfg = new RestCfg(\"rest.properties\");\n\n       final RestMain main = new RestMain(cfg);\n       main.start();\n\n       Runtime.getRuntime().addShutdownHook(new Thread() {\n           @Override\n           public void run() {\n               main.stop();\n               System.out.println(\"Got exit request. Bye.\");\n           }\n       });\n\n       printEndpoints(cfg);\n       System.out.println(\"Server started.\");\n   }\n\n   private static void printEndpoints(RestCfg cfg) {\n       int port = cfg.getPort();\n\n       for (Endpoint e : cfg.getEndpoints()) {\n\n           String context = e.getContext();\n           if (context.charAt(context.length() - 1) != '/') {\n               context += \"/\";\n           }\n\n           System.out.println(String.format(\n                   \"Started %s - WADL: http://localhost:%d%sapplication.wadl\",\n                   context, port, context));\n       }\n   }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/ZooKeeperService.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.TreeSet;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.server.jersey.cfg.Endpoint;\n\n/**\n * Singleton which provides JAX-RS resources access to the ZooKeeper client.\n * There's a single session for each base uri (so usually just one).\n */\npublic class ZooKeeperService {\n\n   private static Logger LOG = LoggerFactory.getLogger(ZooKeeperService.class);\n\n   /** Map base uri to ZooKeeper host:port parameters */\n   private static Map<String, Endpoint> contextMap = new HashMap<String, Endpoint>();\n\n   /** Map base uri to ZooKeeper session */\n   private static Map<String, ZooKeeper> zkMap = new HashMap<String, ZooKeeper>();\n\n   /** Session timers */\n   private static Map<String, SessionTimerTask> zkSessionTimers = new HashMap<String, SessionTimerTask>();\n   private static Timer timer = new Timer();\n\n   /** Track the status of the ZooKeeper session */\n   private static class MyWatcher implements Watcher {\n       final String contextPath;\n\n       /** Separate watcher for each base uri */\n       public MyWatcher(String contextPath) {\n           this.contextPath = contextPath;\n       }\n\n       /**\n        * Track state - in particular watch for expiration. if it happens for\n        * re-creation of the ZK client session\n        */\n       synchronized public void process(WatchedEvent event) {\n           if (event.getState() == KeeperState.Expired) {\n               close(contextPath);\n           }\n       }\n   }\n\n   /** ZooKeeper session timer */\n   private static class SessionTimerTask extends TimerTask {\n\n       private int delay;\n       private String contextPath, session;\n       private Timer timer;\n\n       public SessionTimerTask(int delayInSeconds, String session,\n               String contextPath, Timer timer) {\n           delay = delayInSeconds * 1000; // convert to milliseconds\n           this.contextPath = contextPath;\n           this.session = session;\n           this.timer = timer;\n           reset();\n       }\n\n       public SessionTimerTask(SessionTimerTask t) {\n           this(t.delay / 1000, t.session, t.contextPath, t.timer);\n       }\n\n       @Override\n       public void run() {\n           if (LOG.isInfoEnabled()) {\n               LOG.info(String.format(\"Session '%s' expired after \"\n                       + \"'%d' milliseconds.\", session, delay));\n           }\n           ZooKeeperService.close(contextPath, session);\n       }\n\n       public void reset() {\n           timer.schedule(this, delay);\n       }\n\n   }\n\n   /**\n    * Specify ZooKeeper host:port for a particular context path. The host:port\n    * string is passed to the ZK client, so this can be formatted with more\n    * than a single host:port pair.\n    */\n   synchronized public static void mapContext(String contextPath, Endpoint e) {\n       contextMap.put(contextPath, e);\n   }\n\n   /**\n    * Reset timer for a session\n    */\n   synchronized public static void resetTimer(String contextPath,\n           String session) {\n       if (session != null) {\n           String uri = concat(contextPath, session);\n\n           SessionTimerTask t = zkSessionTimers.remove(uri);\n           t.cancel();\n\n           zkSessionTimers.put(uri, new SessionTimerTask(t));\n       }\n   }\n\n   /**\n    * Close the ZooKeeper session and remove it from the internal maps\n    */\n   public static void close(String contextPath) {\n       close(contextPath, null);\n   }\n\n   /**\n    * Close the ZooKeeper session and remove it\n    */\n   synchronized public static void close(String contextPath, String session) {\n       String uri = concat(contextPath, session);\n\n       TimerTask t = zkSessionTimers.remove(uri);\n       if (t != null) {\n           t.cancel();\n       }\n\n       ZooKeeper zk = zkMap.remove(uri);\n       if (zk == null) {\n           return;\n       }\n       try {\n           zk.close();\n       } catch (InterruptedException e) {\n           LOG.error(\"Interrupted while closing ZooKeeper connection.\", e);\n       }\n   }\n\n   /**\n    * Close all the ZooKeeper sessions and remove them from the internal maps\n    */\n   synchronized public static void closeAll() {\n       Set<String> sessions = new TreeSet<String>(zkMap.keySet());\n       for (String key : sessions) {\n           close(key);\n       }\n   }\n\n   /**\n    * Is there an active connection for this session?\n    */\n   synchronized public static boolean isConnected(String contextPath,\n           String session) {\n       return zkMap.containsKey(concat(contextPath, session));\n   }\n\n   /**\n    * Return a ZooKeeper client not tied to a specific session.\n    */\n   public static ZooKeeper getClient(String contextPath) throws IOException {\n       return getClient(contextPath, null);\n   }\n\n   /**\n    * Return a ZooKeeper client for a session with a default expire time\n    * \n    * @throws IOException\n    */\n   public static ZooKeeper getClient(String contextPath, String session)\n           throws IOException {\n       return getClient(contextPath, session, 5);\n   }\n\n   /**\n    * Return a ZooKeeper client which may or may not be connected, but it will\n    * not be expired. This method can be called multiple times, the same object\n    * will be returned except in the case where the session expires (at which\n    * point a new session will be returned)\n    */\n   synchronized public static ZooKeeper getClient(String contextPath,\n           String session, int expireTime) throws IOException {\n       final String connectionId = concat(contextPath, session);\n\n       ZooKeeper zk = zkMap.get(connectionId);\n       if (zk == null) {\n\n           if (LOG.isInfoEnabled()) {\n               LOG.info(String.format(\"creating new \"\n                       + \"connection for : '%s'\", connectionId));\n           }\n           Endpoint e = contextMap.get(contextPath);\n           zk = new ZooKeeper(e.getHostPort(), 30000, new MyWatcher(\n                   connectionId));\n           \n           for (Map.Entry<String, String> p : e.getZooKeeperAuthInfo().entrySet()) {\n               zk.addAuthInfo(\"digest\", String.format(\"%s:%s\", p.getKey(),\n                       p.getValue()).getBytes());\n           }\n           \n           zkMap.put(connectionId, zk);\n\n           // a session should automatically expire after an amount of time\n           if (session != null) {\n               zkSessionTimers.put(connectionId, new SessionTimerTask(\n                       expireTime, session, contextPath, timer));\n           }\n       }\n       return zk;\n   }\n\n   private static String concat(String contextPath, String session) {\n       if (session != null) {\n           return String.format(\"%s@%s\", contextPath, session);\n       }\n       return contextPath;\n   }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/cfg/Credentials.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.cfg;\n\nimport java.util.HashMap;\n\npublic class Credentials extends HashMap<String, String> {\n\n   public static Credentials join(Credentials a, Credentials b) {\n       Credentials result = new Credentials();\n       result.putAll(a);\n       result.putAll(b);\n       return result;\n   }\n   \n   public Credentials() {\n       super();\n   }\n   \n   public Credentials(String credentials) {\n       super();\n       \n       if (!credentials.trim().equals(\"\")) {\n           String[] parts = credentials.split(\",\");\n           for(String p : parts) {\n               String[] userPass = p.split(\":\");\n               put(userPass[0], userPass[1]);\n           }\n       }\n   }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/cfg/Endpoint.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.cfg;\n\npublic class Endpoint {\n\n   private String context;\n   private HostPortSet hostPort;\n   private Credentials credentials;\n   private Credentials zookeeperAuth;\n\n   public Endpoint(String context, String hostPortList) {\n       this.context = context;\n       this.hostPort = new HostPortSet(hostPortList);\n   }\n\n   public String getContext() {\n       return context;\n   }\n\n   public String getHostPort() {\n       return hostPort.toString();\n   }\n\n   public Credentials getCredentials() {\n       return credentials;\n   }\n   \n   public void setCredentials(String c) {\n       this.credentials = new Credentials(c);\n   }\n   \n   public void setZooKeeperAuthInfo(String digest) {\n       zookeeperAuth = new Credentials(digest);\n   }\n   \n   public final Credentials getZooKeeperAuthInfo() {\n       return zookeeperAuth;\n   }\n\n   @Override\n   public boolean equals(Object o) {\n       Endpoint e = (Endpoint) o;\n       return context.equals(e.context);\n   }\n\n   @Override\n   public int hashCode() {\n       return context.hashCode();\n   }\n\n   @Override\n   public String toString() {\n       return String.format(\"<Endpoint %s %s>\", context, hostPort.toString());\n   }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/cfg/HostPort.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.cfg;\n\npublic class HostPort {\n\n   private String host;\n   private int port;\n   \n   public HostPort(String hostPort) {\n       String[] parts = hostPort.split(\":\");\n       host = parts[0];\n       port = Integer.parseInt(parts[1]);\n   }\n\n   public String getHost() {\n       return host;\n   }\n\n   public int getPort() {\n       return port;\n   }\n\n   @Override\n   public boolean equals(Object o) {\n       HostPort p = (HostPort) o;\n       return host.equals(p.host) && port == p.port;\n   }\n   \n   @Override\n   public int hashCode() {\n       return String.format(\"%s:%d\", host, port).hashCode();\n   }\n   \n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/cfg/HostPortSet.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.cfg;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class HostPortSet {\n\n   private Set<HostPort> hostPortSet = new HashSet<HostPort>();\n   private String original;\n   \n   public HostPortSet(String hostPortList) {\n       original = hostPortList;\n       \n       int chrootStart = hostPortList.indexOf('/');\n       String hostPortPairs;\n       if (chrootStart != -1) {\n           hostPortPairs = hostPortList.substring(0, chrootStart);\n       } else {\n           hostPortPairs = hostPortList;\n       }\n       \n       String[] parts = hostPortPairs.split(\",\");\n       for(String p : parts) {\n           hostPortSet.add(new HostPort(p));\n       }\n   }\n   \n   @Override\n   public String toString() {\n       return original;\n   }\n   \n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/cfg/RestCfg.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.cfg;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.Set;\n\npublic class RestCfg {\n\n   private Properties cfg = new Properties();\n\n   private Set<Endpoint> endpoints = new HashSet<Endpoint>();\n   private Credentials credentials = new Credentials();\n\n   public RestCfg(String resource) throws IOException {\n       this(RestCfg.class.getClassLoader().getResourceAsStream(resource));\n   }\n\n   public RestCfg(InputStream io) throws IOException {\n     try {\n       cfg.load(io);\n       extractEndpoints();\n       extractCredentials();\n     } finally {\n       io.close();\n     }\n   }\n\n   private void extractCredentials() {\n       if (cfg.containsKey(\"rest.http.auth\")) {\n           credentials = new Credentials(cfg.getProperty(\"rest.http.auth\", \"\"));\n       }\n   }\n\n   private void extractEndpoints() {\n       int count = 1;\n       while (true) {\n           String e = cfg.getProperty(\n                   String.format(\"rest.endpoint.%d\", count), null);\n           if (e == null) {\n               break;\n           }\n\n           String[] parts = e.split(\";\");\n           if (parts.length != 2) {\n               count++;\n               continue;\n           }\n           Endpoint point = new Endpoint(parts[0], parts[1]);\n           \n           String c = cfg.getProperty(String.format(\n                   \"rest.endpoint.%d.http.auth\", count), \"\");\n           point.setCredentials(c);\n           \n           String digest = cfg.getProperty(String.format(\n                   \"rest.endpoint.%d.zk.digest\", count), \"\");\n           point.setZooKeeperAuthInfo(digest);\n\n           endpoints.add(point);\n           count++;\n       }\n   }\n\n   public int getPort() {\n       return Integer.parseInt(cfg.getProperty(\"rest.port\", \"9998\"));\n   }\n\n   public boolean useSSL() {\n       return Boolean.valueOf(cfg.getProperty(\"rest.ssl\", \"false\"));\n   }\n\n   public final Set<Endpoint> getEndpoints() {\n       return endpoints;\n   }\n\n   public final Credentials getCredentials() {\n       return credentials;\n   }\n\n   public String getJKS() {\n       return cfg.getProperty(\"rest.ssl.jks\");\n   }\n\n   public String getJKS(String def) {\n       return cfg.getProperty(\"rest.ssl.jks\", def);\n   }\n\n   public String getJKSPassword() {\n       return cfg.getProperty(\"rest.ssl.jks.pass\");\n   }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/filters/HTTPBasicAuth.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.filters;\n\nimport java.io.IOException;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.zookeeper.server.jersey.cfg.Credentials;\n\nimport com.sun.jersey.core.util.Base64;\n\npublic class HTTPBasicAuth implements Filter {\n\n    private Credentials credentials;\n\n    public HTTPBasicAuth(Credentials c) {\n       credentials = c;\n    }\n\n    @Override\n    public void doFilter(ServletRequest req0, ServletResponse resp0,\n            FilterChain chain) throws IOException, ServletException {\n\n        HttpServletRequest request = (HttpServletRequest) req0;\n        HttpServletResponse response = (HttpServletResponse) resp0;\n\n        String authorization = request.getHeader(\"Authorization\");\n        if (authorization != null) {\n            String c[] = parseAuthorization(authorization);\n            if (c != null && credentials.containsKey(c[0])\n                    && credentials.get(c[0]).equals(c[1])) {\n                chain.doFilter(request, response);\n                return;\n            }\n        }\n\n        response.setHeader(\"WWW-Authenticate\", \"Basic realm=\\\"Restricted\\\"\");\n        response.sendError(401);\n    }\n\n    private String[] parseAuthorization(String authorization) {\n        String parts[] = authorization.split(\" \");\n        if (parts.length == 2 && parts[0].equalsIgnoreCase(\"Basic\")) {\n            String userPass = Base64.base64Decode(parts[1]);\n\n            int p = userPass.indexOf(\":\");\n            if (p != -1) {\n                return new String[] { userPass.substring(0, p),\n                        userPass.substring(p + 1) };\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void init(FilterConfig arg0) throws ServletException {\n    }\n\n    @Override\n    public void destroy() {\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZChildren.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlElementWrapper;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n * Represents the CHILD using JAXB.\n * Special JSON version is required to get proper formatting in both\n * JSON and XML output. See details in ZNodeResource.\n */\n@XmlRootElement(name=\"child\")\npublic class ZChildren {\n    public String path;\n    public String uri;\n\n    public String child_uri_template;\n    @XmlElementWrapper(name=\"children\")\n    @XmlElement(name=\"child\")\n    public List<String> children;\n\n    public ZChildren() {\n        // needed by jersey\n        children = new ArrayList<String>();\n    }\n\n    public ZChildren(String path, String uri, String child_uri_template,\n            List<String> children)\n    {\n        this.path = path;\n        this.uri = uri;\n        this.child_uri_template = child_uri_template;\n        if (children != null) {\n            this.children = children;\n        } else {\n            this.children = new ArrayList<String>();\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        return path.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof ZChildren)) {\n            return false;\n        }\n        ZChildren o = (ZChildren) obj;\n        return path.equals(o.path) && children.equals(o.children);\n    }\n\n    @Override\n    public String toString() {\n        return \"ZChildren(\" + path + \",\" + children + \")\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZChildrenJSON.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n * Represents the CHILD using JAXB.\n * Special JSON version is required to get proper formatting in both\n * JSON and XML output. See details in ZNodeResource.\n */\n@XmlRootElement(name=\"child\")\npublic class ZChildrenJSON {\n    public String path;\n    public String uri;\n\n    public String child_uri_template;\n    public List<String> children;\n\n    public ZChildrenJSON() {\n        // needed by jersey\n        children = new ArrayList<String>();\n    }\n\n    public ZChildrenJSON(String path, String uri, String child_uri_template,\n            List<String> children)\n    {\n        this.path = path;\n        this.uri = uri;\n        this.child_uri_template = child_uri_template;\n        if (children != null) {\n            this.children = children;\n        } else {\n            this.children = new ArrayList<String>();\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        return path.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof ZChildrenJSON)) {\n            return false;\n        }\n        ZChildrenJSON o = (ZChildrenJSON) obj;\n        return path.equals(o.path) && children.equals(o.children);\n    }\n\n    @Override\n    public String toString() {\n        return \"ZChildrenJSON(\" + path + \",\" + children + \")\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZError.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n * Represents an ERROR using JAXB.\n */\n@XmlRootElement(name=\"error\")\npublic class ZError {\n    public String request;\n    public String message;\n\n    public ZError(){\n        // needed by jersey\n    }\n\n    public ZError(String request, String message) {\n        this.request = request;\n        this.message = message;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZPath.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n * Represents a PATH using JAXB.\n */\n@XmlRootElement(name=\"path\")\npublic class ZPath {\n    public String path;\n    public String uri;\n\n    public ZPath(){\n        // needed by jersey\n    }\n\n    public ZPath(String path) {\n        this(path, null);\n    }\n\n    public ZPath(String path, String uri) {\n        this.path = path;\n        this.uri = uri;\n    }\n\n    @Override\n    public int hashCode() {\n        return path.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof ZPath)) {\n            return false;\n        }\n        ZPath o = (ZPath) obj;\n        return path.equals(o.path);\n    }\n\n    @Override\n    public String toString() {\n        return \"ZPath(\" + path + \")\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZSession.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n@XmlRootElement(name=\"session\")\npublic class ZSession {\n    public String id;\n    public String uri;\n    \n    public ZSession() {\n        // needed by jersey\n    }\n    \n    public ZSession(String id, String uri) {\n        this.id = id;\n        this.uri = uri;\n    }\n    \n    @Override\n    public int hashCode() {\n        return id.hashCode();\n    }\n    \n    @Override\n    public boolean equals(Object obj) {\n        if(!(obj instanceof ZSession)) {\n            return false;\n        }\n        ZSession s = (ZSession) obj;\n        return id.equals(s.id);\n    }\n    \n    @Override\n    public String toString() {\n        return \"ZSession(\" + id +\")\";   \n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/jaxb/ZStat.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.jaxb;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n * Represents a STAT using JAXB.\n */\n@XmlRootElement(name=\"stat\")\npublic class ZStat {\n    public String path;\n    public String uri;\n    public byte[] data64;\n    public String dataUtf8;\n\n    public long czxid;\n    public long mzxid;\n    public long ctime;\n    public long mtime;\n    public int version;\n    public int cversion;\n    public int aversion;\n    public long ephemeralOwner;\n    public int dataLength;\n    public int numChildren;\n    public long pzxid;\n\n\n    public ZStat(){\n        // needed by jersey\n    }\n\n    public ZStat(String path, byte[] data64, String dataUtf8)\n    {\n        this.path = path;\n        this.data64 = data64;\n        this.dataUtf8 = dataUtf8;\n    }\n\n    public ZStat(String path, String uri, byte[] data64, String dataUtf8,\n            long czxid, long mzxid, long ctime, long mtime, int version,\n            int cversion, int aversion, long ephemeralOwner, int dataLength,\n            int numChildren, long pzxid)\n    {\n        this.path = path;\n        this.uri = uri;\n        this.data64 = data64;\n        this.dataUtf8 = dataUtf8;\n\n        this.czxid = czxid;\n        this.mzxid = mzxid;\n        this.ctime = ctime;\n        this.mtime = mtime;\n        this.version = version;\n        this.cversion = cversion;\n        this.aversion = aversion;\n        this.ephemeralOwner = ephemeralOwner;\n        this.dataLength = dataLength;\n        this.numChildren = numChildren;\n        this.pzxid = pzxid;\n    }\n\n    @Override\n    public int hashCode() {\n        return path.hashCode();\n    }\n\n    /**\n     * This method considers two ZStats equal if their path, encoding, and\n     * data match. It does not compare the ZooKeeper\n     * org.apache.zookeeper.data.Stat class fields.\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof ZStat)) {\n            return false;\n        }\n        ZStat o = (ZStat) obj;\n        return toString().equals(o.toString());\n    }\n\n    @Override\n    public String toString() {\n        return \"ZStat(\" + path + \",\" + \"b64[\"\n            + (data64 == null ? null : new String(data64)) + \"],\"\n            + dataUtf8 + \")\";\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/JAXBContextResolver.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport javax.ws.rs.ext.ContextResolver;\nimport javax.ws.rs.ext.Provider;\nimport javax.xml.bind.JAXBContext;\n\nimport org.apache.zookeeper.server.jersey.jaxb.ZChildrenJSON;\nimport org.apache.zookeeper.server.jersey.jaxb.ZPath;\nimport org.apache.zookeeper.server.jersey.jaxb.ZStat;\n\nimport com.sun.jersey.api.json.JSONConfiguration;\nimport com.sun.jersey.api.json.JSONJAXBContext;\n\n/**\n * Tell Jersey how to resolve JSON formatting. Specifically detail the\n * fields which are arrays and which are numbers (not strings).\n */\n@Provider\n@SuppressWarnings(\"unchecked\")\npublic final class JAXBContextResolver implements ContextResolver<JAXBContext> {\n    private final JAXBContext context;\n\n    private final Set<Class> typesSet;\n\n    public JAXBContextResolver() throws Exception {\n        Class[] typesArr =\n            new Class[]{ZPath.class, ZStat.class, ZChildrenJSON.class};\n        typesSet = new HashSet<Class>(Arrays.asList(typesArr));\n        context = new JSONJAXBContext(\n                JSONConfiguration.mapped()\n                    .arrays(\"children\")\n                    .nonStrings(\"czxid\")\n                    .nonStrings(\"mzxid\")\n                    .nonStrings(\"ctime\")\n                    .nonStrings(\"mtime\")\n                    .nonStrings(\"version\")\n                    .nonStrings(\"cversion\")\n                    .nonStrings(\"aversion\")\n                    .nonStrings(\"ephemeralOwner\")\n                    .nonStrings(\"dataLength\")\n                    .nonStrings(\"numChildren\")\n                    .nonStrings(\"pzxid\")\n                    .build(),\n                typesArr);\n    }\n\n    public JAXBContext getContext(Class<?> objectType) {\n        return (typesSet.contains(objectType)) ? context : null;\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/KeeperExceptionMapper.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport javax.ws.rs.core.Context;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.UriInfo;\nimport javax.ws.rs.ext.ExceptionMapper;\nimport javax.ws.rs.ext.Provider;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.server.jersey.jaxb.ZError;\n\n\n/**\n * Map KeeperException to HTTP status codes\n */\n@Provider\npublic class KeeperExceptionMapper implements ExceptionMapper<KeeperException> {\n    private UriInfo ui;\n\n    public KeeperExceptionMapper(@Context UriInfo ui) {\n        this.ui = ui;\n    }\n\n    public Response toResponse(KeeperException e) {\n        Response.Status status;\n        String message;\n\n        String path = e.getPath();\n\n        switch(e.code()) {\n        case AUTHFAILED:\n            status = Response.Status.UNAUTHORIZED;\n            message = path + \" not authorized\";\n            break;\n        case BADARGUMENTS:\n            status = Response.Status.BAD_REQUEST;\n            message = path + \" bad arguments\";\n            break;\n        case BADVERSION:\n            status = Response.Status.PRECONDITION_FAILED;\n            message = path + \" bad version\";\n            break;\n        case INVALIDACL:\n            status = Response.Status.BAD_REQUEST;\n            message = path + \" invalid acl\";\n            break;\n        case NODEEXISTS:\n            status = Response.Status.CONFLICT;\n            message = path + \" already exists\";\n            break;\n        case NONODE:\n            status = Response.Status.NOT_FOUND;\n            message = path + \" not found\";\n            break;\n        case NOTEMPTY:\n            status = Response.Status.CONFLICT;\n            message = path + \" not empty\";\n            break;\n        default:\n            status = Response.Status.fromStatusCode(502); // bad gateway\n            message = \"Error processing request for \" + path\n                + \" : \" + e.getMessage();\n        }\n\n        return Response.status(status).entity(\n                new ZError(ui.getRequestUri().toString(), message)).build();\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/RuntimeExceptionMapper.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.Context;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.UriInfo;\nimport javax.ws.rs.ext.ExceptionMapper;\nimport javax.ws.rs.ext.Provider;\n\nimport org.apache.zookeeper.server.jersey.jaxb.ZError;\n\n/**\n * Map RuntimeException to HTTP status codes\n */\n@Provider\npublic class RuntimeExceptionMapper\n    implements ExceptionMapper<RuntimeException>\n{\n    private UriInfo ui;\n\n    public RuntimeExceptionMapper(@Context UriInfo ui) {\n        this.ui = ui;\n    }\n\n    public Response toResponse(RuntimeException e) {\n        // don't try to handle jersey exceptions ourselves\n        if (e instanceof WebApplicationException) { \n            WebApplicationException ie =(WebApplicationException) e; \n            return ie.getResponse(); \n        } \n\n        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(\n                new ZError(ui.getRequestUri().toString(),\n                        \"Error processing request due to \" + e\n                        )).build();\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/SessionsResource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.UUID;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.DELETE;\nimport javax.ws.rs.DefaultValue;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.PUT;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.Context;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.UriInfo;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.jersey.ZooKeeperService;\nimport org.apache.zookeeper.server.jersey.jaxb.ZError;\nimport org.apache.zookeeper.server.jersey.jaxb.ZSession;\n\nimport com.sun.jersey.api.json.JSONWithPadding;\n\n@Path(\"sessions/v1/{session: .*}\")\npublic class SessionsResource {\n\n    private static Logger LOG = LoggerFactory.getLogger(SessionsResource.class);\n\n    private String contextPath;\n\n    public SessionsResource(@Context HttpServletRequest request) {\n        contextPath = request.getContextPath();\n        if (contextPath.equals(\"\")) {\n            contextPath = \"/\";\n        }\n    }\n\n    @PUT\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML })\n    @Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public Response keepAliveSession(@PathParam(\"session\") String session,\n            @Context UriInfo ui, byte[] data) {\n\n        if (!ZooKeeperService.isConnected(contextPath, session)) {\n            throwNotFound(session, ui);\n        }\n\n        ZooKeeperService.resetTimer(contextPath, session);\n        return Response.status(Response.Status.OK).build();\n    }\n\n    @POST\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML })\n    public Response createSession(@QueryParam(\"op\") String op,\n            @DefaultValue(\"5\") @QueryParam(\"expire\") String expire,\n            @Context UriInfo ui) {\n        if (!op.equals(\"create\")) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), \"\")).build());\n        }\n\n        int expireInSeconds;\n        try {\n            expireInSeconds = Integer.parseInt(expire);\n        } catch (NumberFormatException e) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).build());\n        }\n\n        String uuid = UUID.randomUUID().toString();\n        while (ZooKeeperService.isConnected(contextPath, uuid)) {\n            uuid = UUID.randomUUID().toString();\n        }\n\n        // establish the connection to the ZooKeeper cluster\n        try {\n            ZooKeeperService.getClient(contextPath, uuid, expireInSeconds);\n        } catch (IOException e) {\n            LOG.error(\"Failed while trying to create a new session\", e);\n\n            throw new WebApplicationException(Response.status(\n                    Response.Status.INTERNAL_SERVER_ERROR).build());\n        }\n\n        URI uri = ui.getAbsolutePathBuilder().path(uuid).build();\n        return Response.created(uri).entity(\n                new JSONWithPadding(new ZSession(uuid, uri.toString())))\n                .build();\n    }\n\n    @DELETE\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM })\n    public void deleteSession(@PathParam(\"session\") String session,\n            @Context UriInfo ui) {\n        ZooKeeperService.close(contextPath, session);\n    }\n\n    private static void throwNotFound(String session, UriInfo ui)\n            throws WebApplicationException {\n        throw new WebApplicationException(Response.status(\n                Response.Status.NOT_FOUND).entity(\n                new ZError(ui.getRequestUri().toString(), session\n                        + \" not found\")).build());\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/ZErrorWriter.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\n\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.ext.MessageBodyWriter;\nimport javax.ws.rs.ext.Provider;\n\nimport org.apache.zookeeper.server.jersey.jaxb.ZError;\n\n/**\n * Tell Jersey how to format an octet response error message.\n */\n@Produces(MediaType.APPLICATION_OCTET_STREAM)\n@Provider\npublic class ZErrorWriter implements MessageBodyWriter<ZError> {\n\n    public long getSize(ZError t, Class<?> type, Type genericType,\n            Annotation[] annotations, MediaType mediaType)  {\n        return -1;\n    }\n\n    public boolean isWriteable(Class<?> type, Type genericType,\n            Annotation[] annotations, MediaType mediaType) {\n        return ZError.class.isAssignableFrom(type);\n    }\n\n    public void writeTo(ZError t, Class<?> type, Type genericType,\n            Annotation[] annotations, MediaType mediaType,\n            MultivaluedMap<String, Object> httpHeaders,\n            OutputStream os)\n        throws IOException, WebApplicationException\n    {\n        PrintStream p = new PrintStream(os);\n        p.print(\"Request \" + t.request + \" failed due to \" + t.message);\n        p.flush();\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/java/org/apache/zookeeper/server/jersey/resources/ZNodeResource.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey.resources;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.DELETE;\nimport javax.ws.rs.DefaultValue;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HEAD;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.PUT;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.Context;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.UriInfo;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.jersey.ZooKeeperService;\nimport org.apache.zookeeper.server.jersey.jaxb.ZChildren;\nimport org.apache.zookeeper.server.jersey.jaxb.ZChildrenJSON;\nimport org.apache.zookeeper.server.jersey.jaxb.ZError;\nimport org.apache.zookeeper.server.jersey.jaxb.ZPath;\nimport org.apache.zookeeper.server.jersey.jaxb.ZStat;\n\nimport com.sun.jersey.api.json.JSONWithPadding;\n\n/**\n * Version 1 implementation of the ZooKeeper REST specification.\n */\n// TODO test octet fully\n@Path(\"znodes/v1{path: /.*}\")\npublic class ZNodeResource {\n    private final ZooKeeper zk;\n\n    public ZNodeResource(@DefaultValue(\"\") @QueryParam(\"session\") String session,\n            @Context UriInfo ui,\n            @Context HttpServletRequest request\n            )\n            throws IOException {\n\n        String contextPath = request.getContextPath();\n        if (contextPath.equals(\"\")) {\n            contextPath = \"/\";\n        }\n        if (session.equals(\"\")) {\n            session = null;\n        } else if (!ZooKeeperService.isConnected(contextPath, session)) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.UNAUTHORIZED).build());\n        }\n        zk = ZooKeeperService.getClient(contextPath, session);\n    }\n\n    private void ensurePathNotNull(String path) {\n        if (path == null) {\n            throw new IllegalArgumentException(\"Invalid path \\\"\" + path + \"\\\"\");\n        }\n    }\n\n    @HEAD\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML })\n    public Response existsZNode(@PathParam(\"path\") String path,\n            @Context UriInfo ui) throws InterruptedException, KeeperException {\n        Stat stat = zk.exists(path, false);\n        if (stat == null) {\n            throwNotFound(path, ui);\n        }\n        return Response.status(Response.Status.OK).build();\n    }\n\n    @HEAD\n    @Produces( { MediaType.APPLICATION_OCTET_STREAM })\n    public Response existsZNodeAsOctet(@PathParam(\"path\") String path,\n            @Context UriInfo ui) throws InterruptedException, KeeperException {\n        Stat stat = zk.exists(path, false);\n        if (stat == null) {\n            throwNotFound(path, ui);\n        }\n        return Response.status(Response.Status.NO_CONTENT).build();\n    }\n\n    /*\n     * getZNodeList and getZNodeListJSON are bogus - but necessary.\n     * Unfortunately Jersey 1.0.3 is unable to render both xml and json properly\n     * in the case where a object contains a list/array. It's impossible to get\n     * it to render properly for both. As a result we need to split into two\n     * jaxb classes.\n     */\n\n    @GET\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\" })\n    public Response getZNodeListJSON(\n            @PathParam(\"path\") String path,\n            @QueryParam(\"callback\") String callback,\n            @DefaultValue(\"data\") @QueryParam(\"view\") String view,\n            @DefaultValue(\"base64\") @QueryParam(\"dataformat\") String dataformat,\n            @Context UriInfo ui) throws InterruptedException, KeeperException {\n        return getZNodeList(true, path, callback, view, dataformat, ui);\n    }\n\n    @GET\n    @Produces(MediaType.APPLICATION_XML)\n    public Response getZNodeList(\n            @PathParam(\"path\") String path,\n            @QueryParam(\"callback\") String callback,\n            @DefaultValue(\"data\") @QueryParam(\"view\") String view,\n            @DefaultValue(\"base64\") @QueryParam(\"dataformat\") String dataformat,\n            @Context UriInfo ui) throws InterruptedException, KeeperException {\n        return getZNodeList(false, path, callback, view, dataformat, ui);\n    }\n\n    private Response getZNodeList(boolean json, String path, String callback,\n            String view, String dataformat, UriInfo ui)\n            throws InterruptedException, KeeperException {\n        ensurePathNotNull(path);\n\n        if (view.equals(\"children\")) {\n            List<String> children = new ArrayList<String>();\n            for (String child : zk.getChildren(path, false)) {\n                children.add(child);\n            }\n\n            Object child;\n            String childTemplate = ui.getAbsolutePath().toString();\n            if (!childTemplate.endsWith(\"/\")) {\n                childTemplate += \"/\";\n            }\n            childTemplate += \"{child}\";\n            if (json) {\n                child = new ZChildrenJSON(path,\n                        ui.getAbsolutePath().toString(), childTemplate,\n                        children);\n            } else {\n                child = new ZChildren(path, ui.getAbsolutePath().toString(),\n                        childTemplate, children);\n            }\n            return Response.status(Response.Status.OK).entity(\n                    new JSONWithPadding(child, callback)).build();\n        } else {\n            Stat stat = new Stat();\n            byte[] data = zk.getData(path, false, stat);\n\n            byte[] data64;\n            String dataUtf8;\n            if (data == null) {\n                data64 = null;\n                dataUtf8 = null;\n            } else if (!dataformat.equals(\"utf8\")) {\n                data64 = data;\n                dataUtf8 = null;\n            } else {\n                data64 = null;\n                dataUtf8 = new String(data);\n            }\n            ZStat zstat = new ZStat(path, ui.getAbsolutePath().toString(),\n                    data64, dataUtf8, stat.getCzxid(), stat.getMzxid(), stat\n                            .getCtime(), stat.getMtime(), stat.getVersion(),\n                    stat.getCversion(), stat.getAversion(), stat\n                            .getEphemeralOwner(), stat.getDataLength(), stat\n                            .getNumChildren(), stat.getPzxid());\n\n            return Response.status(Response.Status.OK).entity(\n                    new JSONWithPadding(zstat, callback)).build();\n        }\n    }\n\n    @GET\n    @Produces(MediaType.APPLICATION_OCTET_STREAM)\n    public Response getZNodeListAsOctet(@PathParam(\"path\") String path)\n            throws InterruptedException, KeeperException {\n        ensurePathNotNull(path);\n\n        Stat stat = new Stat();\n        byte[] data = zk.getData(path, false, stat);\n\n        if (data == null) {\n            return Response.status(Response.Status.NO_CONTENT).build();\n        } else {\n            return Response.status(Response.Status.OK).entity(data).build();\n        }\n    }\n\n    @PUT\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML })\n    @Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public Response setZNode(\n            @PathParam(\"path\") String path,\n            @QueryParam(\"callback\") String callback,\n            @DefaultValue(\"-1\") @QueryParam(\"version\") String versionParam,\n            @DefaultValue(\"base64\") @QueryParam(\"dataformat\") String dataformat,\n            @DefaultValue(\"false\") @QueryParam(\"null\") String setNull,\n            @Context UriInfo ui, byte[] data) throws InterruptedException,\n            KeeperException {\n        ensurePathNotNull(path);\n\n        int version;\n        try {\n            version = Integer.parseInt(versionParam);\n        } catch (NumberFormatException e) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), path\n                            + \" bad version \" + versionParam)).build());\n        }\n\n        if (setNull.equals(\"true\")) {\n            data = null;\n        }\n\n        Stat stat = zk.setData(path, data, version);\n\n        ZStat zstat = new ZStat(path, ui.getAbsolutePath().toString(), null,\n                null, stat.getCzxid(), stat.getMzxid(), stat.getCtime(), stat\n                        .getMtime(), stat.getVersion(), stat.getCversion(),\n                stat.getAversion(), stat.getEphemeralOwner(), stat\n                        .getDataLength(), stat.getNumChildren(), stat\n                        .getPzxid());\n\n        return Response.status(Response.Status.OK).entity(\n                new JSONWithPadding(zstat, callback)).build();\n    }\n\n    @PUT\n    @Produces(MediaType.APPLICATION_OCTET_STREAM)\n    @Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public void setZNodeAsOctet(@PathParam(\"path\") String path,\n            @DefaultValue(\"-1\") @QueryParam(\"version\") String versionParam,\n            @DefaultValue(\"false\") @QueryParam(\"null\") String setNull,\n            @Context UriInfo ui, byte[] data) throws InterruptedException,\n            KeeperException {\n        ensurePathNotNull(path);\n\n        int version;\n        try {\n            version = Integer.parseInt(versionParam);\n        } catch (NumberFormatException e) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), path\n                            + \" bad version \" + versionParam)).build());\n        }\n\n        if (setNull.equals(\"true\")) {\n            data = null;\n        }\n\n        zk.setData(path, data, version);\n    }\n\n    @POST\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML })\n    @Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public Response createZNode(\n            @PathParam(\"path\") String path,\n            @QueryParam(\"callback\") String callback,\n            @DefaultValue(\"create\") @QueryParam(\"op\") String op,\n            @QueryParam(\"name\") String name,\n            @DefaultValue(\"base64\") @QueryParam(\"dataformat\") String dataformat,\n            @DefaultValue(\"false\") @QueryParam(\"null\") String setNull,\n            @DefaultValue(\"false\") @QueryParam(\"sequence\") String sequence,\n            @DefaultValue(\"false\") @QueryParam(\"ephemeral\") String ephemeral,\n            @Context UriInfo ui, byte[] data) throws InterruptedException,\n            KeeperException {\n        ensurePathNotNull(path);\n\n        if (path.equals(\"/\")) {\n            path += name;\n        } else {\n            path += \"/\" + name;\n        }\n\n        if (!op.equals(\"create\")) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), path\n                            + \" bad operaton \" + op)).build());\n        }\n\n        if (setNull.equals(\"true\")) {\n            data = null;\n        }\n\n        CreateMode createMode;\n        if (sequence.equals(\"true\")) {\n            if (ephemeral.equals(\"false\")) {\n                createMode = CreateMode.PERSISTENT_SEQUENTIAL;\n            } else {\n                createMode = CreateMode.EPHEMERAL_SEQUENTIAL;\n            }\n        } else if (ephemeral.equals(\"false\")) {\n            createMode = CreateMode.PERSISTENT;\n        } else {\n            createMode = CreateMode.EPHEMERAL;\n        }\n\n        String newPath = zk.create(path, data, Ids.OPEN_ACL_UNSAFE, createMode);\n\n        URI uri = ui.getAbsolutePathBuilder().path(newPath).build();\n\n        return Response.created(uri).entity(\n                new JSONWithPadding(new ZPath(newPath, ui.getAbsolutePath()\n                        .toString()))).build();\n    }\n\n    @POST\n    @Produces(MediaType.APPLICATION_OCTET_STREAM)\n    @Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public Response createZNodeAsOctet(@PathParam(\"path\") String path,\n            @DefaultValue(\"create\") @QueryParam(\"op\") String op,\n            @QueryParam(\"name\") String name,\n            @DefaultValue(\"false\") @QueryParam(\"null\") String setNull,\n            @DefaultValue(\"false\") @QueryParam(\"sequence\") String sequence,\n            @Context UriInfo ui, byte[] data) throws InterruptedException,\n            KeeperException {\n        ensurePathNotNull(path);\n\n        if (path.equals(\"/\")) {\n            path += name;\n        } else {\n            path += \"/\" + name;\n        }\n\n        if (!op.equals(\"create\")) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), path\n                            + \" bad operaton \" + op)).build());\n        }\n\n        if (setNull.equals(\"true\")) {\n            data = null;\n        }\n\n        CreateMode createMode;\n        if (sequence.equals(\"true\")) {\n            createMode = CreateMode.PERSISTENT_SEQUENTIAL;\n        } else {\n            createMode = CreateMode.PERSISTENT;\n        }\n\n        String newPath = zk.create(path, data, Ids.OPEN_ACL_UNSAFE, createMode);\n\n        URI uri = ui.getAbsolutePathBuilder().path(newPath).build();\n\n        return Response.created(uri).entity(\n                new ZPath(newPath, ui.getAbsolutePath().toString())).build();\n    }\n\n    @DELETE\n    @Produces( { MediaType.APPLICATION_JSON, \"application/javascript\",\n            MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM })\n    public void deleteZNode(@PathParam(\"path\") String path,\n            @DefaultValue(\"-1\") @QueryParam(\"version\") String versionParam,\n            @Context UriInfo ui) throws InterruptedException, KeeperException {\n        ensurePathNotNull(path);\n\n        int version;\n        try {\n            version = Integer.parseInt(versionParam);\n        } catch (NumberFormatException e) {\n            throw new WebApplicationException(Response.status(\n                    Response.Status.BAD_REQUEST).entity(\n                    new ZError(ui.getRequestUri().toString(), path\n                            + \" bad version \" + versionParam)).build());\n        }\n\n        zk.delete(path, version);\n    }\n\n    private static void throwNotFound(String path, UriInfo ui)\n            throws WebApplicationException {\n        throw new WebApplicationException(Response.status(\n                Response.Status.NOT_FOUND).entity(\n                new ZError(ui.getRequestUri().toString(), path + \" not found\"))\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/python/README.txt",
    "content": "Some basic python scripts which use the REST interface:\n\nzkrest.py -- basic REST ZooKeeper client\ndemo_master_election.py -- shows how to implement master election\ndemo_queue.py -- basic queue\nzk_dump_tree.py -- dumps the nodes & data of a znode hierarchy\n\nGenerally these scripts require:\n  * simplejson\n"
  },
  {
    "path": "src/contrib/rest/src/python/demo_master_election.py",
    "content": "#! /usr/bin/env python\n\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport sys\nimport threading\nimport time\n\nfrom zkrest import ZooKeeper\n\nclass Agent(threading.Thread):\n    \"\"\" A basic agent that wants to become a master and exit \"\"\"\n\n    root = '/election'\n\n    def __init__(self, id):\n        super(Agent, self).__init__()\n        self.zk = ZooKeeper()\n        self.id = id\n\n    def run(self):\n        print 'Starting #%s' % self.id\n        with self.zk.session(expire=5):\n\n            # signal agent presence\n            r = self.zk.create(\"%s/agent-\" % self.root, \n                sequence=True, ephemeral=True)\n            self.me = r['path']\n\n            while True:\n                children = sorted([el['path'] \\\n                    for el in self.zk.get_children(self.root)])\n                master, previous = children[0], None\n                try:\n                    index = children.index(self.me)\n                    if index != 0:\n                        previous = children[index-1]\n                except ValueError:\n                    break\n\n                if previous is None:\n                    self.do_master_work()\n                    # and don't forget to send heartbeat messages\n                    break\n                else:\n                    # do slave work in another thread\n                    pass\n               \n                # wait for the previous agent or current master to exit / finish\n                while self.zk.exists(previous) or self.zk.exists(master):\n                    time.sleep(0.5)\n                    self.zk.heartbeat()\n\n                # TODO signal the slave thread to exit and wait for it\n                # and rerun the election loop\n\n    def do_master_work(self):\n        print \"#%s: I'm the master: %s\" % (self.id, self.me) \n            \ndef main():\n    zk = ZooKeeper()\n\n    # create the root node used for master election\n    if not zk.exists('/election'):\n        zk.create('/election')\n\n    print 'Starting 10 agents ...'\n    agents = [Agent(id) for id in range(0,15)]\n\n    map(Agent.start, agents)\n    map(Agent.join, agents)\n\n    zk.delete('/election')    \n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "src/contrib/rest/src/python/demo_queue.py",
    "content": "#! /usr/bin/env python\n\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\n# This is a simple message queue built on top of ZooKeeper. In order\n# to be used in production it needs better error handling but it's \n# still useful as a proof-of-concept. \n\n# Why use ZooKeeper as a queue? Highly available by design and has\n# great performance.\n\nimport sys\nimport threading\nimport time\n\nfrom zkrest import ZooKeeper\n\nclass Queue(object):\n    def __init__(self, root, zk):\n        self.root = root\n\n        self.zk = zk\n\n    def put(self, data):\n        self.zk.create(\"%s/el-\" % self.root, str(data), sequence=True, ephemeral=True)\n\n        # creating ephemeral nodes for easy cleanup\n        # in a real world scenario you should create\n        # normal sequential znodes\n\n    def fetch(self):\n        \"\"\" Pull an element from the queue\n\n        This function is not blocking if the queue is empty, it will\n        just return None.\n        \"\"\"\n        children = sorted(self.zk.get_children(self.root), \\\n            lambda a, b: cmp(a['path'], b['path']))\n\n        if not children:\n            return None\n\n        try:\n            first = children[0]\n            self.zk.delete(first['path'], version=first['version'])\n            if 'data64' not in first:\n                return ''\n            else:\n                return first['data64'].decode('base64')\n\n        except (ZooKeeper.WrongVersion, ZooKeeper.NotFound):\n            # someone changed the znode between the get and delete\n            # this should not happen\n            # in practice you should retry the fetch\n            raise\n        \n\ndef main():\n    zk = ZooKeeper()\n    zk.start_session(expire=60)\n\n    if not zk.exists('/queue'):\n        zk.create('/queue')\n    q = Queue('/queue', zk)\n\n    print 'Pushing to queue 1 ... 5'\n    map(q.put, [1,2,3,4,5])\n\n    print 'Extracting ...'\n    while True:\n        el = q.fetch()\n        if el is None:\n            break\n        print el    \n\n    zk.close_session()\n    zk.delete('/queue')\n\n    print 'Done.'\n   \n\nif __name__ == '__main__':\n    sys.exit(main())\n\n"
  },
  {
    "path": "src/contrib/rest/src/python/test.py",
    "content": "#! /usr/bin/env python\n\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport time\nimport unittest\n\nfrom zkrest import ZooKeeper\n\nclass ZooKeeperREST_TestCase(unittest.TestCase):\n    \n    BASE_URI = 'http://localhost:9998'\n\n    def setUp(self):\n        self.zk = ZooKeeper(self.BASE_URI)\n\n    def tearDown(self):\n        try:\n            self.zk.delete('/test')\n        except ZooKeeper.NotFound:\n            pass\n\n    def test_get_root_node(self):\n        assert self.zk.get('/') is not None\n\n    def test_get_node_not_found(self):\n        self.assertRaises(ZooKeeper.NotFound, \\\n            self.zk.get, '/dummy-node')\n\n    def test_exists_node(self):\n        assert self.zk.exists('/zookeeper') is True\n\n    def test_get_children(self):\n        assert any([child['path'] == '/zookeeper/quota' \\\n            for child in self.zk.get_children('/zookeeper')])\n            \n    def test_create_znode(self):\n        try:\n            self.zk.create('/test')\n        except ZooKeeper.ZNodeExists:\n            pass # it's ok if already exists\n        assert self.zk.exists('/test') is True\n\n    def test_create_hierarchy(self):\n        try:\n            self.zk.delete(['/a/b', '/a'])\n        except ZooKeeper.NotFound:\n            pass\n\n        self.zk.create('/a')\n        self.zk.create('/a/b')\n\n        self.zk.delete(['/a/b', '/a'])\n\n    def test_create_with_data(self):\n        self.zk.create('/test', 'some-data')\n\n        zn = self.zk.get('/test')\n        self.assertEqual(zn.get('data64', None), \\\n            'some-data'.encode('base64').strip())\n\n    def test_delete_znode(self):\n        self.zk.create('/test')\n\n        self.zk.delete('/test')\n        assert not self.zk.exists('/test')\n\n    def test_delete_older_version(self):\n        self.zk.create('/test')\n\n        zn = self.zk.get('/test')\n        # do one more modification in order to increase the version number\n        self.zk.set('/test', 'dummy-data')\n\n        self.assertRaises(ZooKeeper.WrongVersion, \\\n            self.zk.delete, '/test', version=zn['version'])\n\n    def test_delete_raise_not_found(self):\n        self.zk.create('/test')\n\n        zn = self.zk.get('/test')\n        self.zk.delete('/test')\n \n        self.assertRaises(ZooKeeper.NotFound, \\\n            self.zk.delete, '/test', version=zn['version'])\n\n    def test_set(self):\n        self.zk.create('/test')\n\n        self.zk.set('/test', 'dummy')\n\n        self.assertEqual(self.zk.get('/test')['data64'], \\\n            'dummy'.encode('base64').strip())\n\n    def test_set_with_older_version(self):\n        if not self.zk.exists('/test'):\n            self.zk.create('/test', 'random-data')\n\n        zn = self.zk.get('/test')\n        self.zk.set('/test', 'new-data')\n        self.assertRaises(ZooKeeper.WrongVersion, self.zk.set, \\\n            '/test', 'older-version', version=zn['version'])\n\n    def test_set_null(self):\n        if not self.zk.exists('/test'):\n            self.zk.create('/test', 'random-data')\n        self.zk.set('/test', 'data')\n        assert 'data64' in self.zk.get('/test')\n\n        self.zk.set('/test', null=True)\n        assert 'data64' not in self.zk.get('/test')\n\n    def test_create_ephemeral_node(self):\n        with self.zk.session():\n            if self.zk.exists('/ephemeral-test'):\n                self.zk.delete('/ephemeral-test')\n\n            self.zk.create('/ephemeral-test', ephemeral=True)\n            zn = self.zk.get('/ephemeral-test')\n\n            assert zn['ephemeralOwner'] != 0\n\n    def test_create_session(self):\n        with self.zk.session() as sid:\n            self.assertEqual(len(sid), 36) # UUID\n\n    def test_session_invalidation(self):\n        self.zk.start_session(expire=1)\n        self.zk.create('/ephemeral-test', ephemeral=True)\n\n        # keep the session alive by sending heartbeat requests\n        for _ in range(1,2):\n            self.zk.heartbeat()\n            time.sleep(0.9)\n\n        time.sleep(2) # wait for the session to expire\n        self.assertRaises(ZooKeeper.InvalidSession, \\\n            self.zk.create, '/ephemeral-test', ephemeral=True)\n\n    def test_presence_signaling(self):\n        with self.zk.session(expire=1):\n            self.zk.create('/i-am-online', ephemeral=True)\n            assert self.zk.exists('/i-am-online')\n        assert not self.zk.exists('/i-am-online')\n\n\nif __name__ == '__main__':\n    unittest.main()\n\n"
  },
  {
    "path": "src/contrib/rest/src/python/zk_dump_tree.py",
    "content": "#!/usr/bin/python\n\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport getopt\nimport sys\nimport simplejson\nimport urllib2\nfrom base64 import b64decode\n\nprintdata = False\nfullpath = False\n\ndef dump_node(url, depth):\n    \"\"\"Dump the node, then dump children recursively\n    \n    Arguments:\n    - `url`:\n    - `depth`:\n    \"\"\"\n    req = urllib2.urlopen(url)\n    resp = simplejson.load(req)\n    if 'Error' in resp:\n      raise resp['Error']\n\n    if fullpath:\n      name = resp['path']\n    else:\n      name = '/' + resp['path'].split('/')[-1]\n\n    data64 = resp.get('data64')\n    dataUtf8 = resp.get('dataUtf8')\n    if data64 and printdata:\n      data = b64decode(data64)\n      print '%(indent)s%(name)s = b64(%(data64)s) str(%(data)s)' % \\\n          {'indent':' '*2*depth, 'name':name, 'data64':data64, 'data':data}\n    elif dataUtf8 and printdata:\n      print '%(indent)s%(name)s = %(data)s' % \\\n          {'indent':' '*2*depth, 'name':name, 'data':dataUtf8}\n    else:\n      print '%(indent)s%(name)s' % {'indent':' '*2*depth, 'name':name}\n\n    req = urllib2.urlopen(resp['uri'] + '?view=children')\n    resp = simplejson.load(req)\n\n    for child in resp.get('children', []):\n        dump_node(resp['child_uri_template']\n                  .replace(\"{child}\", urllib2.quote(child)),\n                  depth + 1)\n\ndef zk_dump_tree(url, root):\n    \"\"\"Dump the tree starting at the roota\n    \n    Arguments:\n    - `root`:\n    \"\"\"\n    dump_node(url + '/znodes/v1' + root, 0)\n\ndef usage():\n    \"\"\"Usage\n    \"\"\"\n    print 'Usage: zk_dump_tree.py [-h|--help -u|--url=url -d|--data -f|--fullpath -r|--root=root]'\n    print '  where url is the url of the rest server, data is whether to'\n    print '  to include node data on output, root is the znode root'\n    print '  fullpath prints the full node path (useful for copy/paste)'\n\nif __name__ == '__main__':\n    try:\n        opts, args = getopt.getopt(sys.argv[1:],\n            \"hu:dfr:\", [\"help\", \"url=\", \"data\", \"fullpath\", \"root=\"])\n    except getopt.GetoptError, err:\n        # print help information and exit:\n        print str(err) # will print something like \"option -a not recognized\"\n        usage()\n        sys.exit(2)\n    url ='http://localhost:9998'\n    root = '/'\n    for o, a in opts:\n        if o in (\"-d\", \"--data\"):\n            printdata = True\n        elif o in (\"-h\", \"--help\"):\n            usage()\n            sys.exit()\n        elif o in (\"-u\", \"--url\"):\n            url = a\n        elif o in (\"-r\", \"--root\"):\n            root = a\n        elif o in (\"-f\", \"--fullpath\"):\n            fullpath = True\n        else:\n            assert False, \"unhandled option\"\n    \n    print 'Accessing REST server at ' + url\n    zk_dump_tree(url, root)\n"
  },
  {
    "path": "src/contrib/rest/src/python/zkrest.py",
    "content": "\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport urllib2\nimport urllib\nimport simplejson\n\nfrom contextlib import contextmanager\n\nclass RequestWithMethod(urllib2.Request):\n    \"\"\" Request class that know how to set the method name \"\"\"\n    def __init__(self, *args, **kwargs):\n        urllib2.Request.__init__(self, *args, **kwargs)\n        self._method = None\n\n    def get_method(self):\n        return self._method or \\\n            urllib2.Request.get_method(self)\n\n    def set_method(self, method):\n        self._method = method\n\nclass ZooKeeper(object):\n\n    class Error(Exception): pass\n\n    class NotFound(Error): pass\n\n    class ZNodeExists(Error): pass\n\n    class InvalidSession(Error): pass\n\n    class WrongVersion(Error): pass\n\n    def __init__(self, uri = 'http://localhost:9998'):\n        self._base = uri\n        self._session = None\n\n    def start_session(self, expire=5, id=None):\n        \"\"\" Create a session and return the ID \"\"\"\n        if id is None:\n            url = \"%s/sessions/v1/?op=create&expire=%d\" % (self._base, expire)\n            self._session = self._do_post(url)['id']\n        else:\n            self._session = id\n        return self._session\n\n    def close_session(self):\n        \"\"\" Close the session on the server \"\"\"\n        if self._session is not None:\n            url = '%s/sessions/v1/%s' % (self._base, self._session)\n            self._do_delete(url)\n            self._session = None\n\n    def heartbeat(self):\n        \"\"\" Send a heartbeat request. This is needed in order to keep a session alive \"\"\"\n        if self._session is not None:\n            url = '%s/sessions/v1/%s' % (self._base, self._session)\n            self._do_put(url, '')\n\n    @contextmanager\n    def session(self, *args, **kwargs):\n        \"\"\" Session handling using a context manager \"\"\"\n        yield self.start_session(*args, **kwargs)\n        self.close_session()\n\n    def get(self, path):\n        \"\"\" Get a node \"\"\"\n        url = \"%s/znodes/v1%s\" % (self._base, path)\n        return self._do_get(url)\n\n    def get_children(self, path):\n        \"\"\" Get all the children for a given path. This function creates a generator \"\"\"\n        url = \"%s/znodes/v1%s?view=children\" % (self._base, path)\n        resp = self._do_get(url)\n        for child in resp.get('children', []):\n            try:\n                yield self._do_get(resp['child_uri_template']\\\n                    .replace('{child}', urllib2.quote(child)))\n            except ZooKeeper.NotFound:\n                continue\n\n    def create(self, path, data=None, sequence=False, ephemeral=False):\n        \"\"\" Create a new node. By default this call creates a persistent znode.\n\n        You can also create an ephemeral or a sequential znode.\n        \"\"\"\n        ri = path.rindex('/')\n        head, name = path[:ri+1], path[ri+1:]\n        if head != '/': head = head[:-1]\n\n        flags = {\n            'null': 'true' if data is None else 'false',\n            'ephemeral': 'true' if ephemeral else 'false',\n            'sequence': 'true' if sequence else 'false'\n        }\n        if ephemeral:\n            if self._session:\n                flags['session'] = self._session\n            else:\n                raise ZooKeeper.Error, 'You need a session '\\\n                    'to create an ephemeral node'\n        flags = urllib.urlencode(flags)\n\n        url = \"%s/znodes/v1%s?op=create&name=%s&%s\" % \\\n            (self._base, head, name, flags)\n\n        return self._do_post(url, data)\n\n    def set(self, path, data=None, version=-1, null=False):\n        \"\"\" Set the value of node \"\"\"\n        url = \"%s/znodes/v1%s?%s\" % (self._base, path, \\\n            urllib.urlencode({\n                'version': version,\n                'null': 'true' if null else 'false'\n        }))\n        return self._do_put(url, data)\n\n    def delete(self, path, version=-1):\n        \"\"\" Delete a znode \"\"\"\n        if type(path) is list:\n            map(lambda el: self.delete(el, version), path)\n            return\n\n        url = '%s/znodes/v1%s?%s' % (self._base, path, \\\n            urllib.urlencode({\n                'version':version\n        }))\n        try:\n            return self._do_delete(url)\n        except urllib2.HTTPError, e:\n            if e.code == 412:\n                raise ZooKeeper.WrongVersion(path)\n            elif e.code == 404:\n                raise ZooKeeper.NotFound(path)\n            raise\n\n    def exists(self, path):\n        \"\"\" Do a znode exists \"\"\"\n        try:\n            self.get(path)\n            return True\n        except ZooKeeper.NotFound:\n            return False\n\n    def _do_get(self, uri):\n        \"\"\" Send a GET request and convert errors to exceptions \"\"\"\n        try:\n            req = urllib2.urlopen(uri)\n            resp = simplejson.load(req)\n\n            if 'Error' in resp:\n               raise ZooKeeper.Error(resp['Error'])\n\n            return resp\n        except urllib2.HTTPError, e:\n            if e.code == 404:\n                raise ZooKeeper.NotFound(uri)\n            raise\n\n    def _do_post(self, uri, data=None):\n        \"\"\" Send a POST request and convert errors to exceptions \"\"\"\n        try:\n            req = urllib2.Request(uri, {})\n            req.add_header('Content-Type', 'application/octet-stream')\n            if data is not None:\n                req.add_data(data)\n\n            resp = simplejson.load(urllib2.urlopen(req))\n            if 'Error' in resp:\n                raise ZooKeeper.Error(resp['Error'])\n            return resp\n\n        except urllib2.HTTPError, e:\n            if e.code == 201:\n                return True\n            elif e.code == 409:\n                raise ZooKeeper.ZNodeExists(uri)\n            elif e.code == 401:\n                raise ZooKeeper.InvalidSession(uri)\n            raise\n\n    def _do_delete(self, uri):\n        \"\"\" Send a DELETE request \"\"\"\n        req = RequestWithMethod(uri)\n        req.set_method('DELETE')\n        req.add_header('Content-Type', 'application/octet-stream')\n        return urllib2.urlopen(req).read()\n\n    def _do_put(self, uri, data):\n        \"\"\" Send a PUT request \"\"\"\n        try:\n            req = RequestWithMethod(uri)\n            req.set_method('PUT')\n            req.add_header('Content-Type', 'application/octet-stream')\n            if data is not None:\n                req.add_data(data)\n\n            return urllib2.urlopen(req).read()\n        except urllib2.HTTPError, e:\n            if e.code == 412: # precondition failed\n                raise ZooKeeper.WrongVersion(uri)\n            raise\n\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/Base.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.io.ByteArrayInputStream;\n\nimport junit.framework.TestCase;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.jersey.SetTest.MyWatcher;\nimport org.apache.zookeeper.server.jersey.cfg.RestCfg;\nimport org.junit.After;\nimport org.junit.Before;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jersey.api.client.WebResource;\n\n/**\n * Test stand-alone server.\n * \n */\npublic class Base extends TestCase {\n   protected static final Logger LOG = LoggerFactory.getLogger(Base.class);\n\n   protected static final String CONTEXT_PATH = \"/zk\";\n   protected static final int GRIZZLY_PORT = 10104;\n   protected static final String BASEURI = String.format(\n           \"http://localhost:%d%s\", GRIZZLY_PORT, CONTEXT_PATH);\n   protected static final String ZKHOSTPORT = \"localhost:22182\";\n   protected Client client;\n   protected WebResource znodesr, sessionsr;\n\n   protected ZooKeeper zk;\n\n   private RestMain rest;\n\n   @Before\n   public void setUp() throws Exception {\n       super.setUp();\n\n       RestCfg cfg = new RestCfg(new ByteArrayInputStream(String.format(\n               \"rest.port=%s\\n\" + \n               \"rest.endpoint.1=%s;%s\\n\",\n               GRIZZLY_PORT, CONTEXT_PATH, ZKHOSTPORT).getBytes()));\n\n       rest = new RestMain(cfg);\n       rest.start();\n\n       zk = new ZooKeeper(ZKHOSTPORT, 30000, new MyWatcher());\n\n       client = Client.create();\n       znodesr = client.resource(BASEURI).path(\"znodes/v1\");\n       sessionsr = client.resource(BASEURI).path(\"sessions/v1/\");\n   }\n\n   @After\n   public void tearDown() throws Exception {\n       super.tearDown();\n\n       client.destroy();\n       zk.close();\n       rest.stop();\n   }\n\n   protected static String createBaseZNode() throws Exception {\n       ZooKeeper zk = new ZooKeeper(ZKHOSTPORT, 30000, new MyWatcher());\n\n       String baseZnode = zk.create(\"/test-\", null, Ids.OPEN_ACL_UNSAFE,\n               CreateMode.PERSISTENT_SEQUENTIAL);\n       zk.close();\n\n       return baseZnode;\n   }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/CreateTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.jersey.jaxb.ZPath;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.WebResource.Builder;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class CreateTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(CreateTest.class);\n\n    private String accept;\n    private String path;\n    private String name;\n    private String encoding;\n    private ClientResponse.Status expectedStatus;\n    private ZPath expectedPath;\n    private byte[] data;\n    private boolean sequence;\n\n    public static class MyWatcher implements Watcher {\n        public void process(WatchedEvent event) {\n            // FIXME ignore for now\n        }\n    }\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n\n        return Arrays.asList(new Object[][] {\n          {MediaType.APPLICATION_JSON,\n              baseZnode, \"foo bar\", \"utf8\",\n              ClientResponse.Status.CREATED,\n              new ZPath(baseZnode + \"/foo bar\"), null,\n              false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t1\", \"utf8\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-t1\"),\n              null, false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t1\", \"utf8\",\n              ClientResponse.Status.CONFLICT, null, null, false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t2\", \"utf8\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-t2\"),\n              \"\".getBytes(), false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t2\", \"utf8\",\n              ClientResponse.Status.CONFLICT, null, null, false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t3\", \"utf8\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-t3\"),\n              \"foo\".getBytes(), false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t3\", \"utf8\",\n              ClientResponse.Status.CONFLICT, null, null, false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-t4\", \"base64\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-t4\"),\n              \"foo\".getBytes(), false },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-\", \"utf8\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-\"), null,\n              true },\n          {MediaType.APPLICATION_JSON, baseZnode, \"c-\", \"utf8\",\n              ClientResponse.Status.CREATED, new ZPath(baseZnode + \"/c-\"), null,\n              true }\n          });\n    }\n\n    public CreateTest(String accept, String path, String name, String encoding,\n            ClientResponse.Status status, ZPath expectedPath, byte[] data,\n            boolean sequence)\n    {\n        this.accept = accept;\n        this.path = path;\n        this.name = name;\n        this.encoding = encoding;\n        this.expectedStatus = status;\n        this.expectedPath = expectedPath;\n        this.data = data;\n        this.sequence = sequence;\n    }\n\n    @Test\n    public void testCreate() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n\n        WebResource wr = znodesr.path(path).queryParam(\"dataformat\", encoding)\n            .queryParam(\"name\", name);\n        if (data == null) {\n            wr = wr.queryParam(\"null\", \"true\");\n        }\n        if (sequence) {\n            wr = wr.queryParam(\"sequence\", \"true\");\n        }\n\n        Builder builder = wr.accept(accept);\n\n        ClientResponse cr;\n        if (data == null) {\n            cr = builder.post(ClientResponse.class);\n        } else {\n            cr = builder.post(ClientResponse.class, data);\n        }\n        assertEquals(expectedStatus, cr.getClientResponseStatus());\n\n        if (expectedPath == null) {\n            return;\n        }\n\n        ZPath zpath = cr.getEntity(ZPath.class);\n        if (sequence) {\n            assertTrue(zpath.path.startsWith(expectedPath.path));\n            assertTrue(zpath.uri.startsWith(znodesr.path(path).toString()));\n        } else {\n            assertEquals(expectedPath, zpath);\n            assertEquals(znodesr.path(path).toString(), zpath.uri);\n        }\n\n        // use out-of-band method to verify\n        byte[] data = zk.getData(zpath.path, false, new Stat());\n        if (data == null && this.data == null) {\n            return;\n        } else if (data == null || this.data == null) {\n            assertEquals(data, this.data);\n        } else {\n            assertTrue(new String(data) + \" == \" + new String(this.data),\n                    Arrays.equals(data, this.data));\n        }\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/DeleteTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class DeleteTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(DeleteTest.class);\n\n    private String zpath;\n    private ClientResponse.Status expectedStatus;\n\n    public static class MyWatcher implements Watcher {\n        public void process(WatchedEvent event) {\n            // FIXME ignore for now\n        }\n    }\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n\n        return Arrays.asList(new Object[][] {\n          {baseZnode, baseZnode, ClientResponse.Status.NO_CONTENT },\n          {baseZnode, baseZnode, ClientResponse.Status.NO_CONTENT }\n        });\n    }\n\n    public DeleteTest(String path, String zpath, ClientResponse.Status status) {\n        this.zpath = zpath;\n        this.expectedStatus = status;\n    }\n\n    public void verify(String type) throws Exception {\n        if (expectedStatus != ClientResponse.Status.NOT_FOUND) {\n            zpath = zk.create(zpath, null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT_SEQUENTIAL);\n        }\n\n        ClientResponse cr = znodesr.path(zpath).accept(type).type(type)\n            .delete(ClientResponse.class);\n        assertEquals(expectedStatus, cr.getClientResponseStatus());\n\n        // use out-of-band method to verify\n        Stat stat = zk.exists(zpath, false);\n        assertNull(stat);\n    }\n\n    @Test\n    public void testDelete() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n        verify(MediaType.APPLICATION_OCTET_STREAM);\n        verify(MediaType.APPLICATION_JSON);\n        verify(MediaType.APPLICATION_XML);\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/ExistsTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class ExistsTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(ExistsTest.class);\n\n    private String path;\n    private ClientResponse.Status expectedStatus;\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n\n     return Arrays.asList(new Object[][] {\n      {baseZnode, ClientResponse.Status.OK },\n      {baseZnode + \"dkdk38383\", ClientResponse.Status.NOT_FOUND }\n     });\n    }\n\n    public ExistsTest(String path, ClientResponse.Status status) {\n        this.path = path;\n        this.expectedStatus = status;\n    }\n\n    private void verify(String type) {\n        ClientResponse cr = znodesr.path(path).accept(type).type(type).head();\n        if (type.equals(MediaType.APPLICATION_OCTET_STREAM)\n                && expectedStatus == ClientResponse.Status.OK) {\n            assertEquals(ClientResponse.Status.NO_CONTENT,\n                    cr.getClientResponseStatus());\n        } else {\n            assertEquals(expectedStatus, cr.getClientResponseStatus());\n        }\n    }\n\n    @Test\n    public void testExists() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n        verify(MediaType.APPLICATION_OCTET_STREAM);\n        verify(MediaType.APPLICATION_JSON);\n        verify(MediaType.APPLICATION_XML);\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/GetChildrenTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.jersey.jaxb.ZChildren;\nimport org.apache.zookeeper.server.jersey.jaxb.ZChildrenJSON;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class GetChildrenTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(GetChildrenTest.class);\n\n    private String accept;\n    private String path;\n    private ClientResponse.Status expectedStatus;\n    private String expectedPath;\n    private List<String> expectedChildren;\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n        String baseZnode2 = Base.createBaseZNode();\n        String baseZnode3 = Base.createBaseZNode();\n        String baseZnode4 = Base.createBaseZNode();\n        String baseZnode5 = Base.createBaseZNode();\n        String baseZnode6 = Base.createBaseZNode();\n\n        return Arrays.asList(new Object[][] {\n          {MediaType.APPLICATION_JSON, baseZnode + \"abddkdkd\",\n              ClientResponse.Status.NOT_FOUND, null, null },\n          {MediaType.APPLICATION_XML, baseZnode + \"abddkdkd\",\n              ClientResponse.Status.NOT_FOUND, null, null },\n          {MediaType.APPLICATION_JSON, baseZnode, ClientResponse.Status.OK,\n              baseZnode, Arrays.asList(new String[] {}) },\n          {MediaType.APPLICATION_XML, baseZnode, ClientResponse.Status.OK,\n              baseZnode, Arrays.asList(new String[] {}) },\n          {MediaType.APPLICATION_JSON, baseZnode, ClientResponse.Status.OK,\n              baseZnode, Arrays.asList(new String[] {\"c1\"}) },\n          {MediaType.APPLICATION_XML, baseZnode4, ClientResponse.Status.OK,\n              baseZnode4, Arrays.asList(new String[] {\"c1\"}) },\n          {MediaType.APPLICATION_JSON, baseZnode2, ClientResponse.Status.OK,\n              baseZnode2, Arrays.asList(new String[] {\"c1\", \"c2\"}) },\n          {MediaType.APPLICATION_XML, baseZnode5, ClientResponse.Status.OK,\n              baseZnode5, Arrays.asList(new String[] {\"c1\", \"c2\"}) },\n          {MediaType.APPLICATION_JSON, baseZnode3, ClientResponse.Status.OK,\n              baseZnode3, Arrays.asList(new String[] {\"c1\", \"c2\", \"c3\", \"c4\"}) },\n          {MediaType.APPLICATION_XML, baseZnode6, ClientResponse.Status.OK,\n              baseZnode6, Arrays.asList(new String[] {\"c1\", \"c2\", \"c3\", \"c4\"}) }\n\n          });\n    }\n\n    public GetChildrenTest(String accept, String path, ClientResponse.Status status,\n            String expectedPath, List<String> expectedChildren)\n    {\n        this.accept = accept;\n        this.path = path;\n        this.expectedStatus = status;\n        this.expectedPath = expectedPath;\n        this.expectedChildren = expectedChildren;\n    }\n\n    @Test\n    public void testGetChildren() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n\n        if (expectedChildren != null) {\n            for(String child : expectedChildren) {\n                zk.create(expectedPath + \"/\" + child, null,\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n        }\n\n        ClientResponse cr = znodesr.path(path).queryParam(\"view\", \"children\")\n            .accept(accept).get(ClientResponse.class);\n        assertEquals(expectedStatus, cr.getClientResponseStatus());\n\n        if (expectedChildren == null) {\n            return;\n        }\n\n        if (accept.equals(MediaType.APPLICATION_JSON)) {\n            ZChildrenJSON zchildren = cr.getEntity(ZChildrenJSON.class);\n            Collections.sort(expectedChildren);\n            Collections.sort(zchildren.children);\n            assertEquals(expectedChildren, zchildren.children);\n            assertEquals(znodesr.path(path).toString(), zchildren.uri);\n            assertEquals(znodesr.path(path).toString() + \"/{child}\",\n                    zchildren.child_uri_template);\n        } else if (accept.equals(MediaType.APPLICATION_XML)) {\n            ZChildren zchildren = cr.getEntity(ZChildren.class);\n            Collections.sort(expectedChildren);\n            Collections.sort(zchildren.children);\n            assertEquals(expectedChildren, zchildren.children);\n            assertEquals(znodesr.path(path).toString(), zchildren.uri);\n            assertEquals(znodesr.path(path).toString() + \"/{child}\",\n                    zchildren.child_uri_template);\n        } else {\n            fail(\"unknown accept type\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/GetTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.jersey.jaxb.ZStat;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class GetTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(GetTest.class);\n\n    private String accept;\n    private String path;\n    private String encoding;\n    private ClientResponse.Status expectedStatus;\n    private ZStat expectedStat;\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n\n     return Arrays.asList(new Object[][] {\n      {MediaType.APPLICATION_JSON, baseZnode, \"utf8\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, null, null) },\n      {MediaType.APPLICATION_JSON, baseZnode, \"utf8\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, null, \"\") },\n      {MediaType.APPLICATION_JSON, baseZnode, \"utf8\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, null, \"foo\") },\n      {MediaType.APPLICATION_JSON, baseZnode, \"base64\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, null, null) },\n      {MediaType.APPLICATION_JSON, baseZnode, \"base64\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, \"\".getBytes(), null) },\n      {MediaType.APPLICATION_JSON, baseZnode, \"base64\",\n          ClientResponse.Status.OK, new ZStat(baseZnode, \"\".getBytes(), null) },\n      {MediaType.APPLICATION_JSON, baseZnode, \"base64\",\n              ClientResponse.Status.OK, new ZStat(baseZnode, \"foo\".getBytes(), null) },\n      {MediaType.APPLICATION_JSON, baseZnode + \"abaddkdk\", \"utf8\",\n                      ClientResponse.Status.NOT_FOUND, null },\n      {MediaType.APPLICATION_JSON, baseZnode + \"abaddkdk\", \"base64\",\n              ClientResponse.Status.NOT_FOUND, null },\n\n      {MediaType.APPLICATION_XML, baseZnode, \"utf8\",\n                  ClientResponse.Status.OK, new ZStat(baseZnode, null, \"foo\") },\n      {MediaType.APPLICATION_XML, baseZnode, \"base64\",\n                      ClientResponse.Status.OK,\n                      new ZStat(baseZnode, \"foo\".getBytes(), null) },\n      {MediaType.APPLICATION_XML, baseZnode + \"abaddkdk\", \"utf8\",\n                      ClientResponse.Status.NOT_FOUND, null },\n      {MediaType.APPLICATION_XML, baseZnode + \"abaddkdk\", \"base64\",\n              ClientResponse.Status.NOT_FOUND, null }\n\n     });\n    }\n\n    public GetTest(String accept, String path, String encoding,\n            ClientResponse.Status status, ZStat stat)\n    {\n        this.accept = accept;\n        this.path = path;\n        this.encoding = encoding;\n        this.expectedStatus = status;\n        this.expectedStat = stat;\n    }\n\n    @Test\n    public void testGet() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n\n        if (expectedStat != null) {\n            if (expectedStat.data64 != null || expectedStat.dataUtf8 == null) {\n                zk.setData(expectedStat.path, expectedStat.data64, -1);\n            } else {\n                zk.setData(expectedStat.path,\n                        expectedStat.dataUtf8.getBytes(), -1);\n            }\n        }\n\n        ClientResponse cr = znodesr.path(path).queryParam(\"dataformat\", encoding)\n            .accept(accept).get(ClientResponse.class);\n        assertEquals(expectedStatus, cr.getClientResponseStatus());\n\n        if (expectedStat == null) {\n            return;\n        }\n\n        ZStat zstat = cr.getEntity(ZStat.class);\n        assertEquals(expectedStat, zstat);\n        assertEquals(znodesr.path(path).toString(), zstat.uri);\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/RestTestSuite.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\nimport org.junit.runners.Suite.SuiteClasses;\n\n@RunWith(Suite.class)\n@SuiteClasses({WadlTest.class, GetTest.class, GetChildrenTest.class,\n    CreateTest.class, SetTest.class, ExistsTest.class, DeleteTest.class })\npublic class RestTestSuite {\n\n    @BeforeClass\n    public static void setUp() {\n        // suite setup\n    }\n\n    @AfterClass\n    public static void tearDown() {\n        // suite setup\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/RootTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.jersey.jaxb.ZPath;\nimport org.junit.Test;\n\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.WebResource.Builder;\n\n\n/**\n * Test stand-alone server.\n *\n */\npublic class RootTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(RootTest.class);\n\n    @Test\n    public void testCreate() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n        \n        String path = \"/\";\n        String name = \"roottest-create\";\n        byte[] data = \"foo\".getBytes();\n\n        WebResource wr = znodesr.path(path).queryParam(\"dataformat\", \"utf8\")\n            .queryParam(\"name\", name);\n        Builder builder = wr.accept(MediaType.APPLICATION_JSON);\n\n        ClientResponse cr;\n        cr = builder.post(ClientResponse.class, data);\n        assertEquals(ClientResponse.Status.CREATED, cr.getClientResponseStatus());\n\n        ZPath zpath = cr.getEntity(ZPath.class);\n        assertEquals(new ZPath(path + name), zpath);\n        assertEquals(znodesr.path(path).toString(), zpath.uri);\n\n        // use out-of-band method to verify\n        byte[] rdata = zk.getData(zpath.path, false, new Stat());\n        assertTrue(new String(rdata) + \" == \" + new String(data),\n                Arrays.equals(rdata, data));\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/SessionTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.io.IOException;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.jersey.jaxb.ZSession;\nimport org.codehaus.jettison.json.JSONException;\nimport org.junit.Test;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.WebResource.Builder;\n\npublic class SessionTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(SessionTest.class);\n\n    private ZSession createSession() {\n        return createSession(\"30\");\n    }\n\n    private ZSession createSession(String expire) {\n        WebResource wr = sessionsr.queryParam(\"op\", \"create\")\n            .queryParam(\"expire\", expire);\n        Builder b = wr.accept(MediaType.APPLICATION_JSON);\n\n        ClientResponse cr = b.post(ClientResponse.class, null);\n        assertEquals(ClientResponse.Status.CREATED, cr\n                .getClientResponseStatus());\n\n        return cr.getEntity(ZSession.class);\n    }\n\n    @Test\n    public void testCreateNewSession() throws JSONException {\n        ZSession session = createSession();\n        assertEquals(session.id.length(), 36);\n\n        // use out-of-band method to verify\n        assertTrue(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n    }\n\n    @Test\n    public void testSessionExpires() throws InterruptedException {\n        ZSession session = createSession(\"1\");\n\n        // use out-of-band method to verify\n        assertTrue(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n\n        // wait for the session to be closed\n        Thread.sleep(1500);\n        assertFalse(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n    }\n\n    @Test\n    public void testDeleteSession() {\n        ZSession session = createSession(\"30\");\n\n        WebResource wr = sessionsr.path(session.id);\n        Builder b = wr.accept(MediaType.APPLICATION_JSON);\n\n        assertTrue(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n        ClientResponse cr = b.delete(ClientResponse.class, null);\n        assertEquals(ClientResponse.Status.NO_CONTENT, \n                cr.getClientResponseStatus());\n\n        assertFalse(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n    }\n    \n    @Test\n    public void testSendHeartbeat() throws InterruptedException {\n        ZSession session = createSession(\"2\");\n        \n        Thread.sleep(1000);\n        WebResource wr = sessionsr.path(session.id);\n        Builder b = wr.accept(MediaType.APPLICATION_JSON);\n        \n        ClientResponse cr = b.put(ClientResponse.class, null);\n        assertEquals(ClientResponse.Status.OK, cr.getClientResponseStatus());\n        \n        Thread.sleep(1500);\n        assertTrue(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n        \n        Thread.sleep(1000);\n        assertFalse(ZooKeeperService.isConnected(CONTEXT_PATH, session.id));\n    }\n    \n    @Test\n    public void testCreateEphemeralZNode() \n    throws KeeperException, InterruptedException, IOException {\n        ZSession session = createSession(\"30\");\n        \n        WebResource wr = znodesr.path(\"/\")\n            .queryParam(\"op\", \"create\")\n            .queryParam(\"name\", \"ephemeral-test\")\n            .queryParam(\"ephemeral\", \"true\")\n            .queryParam(\"session\", session.id)\n            .queryParam(\"null\", \"true\");\n        \n        Builder b = wr.accept(MediaType.APPLICATION_JSON);\n        ClientResponse cr = b.post(ClientResponse.class);\n        assertEquals(ClientResponse.Status.CREATED, cr.getClientResponseStatus());\n        \n        Stat stat = new Stat();\n        zk.getData(\"/ephemeral-test\", false, stat);\n        \n        ZooKeeper sessionZK = ZooKeeperService.getClient(CONTEXT_PATH, session.id);\n        assertEquals(stat.getEphemeralOwner(), sessionZK.getSessionId());\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/SetTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.ws.rs.core.MediaType;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.jersey.jaxb.ZStat;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.WebResource.Builder;\n\n\n/**\n * Test stand-alone server.\n *\n */\n@RunWith(Parameterized.class)\npublic class SetTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(SetTest.class);\n\n    private String accept;\n    private String path;\n    private String encoding;\n    private ClientResponse.Status expectedStatus;\n    private ZStat expectedStat;\n    private byte[] data;\n\n    public static class MyWatcher implements Watcher {\n        public void process(WatchedEvent event) {\n            // FIXME ignore for now\n        }\n    }\n\n    @Parameters\n    public static Collection<Object[]> data() throws Exception {\n        String baseZnode = Base.createBaseZNode();\n\n        return Arrays.asList(new Object[][] {\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t1\", \"utf8\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t1\", null, null), null },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t2\", \"utf8\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t2\", null, null), new byte[0] },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t3\", \"utf8\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t3\", null, null), \"foobar\".getBytes() },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t4\", \"base64\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t4\", null, null), null },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t5\", \"base64\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t5\", null, null), new byte[0] },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/s-t6\", \"base64\",\n              ClientResponse.Status.OK,\n              new ZStat(baseZnode + \"/s-t6\", null, null),\n              \"foobar\".getBytes() },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/dkdkdkd\", \"utf8\",\n              ClientResponse.Status.NOT_FOUND, null, null },\n          {MediaType.APPLICATION_JSON, baseZnode + \"/dkdkdkd\", \"base64\",\n              ClientResponse.Status.NOT_FOUND, null, null },\n          });\n    }\n\n    public SetTest(String accept, String path, String encoding,\n            ClientResponse.Status status, ZStat expectedStat, byte[] data)\n    {\n        this.accept = accept;\n        this.path = path;\n        this.encoding = encoding;\n        this.expectedStatus = status;\n        this.expectedStat = expectedStat;\n        this.data = data;\n    }\n\n    @Test\n    public void testSet() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n\n        if (expectedStat != null) {\n            zk.create(expectedStat.path, \"initial\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n\n        WebResource wr = znodesr.path(path).queryParam(\"dataformat\", encoding);\n        if (data == null) {\n            wr = wr.queryParam(\"null\", \"true\");\n        }\n\n        Builder builder = wr.accept(accept)\n            .type(MediaType.APPLICATION_OCTET_STREAM);\n\n        ClientResponse cr;\n        if (data == null) {\n            cr = builder.put(ClientResponse.class);\n        } else {\n            // this shouldn't be necessary (wrapping data with string)\n            // but without it there are problems on the server - ie it\n            // hangs for 30 seconds and doesn't get the data.\n            // TODO investigate\n            cr = builder.put(ClientResponse.class, new String(data));\n        }\n        assertEquals(expectedStatus, cr.getClientResponseStatus());\n\n        if (expectedStat == null) {\n            return;\n        }\n\n        ZStat zstat = cr.getEntity(ZStat.class);\n        assertEquals(expectedStat, zstat);\n\n        // use out-of-band method to verify\n        byte[] data = zk.getData(zstat.path, false, new Stat());\n        if (data == null && this.data == null) {\n            return;\n        } else if (data == null || this.data == null) {\n            fail((data == null ? null : new String(data)) + \" == \"\n                    + (this.data == null ? null : new String(this.data)));\n        } else {\n            assertTrue(new String(data) + \" == \" + new String(this.data),\n                    Arrays.equals(data, this.data));\n        }\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/org/apache/zookeeper/server/jersey/WadlTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.jersey;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.junit.Test;\n\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.core.header.MediaTypes;\n\n\n/**\n * Test stand-alone server.\n *\n */\npublic class WadlTest extends Base {\n    protected static final Logger LOG = LoggerFactory.getLogger(WadlTest.class);\n\n    @Test\n    public void testApplicationWadl() {\n        WebResource r = client.resource(BASEURI);\n        String serviceWadl = r.path(\"application.wadl\").\n                accept(MediaTypes.WADL).get(String.class);\n        assertTrue(\"Something wrong. Returned wadl length not > 0.\",\n                serviceWadl.length() > 0);\n    }\n}\n"
  },
  {
    "path": "src/contrib/rest/src/test/zkServer.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nif [ \"x$1\" == \"x\" ]\nthen\n    echo \"USAGE: $0 startClean|start|stop hostPorts\"\n    exit 2\nfi\n\nif [ \"x$1\" == \"xstartClean\" ]\nthen\n    if [ \"x${base_dir}\" == \"x\" ]\n    then\n    rm -rf /tmp/zkdata\n    else\n    rm -rf ${base_dir}/build/tmp\n    fi\nfi\n\n# Make sure nothing is left over from before\nif [ -r \"/tmp/zk.pid\" ]\nthen\npid=`cat /tmp/zk.pid`\nkill -9 $pid\nrm -f /tmp/zk.pid\nfi\n\nif [ -r \"${base_dir}/build/tmp/zk.pid\" ]\nthen\npid=`cat ${base_dir}/build/tmp/zk.pid`\nkill -9 $pid\nrm -f ${base_dir}/build/tmp/zk.pid\nfi\n\nif [ \"x${base_dir}\" == \"x\" ]\t\nthen\nzk_base=\"../../../\"\nelse\nzk_base=\"${base_dir}\"\nfi\n\nCLASSPATH=\"$CLASSPATH:${zk_base}/build/classes\"\nCLASSPATH=\"$CLASSPATH:${zk_base}/conf\"\n\nfor i in \"${zk_base}\"/build/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nfor i in \"${zk_base}\"/src/java/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\ncase $1 in\nstart|startClean)\n    if [ \"x${base_dir}\" == \"x\" ]\n        then\n        mkdir -p /tmp/zkdata\n        java -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22182 /tmp/zkdata &> /tmp/zk.log &\n        echo $! > /tmp/zk.pid\n        else\n        mkdir -p ${base_dir}/build/tmp/zkdata\n        java -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22182 ${base_dir}/build/tmp/zkdata &> ${base_dir}/build/tmp/zk.log &\n        echo $! > ${base_dir}/build/tmp/zk.pid\n    fi\n        sleep 5\n    ;;\nstop)\n    # Already killed above\n    ;;\n*)\n    echo \"Unknown command \" + $1\n    exit 2\nesac\n\n"
  },
  {
    "path": "src/contrib/zkfuse/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in\n\nSUBDIRS = src\n\n"
  },
  {
    "path": "src/contrib/zkfuse/README.txt",
    "content": "Original authors of zkfuse are Swee Lim & Bartlomiej M Niechwiej of Yahoo.\n'\nZooKeeper FUSE (File System in Userspace)\n=========================================\n\nPre-requisites\n--------------\n1. Linux system with 2.6.X kernel.\n2. Fuse (Filesystem in Userspace) must be installed on the build node. \n3. Development build libraries:\n  a. fuse\n  b. log4cxx\n  c. pthread\n  d. boost\n\nBuild instructions\n------------------\n1. cd into this directory\n2. autoreconf -if\n3. ./configure\n4. make\n5. zkfuse binary is under the src directory\n\nTesting Zkfuse\n--------------\n1. Depending on permission on /dev/fuse, you may need to sudo -u root.\n   * If /dev/fuse has permissions 0600, then you have to run Zkfuse as root.\n   * If /dev/fuse has permissions 0666, then you can run Zkfuse as any user.\n2. Create or find a mount point that you have \"rwx\" permission. \n   * e.g. mkdir -p /tmp/zkfuse\n3. Run Zkfuse as follows:\n   zkfuse -z <hostspec> -m /tmp/zkfuse -d\n   -z specifies ZooKeeper address(es) <host>:<port>\n   -m specifies the mount point\n   -d specifies the debug mode.\n   For additional command line options, try \"zkfuse -h\".\n\nFAQ\n---\nQ. How to fix \"warning: macro `AM_PATH_CPPUNIT' not found in library\"?\nA. * install cppunit (src or pkg) on build machine\n\nQ. Why can't Zkfuse cannot write to current directory?\nA. * If Zkfuse is running as root on a NFS mounted file system, it will not\n     have root permissions because root user is mapped to another user by\n     NFS admin.\n   * If you run Zkfuse as root, it is a good idea to run Zkfuse from a\n     directory that you have write access to. This will allow core files\n     to be saved.\n\nQ. Why Zkfuse cannot mount?\nA. * Check that the mount point exists and you have \"rwx\" permissions.\n   * Check that previous mounts have been umounted. If Zkfuse does not \n     exit cleanly, its mount point may have to be umounted manually. \n     If you cannot umount manually, make sure that there no files is open \n     within the mount point.\n\nQ. Why does Zkfuse complain about logging at startup?\nA. * Zkfuse uses log4cxx for logging. It is looking for log4cxx.properties\n     file to obtain its logging configuration.\n   * There is an example log4cxx.properties file in the Zkfuse source \n     directory.\n\n"
  },
  {
    "path": "src/contrib/zkfuse/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zkfuse\" default=\"compile\">\n  <import file=\"../build-contrib.xml\"/>\n\n  <target name=\"init\" depends=\"check-contrib\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <antcall target=\"init-contrib\"/>\n  </target>\n\n  <target name=\"compile\" depends=\"init\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${build.dir}\"/>\n    <copy todir=\"${build.dir}\">\n      <fileset dir=\"${basedir}\">\n        <exclude name=\"**/VERSION\"/>\n      </fileset>\n    </copy>\n    <exec executable=\"echo\" output=\"${build.dir}/VERSION\">\n      <arg line=\"${version}\" />\n    </exec>\n  </target>\n\n\t<target name=\"jar\" depends=\"compile\" >\n\t\t<echo message=\"No jar target defined for this package\"/>\n\t</target>\n\n \t<target name=\"test\">\n        <echo message=\"No test target defined for this package\" />\n    </target>\n\n\n  <target name=\"package\" depends=\"compile\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}\">\n      <fileset dir=\"${build.dir}\"/>\n    </copy>\n  </target>\n\n</project>\n"
  },
  {
    "path": "src/contrib/zkfuse/configure.ac",
    "content": "#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ(2.59)\n\nAC_INIT([zkfuse], [2.2.0])\nAM_INIT_AUTOMAKE(foreign)\n\nAC_CONFIG_SRCDIR([src/zkadapter.h])\nAM_CONFIG_HEADER([config.h])\n\nPACKAGE=zkfuse\nVERSION=1.0\n\nAC_SUBST(PACKAGE)\nAC_SUBST(VERSION)\n\nBUILD_PATH=\"`pwd`\"\n\n# Checks for programs.\nAC_LANG_CPLUSPLUS\nAC_PROG_CXX\n\n# Checks for libraries.\nAC_CHECK_LIB([fuse], [main])\nAC_CHECK_LIB([log4cxx], [main], [], [AC_MSG_ERROR(\"We need log4cxx to build zkfuse\")])\nAC_CHECK_LIB([thread], [thr_create])\nAC_CHECK_LIB([pthread], [pthread_create])\nAC_CHECK_LIB([rt], [clock_gettime])\nAC_CHECK_LIB([socket], [socket])\nAC_CHECK_LIB([nsl], [gethostbyname])\nAC_CHECK_LIB([ulockmgr], [ulockmgr_op])\n\nZOOKEEPER_PATH=${BUILD_PATH}/../../c\nZOOKEEPER_BUILD_PATH=${BUILD_PATH}/../../../build/c\nAC_CHECK_LIB(zookeeper_mt, main, [ZOOKEEPER_LD=\"-L${ZOOKEEPER_BUILD_PATH}/.libs -lzookeeper_mt\"],,[\"-L${ZOOKEEPER_BUILD_PATH}/.libs\"])\n\nAC_SUBST(ZOOKEEPER_PATH)\nAC_SUBST(ZOOKEEPER_LD)\n\n# Checks for header files.\nAC_HEADER_DIRENT\nAC_HEADER_STDC\nAC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h])\nAC_CHECK_HEADERS([boost/shared_ptr.hpp boost/utility.hpp boost/weak_ptr.hpp],, AC_MSG_ERROR([boost library headers not found. Please install boost library.]))\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_HEADER_STDBOOL\nAC_C_CONST\nAC_TYPE_UID_T\nAC_C_INLINE\nAC_TYPE_INT32_T\nAC_TYPE_INT64_T\nAC_TYPE_MODE_T\nAC_TYPE_OFF_T\nAC_TYPE_SIZE_T\nAC_CHECK_MEMBERS([struct stat.st_blksize])\nAC_STRUCT_ST_BLOCKS\nAC_HEADER_TIME\nAC_TYPE_UINT32_T\nAC_TYPE_UINT64_T\nAC_TYPE_UINT8_T\nAC_C_VOLATILE\n\n# Checks for library functions.\nAC_FUNC_UTIME_NULL\nAC_CHECK_FUNCS([gettimeofday memset mkdir rmdir strdup strerror strstr strtol strtoul strtoull utime])\n\nAC_CONFIG_FILES([Makefile])\nAC_CONFIG_FILES([src/Makefile])\nAC_OUTPUT\nAC_C_VOLATILE\n"
  },
  {
    "path": "src/contrib/zkfuse/src/Makefile.am",
    "content": "AM_CXXFLAGS = -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated \\\n  -I$(top_srcdir)/include -I/usr/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT\n\nnoinst_PROGRAMS = zkfuse\n\nzkfuse_SOURCES = zkfuse.cc zkadapter.cc thread.cc log.cc\nzkfuse_LDADD = ${ZOOKEEPER_LD}"
  },
  {
    "path": "src/contrib/zkfuse/src/blockingqueue.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n \n#ifndef __BLOCKINGQUEUE_H__\n#define __BLOCKINGQUEUE_H__\n \n#include <deque>\n\n#include \"mutex.h\"\n \nusing namespace std;\nUSING_ZKFUSE_NAMESPACE\n\nnamespace zk {\n \n/**\n * \\brief An unbounded blocking queue of elements of type E.\n * \n * <p>\n * This class is thread safe.\n */\ntemplate <class E>\nclass BlockingQueue {\n    public:\n        \n        /**\n         * \\brief Adds the specified element to this queue, waiting if necessary \n         * \\brief for space to become available.\n         * \n         * @param e the element to be added\n         */\n        void put(E e);\n        \n        /**\n         * \\brief Retrieves and removes the head of this queue, waiting if \n         * \\brief no elements are present in this queue.\n         * \n         * @param timeout how long to wait until an element becomes availabe, \n         *                in milliseconds; if <code>0</code> then wait forever\n         * @param timedOut if not NULL then set to true whether this function timed out\n         * @return the element from the queue\n         */\n        E take(int32_t timeout = 0, bool *timedOut = NULL);\n        \n        /**\n         * Returns the current size of this blocking queue.\n         * \n         * @return the number of elements in this queue\n         */\n        int size() const;\n        \n        /**\n         * \\brief Returns whether this queue is empty or not.\n         * \n         * @return true if this queue has no elements; false otherwise\n         */\n        bool empty() const;\n        \n    private:\n        \n        /**\n         * The queue of elements. Deque is used to provide O(1) time \n         * for head elements removal.\n         */\n        deque<E> m_queue;\n        \n        /**\n         * The mutex used for queue synchronization.\n         */\n        mutable zkfuse::Mutex m_mutex;\n        \n        /**\n         * The conditionial variable associated with the mutex above.\n         */\n        mutable Cond m_cond;\n        \n};\n\ntemplate<class E>\nint BlockingQueue<E>::size() const {\n    int size;\n    m_mutex.Acquire();\n    size = m_queue.size();\n    m_mutex.Release();\n    return size;\n}\n\ntemplate<class E>\nbool BlockingQueue<E>::empty() const {\n    bool isEmpty;\n    m_mutex.Acquire();\n    isEmpty = m_queue.empty();\n    m_mutex.Release();\n    return isEmpty;\n}\n\ntemplate<class E> \nvoid BlockingQueue<E>::put(E e) {\n    m_mutex.Acquire();\n    m_queue.push_back( e );\n    m_cond.Signal();\n    m_mutex.Release();\n}\n\ntemplate<class E> \n    E BlockingQueue<E>::take(int32_t timeout, bool *timedOut) {\n    m_mutex.Acquire();\n    bool hasResult = true;\n    while (m_queue.empty()) {\n        if (timeout <= 0) {\n            m_cond.Wait( m_mutex );\n        } else {\n            if (!m_cond.Wait( m_mutex, timeout )) {\n                hasResult = false;\n                break;\n            }\n        }\n    }\n    if (hasResult) {\n        E e = m_queue.front();\n        m_queue.pop_front();            \n        m_mutex.Release();\n        if (timedOut) {\n            *timedOut = false;\n        }\n        return e;\n    } else {\n        m_mutex.Release();\n        if (timedOut) {\n            *timedOut = true;\n        }\n        return E();\n    }\n}\n\n}\n\n#endif  /* __BLOCKINGQUEUE_H__ */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/doxygen.cfg",
    "content": "# Doxyfile 1.4.3\n\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project\n#\n# All text after a hash (#) is considered a comment and will be ignored\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \")\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \n# by quotes) that should identify the project.\n\nPROJECT_NAME           = ZkFuse\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. \n# This could be handy for archiving the generated documentation or \n# if some version control system is used.\n\nPROJECT_NUMBER         = \n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \n# base path where the generated documentation will be put. \n# If a relative path is entered, it will be relative to the location \n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doc\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \n# 4096 sub-directories (in 2 levels) under the output directory of each output \n# format and will distribute the generated files over these directories. \n# Enabling this option can be useful when feeding doxygen a huge amount of \n# source files, where putting all generated files in the same directory would \n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS         = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all \n# documentation generated by doxygen is written. Doxygen will use this \n# information to generate all constant output in the proper language. \n# The default language is English, other supported languages are: \n# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \n# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \n# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \n# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \n# Swedish, and Ukrainian.\n\nOUTPUT_LANGUAGE        = English\n\n# This tag can be used to specify the encoding used in the generated output. \n# The encoding is not always determined by the language that is chosen, \n# but also whether or not the output is meant for Windows or non-Windows users. \n# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \n# forces the Windows encoding (this is the default for the Windows binary), \n# whereas setting the tag to NO uses a Unix-style encoding (the default for \n# all platforms other than Windows).\n\nUSE_WINDOWS_ENCODING   = NO\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n# include brief member descriptions after the members that are listed in \n# the file and class documentation (similar to JavaDoc). \n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n# the brief description of a member or function before the detailed description. \n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator \n# that is used to form the text in various listings. Each string \n# in this list, if found as the leading text of the brief description, will be \n# stripped from the text and the result after processing the whole list, is \n# used as the annotated text. Otherwise, the brief description is used as-is. \n# If left blank, the following values are used (\"$name\" is automatically \n# replaced with the name of the entity): \"The $name class\" \"The $name widget\" \n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\" \n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF       = \n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n# Doxygen will generate a detailed section even if there is only a brief \n# description.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all \n# inherited members of a class in the documentation of that class as if those \n# members were ordinary class members. Constructors, destructors and assignment \n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n# path before files name in the file list and in the header files. If set \n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES        = YES\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n# can be used to strip a user-defined part of the path. Stripping is \n# only done if one of the specified strings matches the left-hand part of \n# the path. The tag can be used to show relative paths in the file list. \n# If left blank the directory from which doxygen is run is used as the \n# path to strip.\n\nSTRIP_FROM_PATH        = \n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \n# the path mentioned in the documentation of a class, which tells \n# the reader which header file to include in order to use a class. \n# If left blank only the name of the header file containing the class \n# definition is used. Otherwise one should specify the include paths that \n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH    = \n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n# (but less readable) file names. This can be useful is your file systems \n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n# will interpret the first line (until the first dot) of a JavaDoc-style \n# comment as the brief description. If set to NO, the JavaDoc \n# comments will behave just like the Qt-style comments (thus requiring an \n# explicit @brief command for a brief description.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n# treat a multi-line C++ special comment block (i.e. a block of //! or /// \n# comments) as a brief description. This used to be the default behaviour. \n# The new default is to treat a multi-line C++ comment block as a detailed \n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the DETAILS_AT_TOP tag is set to YES then Doxygen \n# will output the detailed description near the top, like JavaDoc.\n# If set to NO, the detailed description appears after the member \n# documentation.\n\nDETAILS_AT_TOP         = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n# member inherits the documentation from any documented member that it \n# re-implements.\n\nINHERIT_DOCS           = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n# tag is set to YES, then doxygen will reuse the documentation of the first \n# member in the group (if any) for the other members of the group. By default \n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce \n# a new page for each member. If set to NO, the documentation of a member will \n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. \n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE               = 8\n\n# This tag can be used to specify a number of aliases that acts \n# as commands in the documentation. An alias has the form \"name=value\". \n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n# put the command \\sideeffect (or @sideeffect) in the documentation, which \n# will result in a user-defined paragraph with heading \"Side Effects:\". \n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES                = \n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C \n# sources only. Doxygen will then generate output that is more tailored for C. \n# For instance, some of the names that are used will be different. The list \n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \n# only. Doxygen will then generate output that is more tailored for Java. \n# For instance, namespaces will be presented as packages, qualified scopes \n# will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n# the same type (for instance a group of public functions) to be put as a \n# subgroup of that type (e.g. under the Public Functions section). Set it to \n# NO to prevent subgrouping. Alternatively, this can be done per class using \n# the \\nosubgrouping command.\n\nSUBGROUPING            = YES\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \n# documentation are documented, even if no documentation was available. \n# Private class members and static file members will be hidden unless \n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \n# will be included in the documentation.\n\nEXTRACT_PRIVATE        = YES\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file \n# will be included in the documentation.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \n# defined locally in source files will be included in the documentation. \n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. When set to YES local \n# methods, which are defined in the implementation section but not in \n# the interface are included in the documentation. \n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \n# undocumented members of documented classes, files or namespaces. \n# If set to NO (the default) these members will be included in the \n# various overviews, but no documentation section is generated. \n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \n# undocumented classes that are normally visible in the class hierarchy. \n# If set to NO (the default) these classes will be included in the various \n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \n# friend (class|struct|union) declarations. \n# If set to NO (the default) these declarations will be included in the \n# documentation.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \n# documentation blocks found inside the body of a function. \n# If set to NO (the default) these blocks will be appended to the \n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation \n# that is typed after a \\internal command is included. If the tag is set \n# to NO (the default) then the documentation will be excluded. \n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \n# file names in lower-case letters. If set to YES upper-case letters are also \n# allowed. This is useful if you have classes or files whose names only differ \n# in case and if your file system supports case sensitive file names. Windows \n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \n# will show members with their full class and namespace scopes in the \n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \n# will put a list of the files that are included by a file in the documentation \n# of that file.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \n# is inserted in the documentation for inline members.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \n# will sort the (detailed) documentation of file and class members \n# alphabetically by member name. If set to NO the members will appear in \n# declaration order.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \n# brief documentation of file, namespace and class members alphabetically \n# by member name. If set to NO (the default) the members will appear in \n# declaration order.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \n# sorted by fully-qualified names, including namespaces. If set to \n# NO (the default), the class list will be sorted only by class name, \n# not including the namespace part. \n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the \n# alphabetical list.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or \n# disable (NO) the todo list. This list is created by putting \\todo \n# commands in the documentation.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or \n# disable (NO) the test list. This list is created by putting \\test \n# commands in the documentation.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or \n# disable (NO) the bug list. This list is created by putting \\bug \n# commands in the documentation.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \n# disable (NO) the deprecated list. This list is created by putting \n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional \n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS       = \n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \n# the initial value of a variable or define consists of for it to appear in \n# the documentation. If the initializer consists of more lines than specified \n# here it will be hidden. Use a value of 0 to hide initializers completely. \n# The appearance of the initializer of individual variables and defines in the \n# documentation can be controlled using \\showinitializer or \\hideinitializer \n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \n# at the bottom of the documentation of classes and structs. If set to YES the \n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES        = YES\n\n# If the sources in your project are distributed over multiple directories \n# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \n# in the documentation.\n\nSHOW_DIRECTORIES       = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that \n# doxygen should invoke to get the current version for each file (typically from the \n# version control system). Doxygen will invoke the program by executing (via \n# popen()) the command <command> <input-file>, where <command> is the value of \n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file \n# provided by doxygen. Whatever the progam writes to standard output \n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER    = \n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated \n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are \n# generated by doxygen. Possible values are YES and NO. If left blank \n# NO is used.\n\nWARNINGS               = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \n# potential errors in the documentation, such as not documenting some \n# parameters in a documented function, or documenting parameters that \n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be abled to get warnings for \n# functions that are documented, but have no documentation for their parameters \n# or return value. If set to NO (the default) doxygen will only warn about \n# wrong or incomplete parameter documentation, but not about the absence of \n# documentation.\n\nWARN_NO_PARAMDOC       = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that \n# doxygen can produce. The string should contain the $file, $line, and $text \n# tags, which will be replaced by the file and line number from which the \n# warning originated and the warning text. Optionally the format may contain \n# $version, which will be replaced by the version of the file (if it could \n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning \n# and error messages should be written. If left blank the output is written \n# to stderr.\n\nWARN_LOGFILE           = \n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain \n# documented source files. You may enter file names like \"myfile.cpp\" or \n# directories like \"/usr/src/myproject\". Separate the files or directories \n# with spaces.\n\nINPUT                  = \n\n# If the value of the INPUT tag contains directories, you can use the \n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank the following patterns are tested: \n# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx \n# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm\n\nFILE_PATTERNS          = \n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories \n# should be searched for input files as well. Possible values are YES and NO. \n# If left blank NO is used.\n\nRECURSIVE              = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should \n# excluded from the INPUT source files. This way you can easily exclude a \n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n\nEXCLUDE                = \n\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or \n# directories that are symbolic links (a Unix filesystem feature) are excluded \n# from the input.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the \n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \n# certain files from those directories.\n\nEXCLUDE_PATTERNS       = \n\n# The EXAMPLE_PATH tag can be used to specify one or more files or \n# directories that contain example code fragments that are included (see \n# the \\include command).\n\nEXAMPLE_PATH           = \n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the \n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank all files are included.\n\nEXAMPLE_PATTERNS       = \n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \n# searched for input files to be used with the \\include or \\dontinclude \n# commands irrespective of the value of the RECURSIVE tag. \n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or \n# directories that contain image that are included in the documentation (see \n# the \\image command).\n\nIMAGE_PATH             = \n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should \n# invoke to filter for each input file. Doxygen will invoke the filter program \n# by executing (via popen()) the command <filter> <input-file>, where <filter> \n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \n# input file. Doxygen will then use the output that the filter program writes \n# to standard output.  If FILTER_PATTERNS is specified, this tag will be \n# ignored.\n\nINPUT_FILTER           = \n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \n# basis.  Doxygen will compare the file name with each pattern and apply the \n# filter if there is a match.  The filters are a list of the form: \n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \n# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \n# is applied to all files.\n\nFILTER_PATTERNS        = \n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \n# INPUT_FILTER) will be used to filter the input files when producing source \n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES    = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will \n# be generated. Documented entities will be cross-referenced with these sources. \n# Note: To get rid of all source code in the generated output, make sure also \n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body \n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \n# doxygen to hide any special comment blocks from generated source code \n# fragments. Normal C and C++ comments will always remain visible.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES (the default) \n# then for each documented function all documented \n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES (the default) \n# then for each documented function all documented entities \n# called/used by that function will be listed.\n\nREFERENCES_RELATION    = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code \n# will point to the HTML generated by the htags(1) tool instead of doxygen \n# built-in source browser. The htags tool is part of GNU's global source \n# tagging system (see http://www.gnu.org/software/global/global.html). You \n# will need version 4.8.6 or higher.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \n# will generate a verbatim copy of the header file for each class for \n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \n# of all compounds will be generated. Enable this if the project \n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX     = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all \n# classes will be put under the same header in the alphabetical index. \n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX          = \n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \n# generate HTML output.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard header.\n\nHTML_HEADER            = \n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard footer.\n\nHTML_FOOTER            = \n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \n# style sheet that is used by each HTML page. It can be used to \n# fine-tune the look of the HTML output. If the tag is left blank doxygen \n# will generate a default style sheet. Note that doxygen will try to copy \n# the style sheet file to the HTML output directory, so don't put your own \n# stylesheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET        = \n\n# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \n# files or namespaces will be aligned in HTML using tables. If set to \n# NO a bullet list will be used.\n\nHTML_ALIGN_MEMBERS     = YES\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files \n# will be generated that can be used as input for tools like the \n# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP      = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \n# be used to specify the file name of the resulting .chm file. You \n# can add a path in front of the file if the result should not be \n# written to the html output directory.\n\nCHM_FILE               = \n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \n# be used to specify the location (absolute path including file name) of \n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION           = \n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \n# controls if a separate .chi index file is generated (YES) or that \n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI           = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \n# controls whether a binary table of contents is generated (YES) or a \n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members \n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND             = NO\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \n# top of each HTML page. The value NO (the default) enables the index and \n# the value YES disables it.\n\nDISABLE_INDEX          = NO\n\n# This tag can be used to set the number of enum values (range [1..20]) \n# that doxygen will group on one line in the generated HTML documentation.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\n# generated containing a tree-like index structure (just like the one that \n# is generated for HTML Help). For this to work a browser that supports \n# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \n# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \n# probably better off using the HTML help feature.\n\nGENERATE_TREEVIEW      = NO\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \n# used to set the initial width (in pixels) of the frame in which the tree \n# is shown.\n\nTREEVIEW_WIDTH         = 250\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \n# generate Latex output.\n\nGENERATE_LATEX         = YES\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \n# invoked. If left blank `latex' will be used as the default command name.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \n# generate index for LaTeX. If left blank `makeindex' will be used as the \n# default command name.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \n# LaTeX documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used \n# by the printer. Possible values are: a4, a4wide, letter, legal and \n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE             = a4wide\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES         = \n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \n# the generated latex document. The header should contain everything until \n# the first chapter. If it is left blank doxygen will generate a \n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER           = \n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \n# is prepared for conversion to pdf (using ps2pdf). The pdf file will \n# contain links (just like the HTML output) instead of page references \n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS         = NO\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \n# plain latex in the generated Makefile. Set this option to YES to get a \n# higher quality PDF documentation.\n\nUSE_PDFLATEX           = NO\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode. \n# command to the generated LaTeX files. This will instruct LaTeX to keep \n# running if errors occur, instead of asking the user for help. \n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE        = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not \n# include the index chapters (such as File Index, Compound Index, etc.) \n# in the output.\n\nLATEX_HIDE_INDICES     = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \n# The RTF output is optimized for Word 97 and may not look very pretty with \n# other RTF readers or editors.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \n# RTF documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \n# will contain hyperlink fields. The RTF file will \n# contain links (just like the HTML output) instead of page references. \n# This makes the output suitable for online browsing using WORD or other \n# programs which support those fields. \n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's \n# config file, i.e. a series of assignments. You only have to provide \n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE    = \n\n# Set optional variables used in the generation of an rtf document. \n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE    = \n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \n# generate man pages\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to \n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION          = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \n# then it will generate one additional man file for each entity \n# documented in the real man page(s). These additional files \n# only source the real man page, but without them the man command \n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will \n# generate an XML file that captures the structure of \n# the code including all documentation.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT             = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_SCHEMA             = \n\n# The XML_DTD tag can be used to specify an XML DTD, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_DTD                = \n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \n# dump the program listings (including syntax highlighting \n# and cross-referencing information) to the XML output. Note that \n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \n# generate an AutoGen Definitions (see autogen.sf.net) file \n# that captures the structure of the code including all \n# documentation. Note that this feature is still experimental \n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will \n# generate a Perl module file that captures the structure of \n# the code including all documentation. Note that this \n# feature is still experimental and incomplete at the \n# moment.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \n# the necessary Makefile rules, Perl scripts and LaTeX code to be able \n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \n# nicely formatted so it can be parsed by a human reader.  This is useful \n# if you want to understand what is going on.  On the other hand, if this \n# tag is set to NO the size of the Perl module output will be much smaller \n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file \n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \n# This is useful so different doxyrules.make files included by the same \n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor   \n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \n# evaluate all C-preprocessor directives found in the sources and include \n# files.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \n# names in the source code. If set to NO (the default) only conditional \n# compilation will be performed. Macro expansion can be done in a controlled \n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \n# then the macro expansion is limited to the macros specified with the \n# PREDEFINED and EXPAND_AS_PREDEFINED tags.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \n# in the INCLUDE_PATH (see below) will be search if a #include is found.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that \n# contain include files that are not input files but should be processed by \n# the preprocessor.\n\nINCLUDE_PATH           = \n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \n# patterns (like *.h and *.hpp) to filter out the header-files in the \n# directories. If left blank, the patterns specified with FILE_PATTERNS will \n# be used.\n\nINCLUDE_FILE_PATTERNS  = \n\n# The PREDEFINED tag can be used to specify one or more macro names that \n# are defined before the preprocessor is started (similar to the -D option of \n# gcc). The argument of the tag is a list of macros of the form: name \n# or name=definition (no spaces). If the definition and the = are \n# omitted =1 is assumed. To prevent a macro definition from being \n# undefined via #undef or recursively expanded use the := operator \n# instead of the = operator.\n\nPREDEFINED             = \n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \n# this tag can be used to specify a list of macro names that should be expanded. \n# The macro definition that is found in the sources will be used. \n# Use the PREDEFINED tag if you want to use a different macro definition.\n\nEXPAND_AS_DEFINED      = \n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \n# doxygen's preprocessor will remove all function-like macros that are alone \n# on a line, have an all uppercase name, and do not end with a semicolon. Such \n# function macros are typically used for boiler-plate code, and will confuse \n# the parser if not removed.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references   \n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles. \n# Optionally an initial location of the external documentation \n# can be added for each tagfile. The format of a tag file without \n# this location is as follows: \n#   TAGFILES = file1 file2 ... \n# Adding location for the tag files is done as follows: \n#   TAGFILES = file1=loc1 \"file2 = loc2\" ... \n# where \"loc1\" and \"loc2\" can be relative or absolute paths or \n# URLs. If a location is present for each tag, the installdox tool \n# does not have to be run to correct the links.\n# Note that each tag file must have a unique name\n# (where the name does NOT include the path)\n# If a tag file is not located in the directory in which doxygen \n# is run, you must also specify the path to the tagfile here.\n\nTAGFILES               = \n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create \n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE       = \n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed \n# in the class index. If set to NO only the inherited external classes \n# will be listed.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \n# in the modules index. If set to NO, only the current project's groups will \n# be listed.\n\nEXTERNAL_GROUPS        = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script \n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool   \n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base \n# or super classes. Setting the tag to NO turns the diagrams off. Note that \n# this option is superseded by the HAVE_DOT option below. This is only a \n# fallback. It is recommended to install and use dot, since it yields more \n# powerful graphs.\n\nCLASS_DIAGRAMS         = YES\n\n# If set to YES, the inheritance and collaboration graphs will hide \n# inheritance and usage relations if the target is undocumented \n# or is not a class.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \n# available from the path. This tool is part of Graphviz, a graph visualization \n# toolkit from AT&T and Lucent Bell Labs. The other options in this section \n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT               = NO\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect inheritance relations. Setting this tag to YES will force the \n# the CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect implementation dependencies (inheritance, containment, and \n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \n# collaboration diagrams in a style similar to the OMG's Unified Modeling \n# Language.\n\nUML_LOOK               = NO\n\n# If set to YES, the inheritance and collaboration graphs will show the \n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \n# tags are set to YES then doxygen will generate a graph for each documented \n# file showing the direct and indirect include dependencies of the file with \n# other documented files.\n\nINCLUDE_GRAPH          = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \n# documented header file showing the documented files that directly or \n# indirectly include this file.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a call dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable call graphs for selected \n# functions only using the \\callgraph command.\n\nCALL_GRAPH             = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \n# will graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \n# then doxygen will show the dependencies a directory has on other directories \n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \n# generated by dot. Possible values are png, jpg, or gif\n# If left blank png will be used.\n\nDOT_IMAGE_FORMAT       = png\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be \n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH               = \n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that \n# contain dot files that are included in the documentation (see the \n# \\dotfile command).\n\nDOTFILE_DIRS           = \n\n# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_WIDTH    = 1024\n\n# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_HEIGHT   = 1024\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \n# graphs generated by dot. A depth value of 3 means that only nodes reachable \n# from the root by following a path via at most 3 edges will be shown. Nodes \n# that lay further from the root node will be omitted. Note that setting this \n# option to 1 or 2 may greatly reduce the computation time needed for large \n# code bases. Also note that a graph may be further truncated if the graph's \n# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH \n# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), \n# the graph is not depth-constrained.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent \n# background. This is disabled by default, which results in a white background. \n# Warning: Depending on the platform used, enabling this option may lead to \n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to \n# read).\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output \n# files in one run (i.e. multiple -o and -T options on the command line). This \n# makes dot run faster, but since only newer versions of dot (>1.8.10) \n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \n# generate a legend page explaining the meaning of the various boxes and \n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \n# remove the intermediate dot files that are used to generate \n# the various graphs.\n\nDOT_CLEANUP            = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to the search engine   \n#---------------------------------------------------------------------------\n\n# The SEARCHENGINE tag specifies whether or not a search engine should be \n# used. If set to NO the values of all tags below this one will be ignored.\n\nSEARCHENGINE           = NO\n"
  },
  {
    "path": "src/contrib/zkfuse/src/event.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"event.h\"\n\n#define LOG_LEVEL LOG_FATAL\n#define MODULE_NAME \"Event\"\n\nusing namespace std;\n\nnamespace zkfuse {\n\n}       /* end of 'namespace zkfuse' */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/event.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __EVENT_H__\n#define __EVENT_H__\n\n#include <string>\n#include <set>\n#include <deque>\n#include <algorithm>\n#ifdef GCC4\n#   include <tr1/memory>\nusing namespace std::tr1;\n#else\n#   include <boost/shared_ptr.hpp>\nusing namespace boost;\n#endif\n\n#include \"log.h\"\n#include \"blockingqueue.h\"\n#include \"mutex.h\"\n#include \"thread.h\"\n\nusing namespace std;\nusing namespace zk;\n\nnamespace zkfuse {\n\n//forward declaration of EventSource\ntemplate<typename E>\nclass EventSource;\n\n/**\n * \\brief This interface is implemented by an observer\n * \\brief of a particular {@link EventSource}.\n */\ntemplate<typename E>\nclass EventListener {\n    public:\n        \n        /**\n         * \\brief This method is invoked whenever an event \n         * \\brief has been received by the event source being observed.\n         * \n         * @param source the source the triggered the event\n         * @param e      the actual event being triggered\n         */\n        virtual void eventReceived(const EventSource<E> &source, const E &e) = 0;\n};            \n\n/**\n * \\brief This class represents a source of events.\n * \n * <p>\n * Each source can have many observers (listeners) attached to it\n * and in case of an event, this source may propagate the event\n * using {@link #fireEvent} method.\n */\ntemplate<typename E>           \nclass EventSource {\n    public:\n        \n        /**\n         * \\brief The type corresponding to the list of registered event listeners.\n         */\n        typedef set<EventListener<E> *> EventListeners;\n        \n        /**\n         * \\brief Registers a new event listener.\n         * \n         * @param listener the listener to be added to the set of listeners\n         */\n        void addListener(EventListener<E> *listener) {\n            m_listeners.insert( listener );\n        }\n        \n        /**\n         * \\brief Removes an already registered listener.\n         * \n         * @param listener the listener to be removed\n         */\n        void removeListener(EventListener<E> *listener) {\n            m_listeners.erase( listener );\n        }\n        \n        /**\n         * \\brief Destructor.\n         */\n        virtual ~EventSource() {}\n        \n    protected:\n        \n        /**\n         * \\brief Fires the given event to all registered listeners.\n         * \n         * <p>\n         * This method essentially iterates over all listeners\n         * and invokes {@link fireEvent(EventListener<E> *listener, const E &event)}\n         * for each element. All derived classes are free to\n         * override the method to provide better error handling\n         * than the default implementation.\n         * \n         * @param event the event to be propagated to all listeners\n         */\n        void fireEvent(const E &event);\n        \n        /**\n         * \\brief Sends an event to the given listener.\n         * \n         * @param listener the listener to whom pass the event\n         * @param event the event to be handled\n         */\n        virtual void fireEvent(EventListener<E> *listener, const E &event);\n        \n    private:\n        \n        /**\n         * The set of registered event listeners.\n         */\n        EventListeners m_listeners;            \n    \n};\n\n/**\n * \\brief The interface of a generic event wrapper.\n */\nclass AbstractEventWrapper {\n    public:\n        \n        /**\n         * \\brief Destructor.\n         */\n        virtual ~AbstractEventWrapper() {}\n        \n        /**\n         * \\brief Returns the underlying wrapee's data.\n         */\n        virtual void *getWrapee() = 0;\n};\n\n/**\n * \\brief A template based implementation of {@link AbstractEventWrapper}.\n */\ntemplate<typename E>\nclass EventWrapper : public AbstractEventWrapper {\n    public:\n        EventWrapper(const E &e) : m_e(e) {\n        }\n        void *getWrapee() {\n            return &m_e;\n        }\n    private:\n        E m_e;\n};\n\n/**\n * \\brief This class represents a generic event.\n */\nclass GenericEvent {\n    public:\n        \n        /**\n         * \\brief Constructor.\n         */\n        GenericEvent() : m_type(0) {}\n\n        /**\n         * \\brief Constructor.\n         * \n         * @param type the type of this event\n         * @param eventWarpper the wrapper around event's data\n         */\n        GenericEvent(int type, AbstractEventWrapper *eventWrapper) : \n            m_type(type), m_eventWrapper(eventWrapper) {\n        }\n        \n        /**\n         * \\brief Returns the type of this event.\n         * \n         * @return type of this event\n         */\n        int getType() const { return m_type; }\n        \n        /**\n         * \\brief Returns the event's data.\n         * \n         * @return the event's data\n         */\n        void *getEvent() const { return m_eventWrapper->getWrapee(); }\n        \n    private:\n\n        /**\n         * The event type.\n         */\n        int m_type;\n\n        /**\n         * The event represented as abstract wrapper.\n         */\n        boost::shared_ptr<AbstractEventWrapper> m_eventWrapper;\n        \n};\n    \n/**\n * \\brief This class adapts {@link EventListener} to a generic listener.\n * Essentially this class listens on incoming events and fires them \n * as {@link GenericEvent}s.\n */\ntemplate<typename E, const int type>\nclass EventListenerAdapter : public virtual EventListener<E>,\n                             public virtual EventSource<GenericEvent>\n{\n    public:\n        \n        /**\n         * \\brief Constructor.\n         * \n         * @param eventSource the source on which register this listener\n         */\n        EventListenerAdapter(EventSource<E> &eventSource) {\n            eventSource.addListener(this);\n        }\n        \n        void eventReceived(const EventSource<E> &source, const E &e) {\n            AbstractEventWrapper *wrapper = new EventWrapper<E>(e);\n            GenericEvent event(type, wrapper);\n            fireEvent( event );\n        }\n\n};        \n\n/**\n * \\brief This class provides an adapter between an asynchronous and synchronous \n * \\brief event handling.\n * \n * <p>\n * This class queues up all received events and exposes them through \n * {@link #getNextEvent()} method.\n */\ntemplate<typename E>                  \nclass SynchronousEventAdapter : public EventListener<E> {\n    public:\n        \n        void eventReceived(const EventSource<E> &source, const E &e) {\n            m_queue.put( e );\n        }\n\n        /**\n         * \\brief Returns the next available event from the underlying queue,\n         * \\brief possibly blocking, if no data is available.\n         * \n         * @return the next available event\n         */\n        E getNextEvent() {\n            return m_queue.take();\n        }\n        \n        /**\n         * \\brief Returns whether there are any events in the queue or not.\n         * \n         * @return true if there is at least one event and \n         *         the next call to {@link #getNextEvent} won't block\n         */\n        bool hasEvents() const {\n            return (m_queue.empty() ? false : true);\n        }\n        \n        /**\n         * \\brief Destructor.\n         */\n        virtual ~SynchronousEventAdapter() {}\n\n    private:\n        \n        /**\n         * The blocking queue of all events received so far.\n         */\n        BlockingQueue<E> m_queue;\n        \n};\n\n/**\n * This typedef defines the type of a timer Id.\n */\ntypedef int32_t TimerId;\n\n/**\n * This class represents a timer event parametrized by the user's data type.\n */\ntemplate<typename T>\nclass TimerEvent {\n    public:\n       \n        /**\n         * \\brief Constructor.\n         * \n         * @param id the ID of this event\n         * @param alarmTime when this event is to be triggered\n         * @param userData the user data associated with this event\n         */\n        TimerEvent(TimerId id, int64_t alarmTime, const T &userData) :\n            m_id(id), m_alarmTime(alarmTime), m_userData(userData) \n        {}     \n\n        /**\n         * \\brief Constructor.\n         */\n        TimerEvent() : m_id(-1), m_alarmTime(-1) {}\n                           \n        /**\n         * \\brief Returns the ID.\n         * \n         * @return the ID of this event\n         */\n        TimerId getID() const { return m_id; }\n        \n        /**\n         * \\brief Returns the alarm time.\n         * \n         * @return the alarm time\n         */\n        int64_t getAlarmTime() const { return m_alarmTime; }\n              \n        /**\n         * \\brief Returns the user's data.\n         * \n         * @return the user's data\n         */\n        T const &getUserData() const { return m_userData; }\n        \n        /**\n         * \\brief Returns whether the given alarm time is less than this event's \n         * \\brief time.\n         */\n        bool operator<(const int64_t alarmTime) const {\n            return m_alarmTime < alarmTime;\n        }\n        \n    private:\n        \n        /**\n         * The ID of ths event.\n         */\n        TimerId m_id;\n        \n        /**\n         * The time at which this event triggers.\n         */\n        int64_t m_alarmTime;    \n        \n        /**\n         * The user specific data associated with this event.\n         */\n        T m_userData;\n        \n};\n\ntemplate<typename T>\nclass Timer : public EventSource<TimerEvent<T> > {\n    public:\n        \n        /**\n         * \\brief Constructor.\n         */\n        Timer() : m_currentEventID(0), m_terminating(false) {\n            m_workerThread.Create( *this, &Timer<T>::sendAlarms );\n        }\n        \n        /**\n         * \\brief Destructor.\n         */\n        ~Timer() {\n            m_terminating = true;\n            m_lock.notify();\n            m_workerThread.Join();\n        }\n        \n        /**\n         * \\brief Schedules the given event <code>timeFromNow</code> milliseconds.\n         * \n         * @param timeFromNow time from now, in milliseconds, when the event \n         *                    should be triggered \n         * @param userData the user data associated with the timer event\n         * \n         * @return the ID of the newly created timer event\n         */\n        TimerId scheduleAfter(int64_t timeFromNow, const T &userData) {\n            return scheduleAt( getCurrentTimeMillis() + timeFromNow, userData );\n        }\n\n        /**\n         * \\brief Schedules an event at the given time.\n         * \n         * @param absTime absolute time, in milliseconds, at which the event \n         *                should be triggered; the time is measured\n         *                from Jan 1st, 1970   \n         * @param userData the user data associated with the timer event\n         * \n         * @return the ID of the newly created timer event\n         */\n        TimerId scheduleAt(int64_t absTime, const T &userData) {\n            m_lock.lock();\n            typename QueueType::iterator pos = \n                    lower_bound( m_queue.begin(), m_queue.end(), absTime );\n            TimerId id = m_currentEventID++;\n            TimerEvent<T> event(id, absTime, userData); \n            m_queue.insert( pos, event );\n            m_lock.notify();\n            m_lock.unlock();\n            return id;\n        }\n        \n        /**\n         * \\brief Returns the current time since Jan 1, 1970, in milliseconds.\n         * \n         * @return the current time in milliseconds\n         */\n        static int64_t getCurrentTimeMillis() {\n            struct timeval now;\n            gettimeofday( &now, NULL );\n            return now.tv_sec * 1000LL + now.tv_usec / 1000;\n        }\n\n        /**\n         * \\brief Cancels the given timer event.\n         * \n         * \n         * @param eventID the ID of the event to be canceled\n         * \n         * @return whether the event has been canceled\n         */\n        bool cancelAlarm(TimerId eventID) {\n            bool canceled = false;                      \n            m_lock.lock();\n            typename QueueType::iterator i;\n            for (i = m_queue.begin(); i != m_queue.end(); ++i) {\n                if (eventID == i->getID()) {\n                    m_queue.erase( i );\n                    canceled = true;\n                    break;\n                }\n            }\n            m_lock.unlock();\n            return canceled;\n        }\n        \n        /**\n         * Executes the main loop of the worker thread.\n         */\n        void sendAlarms() {\n            //iterate until terminating\n            while (!m_terminating) {\n                m_lock.lock();\n                //1 step - wait until there is an event in the queue\n                if (m_queue.empty()) {\n                    //wait up to 100ms to get next event\n                    m_lock.wait( 100 );\n                }     \n                bool fire = false;\n                if (!m_queue.empty()) {\n                    //retrieve the event from the queue and send it\n                    TimerEvent<T> event = m_queue.front();      \n                    //check whether we can send it right away\n                    int64_t timeToWait = \n                        event.getAlarmTime() - getCurrentTimeMillis();\n                    if (timeToWait <= 0) {\n                        m_queue.pop_front();\n                        //we fire only if it's still in the queue and alarm\n                        //time has just elapsed (in case the top event\n                        //is canceled)\n                        fire = true;    \n                    } else {\n                        m_lock.wait( timeToWait );\n                    }\n                    m_lock.unlock();\n                    if (fire) {\n                        fireEvent( event );\n                    }\n                } else {\n                    m_lock.unlock();\n                }\n            }    \n        }\n        \n    private:\n        \n        /**\n         * The type of timer events queue.\n         */\n        typedef deque<TimerEvent<T> > QueueType;\n        \n        /**\n         * The current event ID, auto-incremented each time a new event \n         * is created.\n         */\n        TimerId m_currentEventID;\n        \n        /**\n         * The queue of timer events sorted by {@link TimerEvent#alarmTime}.\n         */\n        QueueType m_queue;\n        \n        /**\n         * The lock used to guard {@link #m_queue}.\n         */\n        Lock m_lock;\n        \n        /**\n         * The thread that triggers alarms.\n         */\n        CXXThread<Timer<T> > m_workerThread;\n        \n        /**\n         * Whether {@link #m_workerThread}  is terminating.\n         */\n        volatile bool m_terminating;\n        \n};\n\ntemplate<typename E>\nvoid EventSource<E>::fireEvent(const E &event) {\n    for (typename EventListeners::iterator i = m_listeners.begin(); \n         i != m_listeners.end(); \n         ++i) \n    {\n        fireEvent( *i, event );\n    }\n}\n\ntemplate<typename E>\nvoid EventSource<E>::fireEvent(EventListener<E> *listener, const E &event) {\n    listener->eventReceived( *this, event );\n}\n        \n}   /* end of 'namespace zkfuse' */\n\n#endif /* __EVENT_H__ */\n"
  },
  {
    "path": "src/contrib/zkfuse/src/log.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <string>\n  \n#include \"log.h\"\n\nusing namespace std;\n  \n/**\n * \\brief This class encapsulates a log4cxx configuration.\n */\nclass LogConfiguration {\n    public:\n        LogConfiguration(const string &file) {\n            PropertyConfigurator::configureAndWatch( file, 5000 );\n        }\n};\n\n//enforces the configuration to be initialized\nstatic LogConfiguration logConfig( \"log4cxx.properties\" );\n"
  },
  {
    "path": "src/contrib/zkfuse/src/log.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __LOG_H__\n#define __LOG_H__\n\n#define ZKFUSE_NAMESPACE zkfuse\n#define START_ZKFUSE_NAMESPACE namespace ZKFUSE_NAMESPACE {\n#define END_ZKFUSE_NAMESPACE   }\n#define USING_ZKFUSE_NAMESPACE using namespace ZKFUSE_NAMESPACE;\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <pthread.h>\n\n#include <log4cxx/logger.h> \n#include <log4cxx/propertyconfigurator.h> \n#include <log4cxx/helpers/exception.h> \nusing namespace log4cxx; \nusing namespace log4cxx::helpers;\n\n#define PRINTIP(x) ((uint8_t*)&x)[0], ((uint8_t*)&x)[1], \\\n                   ((uint8_t*)&x)[2], ((uint8_t*)&x)[3]\n\n#define IPFMT \"%u.%u.%u.%u\"\n\n#define DECLARE_LOGGER(varName) \\\nextern LoggerPtr varName;\n\n#define DEFINE_LOGGER(varName, logName) \\\nstatic LoggerPtr varName = Logger::getLogger( logName );\n\n#define MAX_BUFFER_SIZE 20000\n\n#define SPRINTF_LOG_MSG(buffer, fmt, args...) \\\n    char buffer[MAX_BUFFER_SIZE]; \\\n    snprintf( buffer, MAX_BUFFER_SIZE, fmt, ##args );\n\n// older versions of log4cxx don't support tracing\n#ifdef LOG4CXX_TRACE\n#define LOG_TRACE(logger, fmt, args...) \\\n    if (logger->isTraceEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_TRACE( logger, __tmp ); \\\n    }\n#else\n#define LOG_TRACE(logger, fmt, args...) \\\n    if (logger->isDebugEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_DEBUG( logger, __tmp ); \\\n    }\n#endif\n\n#define LOG_DEBUG(logger, fmt, args...) \\\n    if (logger->isDebugEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_DEBUG( logger, __tmp ); \\\n    }\n\n#define LOG_INFO(logger, fmt, args...) \\\n    if (logger->isInfoEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_INFO( logger, __tmp ); \\\n    }\n\n#define LOG_WARN(logger, fmt, args...) \\\n    if (logger->isWarnEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_WARN( logger, __tmp ); \\\n    }\n\n#define LOG_ERROR(logger, fmt, args...) \\\n    if (logger->isErrorEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_ERROR( logger, __tmp ); \\\n    }\n\n#define LOG_FATAL(logger, fmt, args...) \\\n    if (logger->isFatalEnabled()) { \\\n        SPRINTF_LOG_MSG( __tmp, fmt, ##args ); \\\n        LOG4CXX_FATAL( logger, __tmp ); \\\n    }\n\n#ifdef DISABLE_TRACE\n#   define TRACE(logger, x)\n#else   \n#   define TRACE(logger, x) \\\nclass Trace { \\\n public: \\\n    Trace(const void* p) : _p(p) { \\\n        LOG_TRACE(logger, \"%s %p Enter\", __PRETTY_FUNCTION__, p); \\\n    } \\\n    ~Trace() { \\\n        LOG_TRACE(logger, \"%s %p Exit\", __PRETTY_FUNCTION__, _p); \\\n    } \\\n    const void* _p; \\\n} traceObj(x);\n#endif  /* DISABLE_TRACE */\n    \n#endif  /* __LOG_H__ */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/log4cxx.properties",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Set root logger level to DEBUG and its only appender to A1.\nlog4j.rootLogger=TRACE, A1\n\n# A1 is set to be a ConsoleAppender.\nlog4j.appender.A1=org.apache.log4cxx.ConsoleAppender\n\n# A1 uses PatternLayout.\nlog4j.appender.A1.layout=org.apache.log4cxx.PatternLayout\nlog4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n\n\nlog4j.category.zkfuse=TRACE\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/mutex.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __MUTEX_H__\n#define __MUTEX_H__\n\n#include <pthread.h>\n#include <errno.h>\n#include <sys/time.h>\n\n#include \"log.h\"\n\nSTART_ZKFUSE_NAMESPACE\n\nclass Cond;\n\nclass Mutex {\n    friend class Cond;\n  public:\n    Mutex() {\n        pthread_mutexattr_init( &m_mutexAttr );\n        pthread_mutexattr_settype( &m_mutexAttr, PTHREAD_MUTEX_RECURSIVE_NP );\n        pthread_mutex_init( &mutex, &m_mutexAttr );\n    }\n    ~Mutex() {\n        pthread_mutex_destroy(&mutex);\n        pthread_mutexattr_destroy( &m_mutexAttr );\n    }\n    void Acquire() { Lock(); }\n    void Release() { Unlock(); }\n    void Lock() {\n        pthread_mutex_lock(&mutex);\n    }\n    int  TryLock() {\n        return pthread_mutex_trylock(&mutex);\n    }\n    void Unlock() {\n        pthread_mutex_unlock(&mutex);\n    }\n  private:\n    pthread_mutex_t mutex;\n    pthread_mutexattr_t m_mutexAttr;\n};\n\nclass AutoLock {\n  public:\n    AutoLock(Mutex& mutex) : _mutex(mutex) {\n        mutex.Lock();\n    }\n    ~AutoLock() {\n        _mutex.Unlock();\n    }\n  private:\n    friend class AutoUnlockTemp;\n    Mutex& _mutex;\n};\n\nclass AutoUnlockTemp {\n  public:\n    AutoUnlockTemp(AutoLock & autoLock) : _autoLock(autoLock) {\n        _autoLock._mutex.Unlock();\n    }\n    ~AutoUnlockTemp() {\n        _autoLock._mutex.Lock();\n    }\n  private:\n    AutoLock & _autoLock;\n};\n\nclass Cond {\n  public:\n    Cond() {\n        static pthread_condattr_t attr;\n        static bool inited = false;\n        if(!inited) {\n            inited = true;\n            pthread_condattr_init(&attr);\n        }\n        pthread_cond_init(&_cond, &attr);\n    }\n    ~Cond() {\n        pthread_cond_destroy(&_cond);\n    }\n\n    void Wait(Mutex& mutex) {\n        pthread_cond_wait(&_cond, &mutex.mutex);\n    }\n\n    bool Wait(Mutex& mutex, long long int timeout) {\n        struct timeval now;\n        gettimeofday( &now, NULL );\n        struct timespec abstime;\n        int64_t microSecs = now.tv_sec * 1000000LL + now.tv_usec;\n        microSecs += timeout * 1000;\n        abstime.tv_sec = microSecs / 1000000LL;\n        abstime.tv_nsec = (microSecs % 1000000LL) * 1000;\n        if (pthread_cond_timedwait(&_cond, &mutex.mutex, &abstime) == ETIMEDOUT) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n    \n    void Signal() {\n        pthread_cond_signal(&_cond);\n    }\n\n  private:\n    pthread_cond_t            _cond;\n};\n\n/**\n * A wrapper class for {@link Mutex} and {@link Cond}.\n */\nclass Lock {\n    public:\n        \n        void lock() {\n            m_mutex.Lock();\n        }\n        \n        void unlock() {\n            m_mutex.Unlock();\n        }\n        \n        void wait() {\n            m_cond.Wait( m_mutex );\n        }\n\n        bool wait(long long int timeout) {\n            return m_cond.Wait( m_mutex, timeout );\n        }\n        \n        void notify() {\n            m_cond.Signal();\n        }\n\n    private:\n        \n        /**\n         * The mutex.\n         */\n        Mutex m_mutex;\n        \n        /**\n         * The condition associated with this lock's mutex.\n         */\n        Cond m_cond;         \n};\n\nEND_ZKFUSE_NAMESPACE\n        \n#endif /* __MUTEX_H__ */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/thread.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <log.h>\n\n#include \"thread.h\"\n\nDEFINE_LOGGER( LOG, \"Thread\" )\n\nSTART_ZKFUSE_NAMESPACE\n\nvoid Thread::Create(void* ctx, ThreadFunc func)\n{\n    pthread_attr_t attr;\n    pthread_attr_init(&attr);\n    pthread_attr_setstacksize(&attr, _stackSize);\n    int ret = pthread_create(&mThread, &attr, func, ctx);\n    if(ret != 0) {\n        LOG_FATAL( LOG, \"pthread_create failed: %s\", strerror(errno) );\n    }\n    // pthread_attr_destroy(&attr); \n    _ctx = ctx;\n    _func = func;\n}\n\nEND_ZKFUSE_NAMESPACE\n"
  },
  {
    "path": "src/contrib/zkfuse/src/thread.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __THREAD_H__\n#define __THREAD_H__\n\n#include <errno.h>\n#include <string.h>\n#include <assert.h>\n#include <pthread.h>\n\n#include \"log.h\"\n\nSTART_ZKFUSE_NAMESPACE\n\nclass Thread {\n  public:\n    static const size_t defaultStackSize = 1024 * 1024;\n    typedef void* (*ThreadFunc) (void*);\n    Thread(size_t stackSize = defaultStackSize) \n      : _stackSize(stackSize), _ctx(NULL), _func(NULL) \n    {\n        memset( &mThread, 0, sizeof(mThread) );\n    }\n    ~Thread() { }\n\n    void Create(void* ctx, ThreadFunc func);\n    void Join() {\n        //avoid SEGFAULT because of unitialized mThread\n        //in case Create(...) was never called\n        if (_func != NULL) {\n            pthread_join(mThread, 0);\n        }\n    }\n  private:\n    pthread_t mThread;  \n    void *_ctx;\n    ThreadFunc _func;\n    size_t _stackSize;\n};\n\n\ntemplate<typename T>\nstruct ThreadContext {\n    typedef void (T::*FuncPtr) (void);\n    ThreadContext(T& ctx, FuncPtr func) : _ctx(ctx), _func(func) {}\n    void run(void) {\n        (_ctx.*_func)();\n    }\n    T& _ctx;\n    FuncPtr   _func;\n};\n\ntemplate<typename T>\nvoid* ThreadExec(void *obj) {\n    ThreadContext<T>* tc = (ThreadContext<T>*)(obj);\n    assert(tc != 0);\n    tc->run();\n    return 0;\n}\n\ntemplate <typename T>\nclass CXXThread : public Thread {\n  public:\n    typedef void (T::*FuncPtr) (void);\n    CXXThread(size_t stackSize = Thread::defaultStackSize) \n      : Thread(stackSize), ctx(0) {}\n    ~CXXThread() { if (ctx) delete ctx; }\n\n    void Create(T& obj, FuncPtr func) {\n        assert(ctx == 0);\n        ctx = new ThreadContext<T>(obj, func);\n        Thread::Create(ctx, ThreadExec<T>);\n    }\n\n  private:\n    ThreadContext<T>* ctx;\n};\n\n    \nEND_ZKFUSE_NAMESPACE\n\n#endif /* __THREAD_H__ */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/zkadapter.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <algorithm>\n#include <iostream>\n\n#include \"blockingqueue.h\"\n#include \"thread.h\"\n#include \"zkadapter.h\"\n\nusing namespace std;\nusing namespace zk;\n\nDEFINE_LOGGER( LOG, \"zookeeper.adapter\" )\nDEFINE_LOGGER( ZK_LOG, \"zookeeper.core\" )\n\n/**\n * \\brief A helper class to initialize ZK logging.\n */\nclass InitZooKeeperLogging\n{\n  public:\n    InitZooKeeperLogging() {\n        if (ZK_LOG->isDebugEnabled()\n#ifdef LOG4CXX_TRACE\n            || ZK_LOG->isTraceEnabled()\n#endif\n            ) \n        {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_DEBUG );\n        } else if (ZK_LOG->isInfoEnabled()) {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_INFO );\n        } else if (ZK_LOG->isWarnEnabled()) {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_WARN );\n        } else {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_ERROR );\n        }\n    }\n};\n\nusing namespace std;\n\nnamespace zk\n{\n\n/**\n * \\brief This class provides logic for checking if a request can be retried.\n */\nclass RetryHandler\n{\n  public:\n    RetryHandler(const ZooKeeperConfig &zkConfig)\n        : m_zkConfig(zkConfig)\n    {\n        if (zkConfig.getAutoReconnect()) {\n            retries = 2;\n        } else {\n            retries = 0;\n        }\n    }\n        \n    /**\n     * \\brief Attempts to fix a side effect of the given RC.\n     * \n     * @param rc the ZK error code\n     * @return whether the error code has been handled and the caller should \n     *         retry an operation the caused this error\n     */\n    bool handleRC(int rc)\n    {\n        TRACE( LOG, \"handleRC\" );\n\n        //check if the given error code is recoverable\n        if (!retryOnError(rc)) {\n            return false;\n        }\n        LOG_TRACE( LOG, \"RC: %d, retries left: %d\", rc, retries );\n        if (retries-- > 0) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n        \n  private:\n    /**\n     * The ZK config.\n     */\n    const ZooKeeperConfig &m_zkConfig;\n        \n    /**\n     * The number of outstanding retries.\n     */\n    int retries;    \n        \n    /**\n     * Checks whether the given error entitles this adapter\n     * to retry the previous operation.\n     * \n     * @param zkErrorCode one of the ZK error code\n     */\n    static bool retryOnError(int zkErrorCode)\n    {\n        return (zkErrorCode == ZCONNECTIONLOSS ||\n                zkErrorCode == ZOPERATIONTIMEOUT);\n    }\n};\n    \n    \n//the implementation of the global ZK event watcher\nvoid zkWatcher(zhandle_t *zh, int type, int state, const char *path,\n               void *watcherCtx)\n{\n    TRACE( LOG, \"zkWatcher\" );\n\n    //a workaround for buggy ZK API\n    string sPath = \n        (path == NULL || \n         state == ZOO_SESSION_EVENT || \n         state == ZOO_NOTWATCHING_EVENT)\n        ? \"\" \n        : string(path);\n    LOG_INFO( LOG,\n              \"Received a ZK event - type: %d, state: %d, path: '%s'\",\n              type, state, sPath.c_str() );\n    ZooKeeperAdapter *zka = (ZooKeeperAdapter *)zoo_get_context(zh);\n    if (zka != NULL) {\n        zka->enqueueEvent( type, state, sPath );\n    } else {\n        LOG_ERROR( LOG,\n                   \"Skipping ZK event (type: %d, state: %d, path: '%s'), \"\n                   \"because ZK passed no context\",\n                   type, state, sPath.c_str() );\n    }\n}\n\n\n\n// =======================================================================\n\nZooKeeperAdapter::ZooKeeperAdapter(ZooKeeperConfig config, \n                                   ZKEventListener *listener,\n                                   bool establishConnection) \n    throw(ZooKeeperException)\n    : m_zkConfig(config),\n      mp_zkHandle(NULL), \n      m_terminating(false),\n      m_connected(false),\n      m_state(AS_DISCONNECTED) \n{\n    TRACE( LOG, \"ZooKeeperAdapter\" );\n\n    resetRemainingConnectTimeout();\n    \n    //enforce setting up appropriate ZK log level\n    static InitZooKeeperLogging INIT_ZK_LOGGING;\n    \n    if (listener != NULL) {\n        addListener(listener);\n    }\n\n    //start the event dispatcher thread\n    m_eventDispatcher.Create( *this, &ZooKeeperAdapter::processEvents );\n\n    //start the user event dispatcher thread\n    m_userEventDispatcher.Create( *this, &ZooKeeperAdapter::processUserEvents );\n    \n    //optionally establish the connection\n    if (establishConnection) {\n        reconnect();\n    }\n}\n\nZooKeeperAdapter::~ZooKeeperAdapter()\n{\n    TRACE( LOG, \"~ZooKeeperAdapter\" );\n\n    try {\n        disconnect();\n    } catch (std::exception &e) {\n        LOG_ERROR( LOG, \n                   \"An exception while disconnecting from ZK: %s\",\n                   e.what() );\n    }\n    m_terminating = true;\n    m_userEventDispatcher.Join();\n    m_eventDispatcher.Join();\n}\n\nvoid\nZooKeeperAdapter::validatePath(const string &path) throw(ZooKeeperException)\n{\n    TRACE( LOG, \"validatePath\" );\n    \n    if (path.find( \"/\" ) != 0) {\n        throw ZooKeeperException( string(\"Node path must start with '/' but\"\n                                         \"it was '\") +\n                                  path +\n                                  \"'\" );\n    }\n    if (path.length() > 1) {\n        if (path.rfind( \"/\" ) == path.length() - 1) {\n            throw ZooKeeperException( string(\"Node path must not end with \"\n                                             \"'/' but it was '\") +\n                                      path +\n                                      \"'\" );\n        }\n        if (path.find( \"//\" ) != string::npos) {\n            throw ZooKeeperException( string(\"Node path must not contain \"\n                                             \"'//' but it was '\") +\n                                      path +\n                                      \"'\" ); \n        }\n    }\n}\n\nvoid\nZooKeeperAdapter::disconnect()\n{\n    TRACE( LOG, \"disconnect\" );\n    LOG_TRACE( LOG, \"mp_zkHandle: %p, state %d\", mp_zkHandle, m_state );\n\n    m_stateLock.lock();\n    if (mp_zkHandle != NULL) {\n        zookeeper_close( mp_zkHandle );\n        mp_zkHandle = NULL;\n        setState( AS_DISCONNECTED );\n    }\n    m_stateLock.unlock();\n}\n\nvoid\nZooKeeperAdapter::reconnect() throw(ZooKeeperException)\n{\n    TRACE( LOG, \"reconnect\" );\n    \n    m_stateLock.lock();\n    //clear the connection state\n    disconnect();\n    \n    //establish a new connection to ZooKeeper\n    mp_zkHandle = zookeeper_init( m_zkConfig.getHosts().c_str(), \n                                  zkWatcher, \n                                  m_zkConfig.getLeaseTimeout(),\n                                  NULL, this, 0);\n    resetRemainingConnectTimeout();\n    if (mp_zkHandle != NULL) {\n        setState( AS_CONNECTING );\n        m_stateLock.unlock();\n    } else {\n        m_stateLock.unlock();\n        throw ZooKeeperException( \n            string(\"Unable to connect to ZK running at '\") +\n                    m_zkConfig.getHosts() + \"'\" );\n    }\n    \n    LOG_DEBUG( LOG, \"mp_zkHandle: %p, state %d\", mp_zkHandle, m_state ); \n}\n\nvoid\nZooKeeperAdapter::handleEvent(int type, int state, const string &path)\n{\n    TRACE( LOG, \"handleEvent\" );\n    LOG_TRACE( LOG, \n               \"type: %d, state %d, path: %s\",\n               type, state, path.c_str() );\n    Listener2Context context, context2;\n    //ignore internal ZK events\n    if (type != ZOO_SESSION_EVENT && type != ZOO_NOTWATCHING_EVENT) {\n        m_zkContextsMutex.Acquire();\n        //check if the user context is available\n        if (type == ZOO_CHANGED_EVENT || type == ZOO_DELETED_EVENT) {\n            //we may have two types of interest here, \n            //in this case lets try to notify twice\n            context = findAndRemoveListenerContext( GET_NODE_DATA, path );\n            context2 = findAndRemoveListenerContext( NODE_EXISTS, path );\n            if (context.empty()) {\n                //make sure that the 2nd context is NULL and\n                // assign it to the 1st one\n                context = context2;\n                context2.clear();\n            }\n        } else if (type == ZOO_CHILD_EVENT) {\n            context = findAndRemoveListenerContext( GET_NODE_CHILDREN, path );\n        } else if (type == ZOO_CREATED_EVENT) {\n            context = findAndRemoveListenerContext( NODE_EXISTS, path );\n        }\n        m_zkContextsMutex.Release();\n    }\n    \n    handleEvent( type, state, path, context );\n    if (!context2.empty()) {\n        handleEvent( type, state, path, context2 );\n    }\n}\n\nvoid\nZooKeeperAdapter::handleEvent(int type,\n                              int state,\n                              const string &path,\n                              const Listener2Context &listeners)\n{\n    TRACE( LOG, \"handleEvents\" );\n\n    if (listeners.empty()) {\n        //propagate with empty context\n        ZKWatcherEvent event(type, state, path);\n        fireEvent( event );\n    } else {\n        for (Listener2Context::const_iterator i = listeners.begin();\n             i != listeners.end();\n             ++i) {\n            ZKWatcherEvent event(type, state, path, i->second);\n            if (i->first != NULL) {\n                fireEvent( i->first, event );\n            } else {\n                fireEvent( event );\n            }\n        }\n    }\n}\n\nvoid \nZooKeeperAdapter::enqueueEvent(int type, int state, const string &path)\n{\n    TRACE( LOG, \"enqueueEvents\" );\n\n    m_events.put( ZKWatcherEvent( type, state, path ) );\n}\n\nvoid\nZooKeeperAdapter::processEvents()\n{\n    TRACE( LOG, \"processEvents\" );\n\n    while (!m_terminating) {\n        bool timedOut = false;\n        ZKWatcherEvent source = m_events.take( 100, &timedOut );\n        if (!timedOut) {\n            if (source.getType() == ZOO_SESSION_EVENT) {\n                LOG_INFO( LOG,\n                          \"Received SESSION event, state: %d. Adapter state: %d\",\n                          source.getState(), m_state );\n                m_stateLock.lock();\n                if (source.getState() == ZOO_CONNECTED_STATE) {\n                    m_connected = true;\n                    resetRemainingConnectTimeout();\n                    setState( AS_CONNECTED );\n                } else if (source.getState() == ZOO_CONNECTING_STATE) {\n                    m_connected = false;\n                    setState( AS_CONNECTING );\n                } else if (source.getState() == ZOO_EXPIRED_SESSION_STATE) {\n                    LOG_INFO( LOG, \"Received EXPIRED_SESSION event\" );\n                    setState( AS_SESSION_EXPIRED );\n                }\n                m_stateLock.unlock();\n            }\n            m_userEvents.put( source );\n        }\n    }\n}\n\nvoid\nZooKeeperAdapter::processUserEvents()\n{\n    TRACE( LOG, \"processUserEvents\" );\n\n    while (!m_terminating) {\n        bool timedOut = false;\n        ZKWatcherEvent source = m_userEvents.take( 100, &timedOut );\n        if (!timedOut) {\n            try {\n                handleEvent( source.getType(),\n                             source.getState(),\n                             source.getPath() );\n            } catch (std::exception &e) {\n                LOG_ERROR( LOG, \n                           \"Unable to process event (type: %d, state: %d, \"\n                                   \"path: %s), because of exception: %s\",\n                           source.getType(),\n                           source.getState(),\n                           source.getPath().c_str(),\n                           e.what() );\n            }\n        }\n    }\n}\n\nvoid \nZooKeeperAdapter::registerContext(WatchableMethod method,\n                                  const string &path,\n                                  ZKEventListener *listener,\n                                  ContextType context)\n{\n    TRACE( LOG, \"registerContext\" );\n\n    m_zkContexts[method][path][listener] = context;\n}\n\nZooKeeperAdapter::Listener2Context\nZooKeeperAdapter::findAndRemoveListenerContext(WatchableMethod method,\n                                               const string &path)\n{\n    TRACE( LOG, \"findAndRemoveListenerContext\" );\n\n    Listener2Context listeners;\n    Path2Listener2Context::iterator elem = m_zkContexts[method].find( path );\n    if (elem != m_zkContexts[method].end()) {\n        listeners = elem->second;\n        m_zkContexts[method].erase( elem );\n    } \n    return listeners;\n}\n\nvoid \nZooKeeperAdapter::setState(AdapterState newState)\n{\n    TRACE( LOG, \"setState\" );    \n    if (newState != m_state) {\n        LOG_INFO( LOG, \"Adapter state transition: %d -> %d\", m_state, newState );\n        m_state = newState;\n        m_stateLock.notify();\n    } else {\n        LOG_TRACE( LOG, \"New state same as the current: %d\", newState );\n    }\n}\n\n\n//TODO move this code to verifyConnection so reconnect()\n//is called from one place only\nvoid\nZooKeeperAdapter::waitUntilConnected() \n  throw(ZooKeeperException)\n{\n    TRACE( LOG, \"waitUntilConnected\" );    \n    long long int timeout = getRemainingConnectTimeout();\n    LOG_INFO( LOG,\n              \"Waiting up to %lld ms until a connection to ZK is established\",\n              timeout );\n    bool connected;\n    if (timeout > 0) {\n        long long int toWait = timeout;\n        while (m_state != AS_CONNECTED && toWait > 0) {\n            //check if session expired and reconnect if so\n            if (m_state == AS_SESSION_EXPIRED) {\n                LOG_INFO( LOG,\n                        \"Reconnecting because the current session has expired\" );\n                reconnect();\n            }\n            struct timeval now;\n            gettimeofday( &now, NULL );\n            int64_t milliSecs = -(now.tv_sec * 1000LL + now.tv_usec / 1000);\n            LOG_TRACE( LOG, \"About to wait %lld ms\", toWait );\n            m_stateLock.wait( toWait );\n            gettimeofday( &now, NULL );\n            milliSecs += now.tv_sec * 1000LL + now.tv_usec / 1000;\n            toWait -= milliSecs;\n        }\n        waitedForConnect( timeout - toWait );\n        LOG_INFO( LOG, \"Waited %lld ms\", timeout - toWait );\n    }\n    connected = (m_state == AS_CONNECTED);\n    if (!connected) {\n        if (timeout > 0) {\n            LOG_WARN( LOG, \"Timed out while waiting for connection to ZK\" );\n            throw ZooKeeperException(\"Timed out while waiting for \"\n                                    \"connection to ZK\");\n        } else {\n            LOG_ERROR( LOG, \"Global timeout expired and still not connected to ZK\" );\n            throw ZooKeeperException(\"Global timeout expired and still not \"\n                                     \"connected to ZK\");\n        }\n    }\n    LOG_INFO( LOG, \"Connected!\" );\n}\n\nvoid\nZooKeeperAdapter::verifyConnection() throw(ZooKeeperException)\n{\n    TRACE( LOG, \"verifyConnection\" );\n\n    m_stateLock.lock();\n    try {\n        if (m_state == AS_DISCONNECTED) {\n            throw ZooKeeperException(\"Disconnected from ZK. \" \\\n                \"Please use reconnect() before attempting to use any ZK API\");\n        } else if (m_state != AS_CONNECTED) {\n            LOG_TRACE( LOG, \"Checking if need to reconnect...\" );\n            //we are not connected, so check if connection in progress...\n            if (m_state != AS_CONNECTING) {\n                LOG_TRACE( LOG, \n                           \"yes. Checking if allowed to auto-reconnect...\" );\n                //...not in progres, so check if we can reconnect\n                if (!m_zkConfig.getAutoReconnect()) {\n                    //...too bad, disallowed :(\n                    LOG_TRACE( LOG, \"no. Sorry.\" );\n                    throw ZooKeeperException(\"ZK connection is down and \"\n                                             \"auto-reconnect is not allowed\");\n                } else {\n                    LOG_TRACE( LOG, \"...yes. About to reconnect\" );\n                }\n                //...we are good to retry the connection\n                reconnect();\n            } else {\n                LOG_TRACE( LOG, \"...no, already in CONNECTING state\" );\n            }               \n            //wait until the connection is established\n            waitUntilConnected(); \n        }\n    } catch (ZooKeeperException &e) {\n        m_stateLock.unlock();\n        throw;\n    }\n    m_stateLock.unlock();\n}\n\nbool\nZooKeeperAdapter::createNode(const string &path, \n                             const string &value, \n                             int flags, \n                             bool createAncestors,\n                             string &returnPath) \n    throw(ZooKeeperException) \n{\n    TRACE( LOG, \"createNode (internal)\" );\n    validatePath( path );\n    \n    const int MAX_PATH_LENGTH = 1024;\n    char realPath[MAX_PATH_LENGTH];\n    realPath[0] = 0;\n    \n    int rc;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        rc = zoo_create( mp_zkHandle, \n                         path.c_str(), \n                         value.c_str(),\n                         value.length(),\n                         &ZOO_OPEN_ACL_UNSAFE,\n                         flags,\n                         realPath,\n                         MAX_PATH_LENGTH );\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        if (rc == ZNODEEXISTS) {\n            //the node already exists\n            LOG_WARN( LOG, \"Error %d for %s\", rc, path.c_str() );\n            return false;\n        } else if (rc == ZNONODE && createAncestors) {\n            LOG_WARN( LOG, \"Error %d for %s\", rc, path.c_str() );\n            //one of the ancestors doesn't exist so lets start from the root \n            //and make sure the whole path exists, creating missing nodes if\n            //necessary\n            for (string::size_type pos = 1; pos != string::npos; ) {\n                pos = path.find( \"/\", pos );\n                if (pos != string::npos) {\n                    try {\n                        createNode( path.substr( 0, pos ), \"\", 0, true );\n                    } catch (ZooKeeperException &e) {\n                        throw ZooKeeperException( string(\"Unable to create \"\n                                                         \"node \") + \n                                                  path, \n                                                  rc );\n                    }\n                    pos++;\n                } else {\n                    //no more path components\n                    return createNode( path, value, flags, false, returnPath );\n                }\n            }\n        }\n        LOG_ERROR( LOG,\"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException( string(\"Unable to create node \") +\n                                  path,\n                                  rc );\n    } else {\n        LOG_INFO( LOG, \"%s has been created\", realPath );\n        returnPath = string( realPath );\n        return true;\n    }\n}\n\nbool\nZooKeeperAdapter::createNode(const string &path,\n                             const string &value,\n                             int flags,\n                             bool createAncestors) \n        throw(ZooKeeperException) \n{\n    TRACE( LOG, \"createNode\" );\n\n    string createdPath;\n    return createNode( path, value, flags, createAncestors, createdPath );\n}\n\nint64_t\nZooKeeperAdapter::createSequence(const string &path,\n                                 const string &value,\n                                 int flags,\n                                 bool createAncestors) \n    throw(ZooKeeperException)\n{\n    TRACE( LOG, \"createSequence\" );\n\n    string createdPath;    \n    bool result = createNode( path,\n                              value,\n                              flags | ZOO_SEQUENCE,\n                              createAncestors,\n                              createdPath );\n    if (!result) {\n        return -1;\n    } else {\n        //extract sequence number from the returned path\n        if (createdPath.find( path ) != 0) {\n            throw ZooKeeperException( string(\"Expecting returned path '\") +\n                                      createdPath + \n                                      \"' to start with '\" +\n                                      path +\n                                      \"'\" );\n        }\n        string seqSuffix =\n            createdPath.substr( path.length(), \n                                createdPath.length() - path.length() );\n        char *ptr = NULL;\n        int64_t seq = strtol( seqSuffix.c_str(), &ptr, 10 );\n        if (ptr != NULL && *ptr != '\\0') {\n            throw ZooKeeperException( string(\"Expecting a number but got \") +\n                                      seqSuffix );\n        }\n        return seq;\n    }\n}\n\nbool\nZooKeeperAdapter::deleteNode(const string &path,\n                             bool recursive,\n                             int version)\n    throw(ZooKeeperException)\n{\n    TRACE( LOG, \"deleteNode\" );\n\n    validatePath( path );\n        \n    int rc;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        rc = zoo_delete( mp_zkHandle, path.c_str(), version );\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        if (rc == ZNONODE) {\n            LOG_WARN( LOG, \"Error %d for %s\", rc, path.c_str() );\n            return false;\n        }\n        if (rc == ZNOTEMPTY && recursive) {\n            LOG_WARN( LOG, \"Error %d for %s\", rc, path.c_str() );\n            //get all children and delete them recursively...\n            vector<string> nodeList;\n            getNodeChildren( nodeList, path, NULL );\n            for (vector<string>::const_iterator i = nodeList.begin();\n                 i != nodeList.end();\n                 ++i) {\n                deleteNode( *i, true );\n            }\n            //...and finally attempt to delete the node again\n            return deleteNode( path, false ); \n        }\n        LOG_ERROR( LOG, \"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException( string(\"Unable to delete node \") + path,\n                                  rc );\n    } else {\n        LOG_INFO( LOG, \"%s has been deleted\", path.c_str() );\n        return true;\n    }\n}\n\nbool\nZooKeeperAdapter::nodeExists(const string &path,\n                             ZKEventListener *listener,\n                             void *context, Stat *stat)\n    throw(ZooKeeperException)\n{\n    TRACE( LOG, \"nodeExists\" );\n\n    validatePath( path );\n\n    struct Stat tmpStat;\n    if (stat == NULL) {\n        stat = &tmpStat;\n    }\n    memset( stat, 0, sizeof(Stat) );\n\n    int rc;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        if (context != NULL) {    \n            m_zkContextsMutex.Acquire();\n            rc = zoo_exists( mp_zkHandle,\n                             path.c_str(),\n                             (listener != NULL ? 1 : 0),\n                             stat );\n            if (rc == ZOK || rc == ZNONODE) {\n                registerContext( NODE_EXISTS, path, listener, context );\n            }\n            m_zkContextsMutex.Release();\n        } else {\n            rc = zoo_exists( mp_zkHandle,\n                             path.c_str(),\n                             (listener != NULL ? 1 : 0),\n                             stat );\n        }\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        if (rc == ZNONODE) {\n            LOG_TRACE( LOG, \"Node %s does not exist\", path.c_str() );\n            return false;\n        }\n        LOG_ERROR( LOG, \"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException(\n                 string(\"Unable to check existence of node \") + path,\n                 rc );\n    } else {\n        return true;        \n    }\n}\n\nvoid\nZooKeeperAdapter::getNodeChildren(vector<string> &nodeList,\n                                  const string &path, \n                                  ZKEventListener *listener,\n                                  void *context)\n    throw (ZooKeeperException)\n{\n    TRACE( LOG, \"getNodeChildren\" );\n\n    validatePath( path );\n    \n    String_vector children;\n    memset( &children, 0, sizeof(children) );\n\n    int rc;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        if (context != NULL) {\n            m_zkContextsMutex.Acquire();\n            rc = zoo_get_children( mp_zkHandle,\n                                   path.c_str(), \n                                   (listener != NULL ? 1 : 0), \n                                   &children );\n            if (rc == ZOK) {\n                registerContext( GET_NODE_CHILDREN, path, listener, context );\n            }\n            m_zkContextsMutex.Release();\n        } else {\n            rc = zoo_get_children( mp_zkHandle,\n                                   path.c_str(), \n                                   (listener != NULL ? 1 : 0),\n                                   &children );\n        }\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        LOG_ERROR( LOG, \"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException( string(\"Unable to get children of node \") +\n                                  path, \n                                  rc );\n    } else {\n        for (int i = 0; i < children.count; ++i) {\n            //convert each child's path from relative to absolute \n            string absPath(path);\n            if (path != \"/\") {\n                absPath.append( \"/\" );\n            } \n            absPath.append( children.data[i] ); \n            nodeList.push_back( absPath );\n        }\n        //make sure the order is always deterministic\n        sort( nodeList.begin(), nodeList.end() );\n    }\n}\n\nstring\nZooKeeperAdapter::getNodeData(const string &path,\n                              ZKEventListener *listener,\n                              void *context, Stat *stat)\n    throw(ZooKeeperException)\n{\n    TRACE( LOG, \"getNodeData\" );\n\n    validatePath( path );\n   \n    const int MAX_DATA_LENGTH = 128 * 1024;\n    char buffer[MAX_DATA_LENGTH];\n    memset( buffer, 0, MAX_DATA_LENGTH );\n    struct Stat tmpStat;\n    if (stat == NULL) {\n        stat = &tmpStat;\n    }\n    memset( stat, 0, sizeof(Stat) );\n    \n    int rc;\n    int len;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        len = MAX_DATA_LENGTH - 1;\n        if (context != NULL) {\n            m_zkContextsMutex.Acquire();\n            rc = zoo_get( mp_zkHandle, \n                          path.c_str(),\n                          (listener != NULL ? 1 : 0),\n                          buffer, &len, stat );\n            if (rc == ZOK) {\n                registerContext( GET_NODE_DATA, path, listener, context );\n            }\n            m_zkContextsMutex.Release();\n        } else {\n            rc = zoo_get( mp_zkHandle,\n                          path.c_str(),\n                          (listener != NULL ? 1 : 0),\n                          buffer, &len, stat );\n        }\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        LOG_ERROR( LOG, \"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException( \n            string(\"Unable to get data of node \") + path, rc \n        );\n    } else {\n        if (len == -1) {\n            len = 0;\n        }\n        return string( buffer, len );\n    }\n}\n\nvoid\nZooKeeperAdapter::setNodeData(const string &path,\n                              const string &value,\n                              int version)\n    throw(ZooKeeperException)\n{\n    TRACE( LOG, \"setNodeData\" );\n\n    validatePath( path );\n\n    int rc;\n    RetryHandler rh(m_zkConfig);\n    do {\n        verifyConnection();\n        rc = zoo_set( mp_zkHandle,\n                      path.c_str(),\n                      value.c_str(),\n                      value.length(),\n                      version);\n    } while (rc != ZOK && rh.handleRC(rc));\n    if (rc != ZOK) {\n        LOG_ERROR( LOG, \"Error %d for %s\", rc, path.c_str() );\n        throw ZooKeeperException( string(\"Unable to set data for node \") +\n                                  path,\n                                  rc );\n    }\n}\n\n}   /* end of 'namespace zk' */\n\n"
  },
  {
    "path": "src/contrib/zkfuse/src/zkadapter.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __ZKADAPTER_H__\n#define __ZKADAPTER_H__\n\n#include <string>\n#include <vector>\n#include <map>\n\nextern \"C\" {\n#include \"zookeeper.h\"\n}\n\n#include \"log.h\"\n#include \"mutex.h\"\n#include \"thread.h\"\n#include \"blockingqueue.h\"\n#include \"event.h\"\n\nusing namespace std;\nusing namespace zkfuse;\n\nnamespace zk {\n    \n/**\n * \\brief A cluster related exception.\n */\nclass ZooKeeperException :\n    public std::exception\n{\n    public:\n        \n        /**\n         * \\brief Constructor.\n         * \n         * @param msg the detailed message associated with this exception\n         */\n        ZooKeeperException(const string &msg) : \n            m_message(msg), m_zkErrorCode(0) \n        {}\n\n        /**\n         * \\brief Constructor.\n         * \n         * @param msg the detailed message associated with this exception\n         * @param errorCode the ZK error code associated with this exception\n         */\n        ZooKeeperException(const string &msg, int errorCode) : \n            m_zkErrorCode(errorCode) \n        {\n            char tmp[100];\n            sprintf( tmp, \" (ZK error code: %d)\", errorCode );\n            m_message = msg + tmp;\n        }\n                \n        /**\n         * \\brief Destructor.\n         */\n        ~ZooKeeperException() throw() {}\n        \n        /**\n         * \\brief Returns detailed description of the exception.\n         */\n        const char *what() const throw() {\n            return m_message.c_str();\n        }\n        \n        /**\n         * \\brief Returns the ZK error code.\n         */\n        int getZKErrorCode() const {\n            return m_zkErrorCode;\n        }\n\n    private:\n        \n        /**\n         * The detailed message associated with this exception.\n         */\n        string m_message;\n        \n        /**\n         * The optional error code received from ZK.\n         */\n        int m_zkErrorCode;\n        \n};\n    \n/**\n * \\brief This class encapsulates configuration of a ZK client.\n */\nclass ZooKeeperConfig\n{\n    public:\n        \n        /**\n         * \\brief Constructor.\n         * \n         * @param hosts the comma separated list of host and port pairs of ZK nodes\n         * @param leaseTimeout the lease timeout (heartbeat)\n         * @param autoReconnect whether to allow for auto-reconnect\n         * @param connectTimeout the connect timeout, in milliseconds;\n         */\n        ZooKeeperConfig(const string &hosts, \n                        int leaseTimeout, \n                        bool autoReconnect = true, \n                        long long int connectTimeout = 15000) :\n            m_hosts(hosts), m_leaseTimeout(leaseTimeout), \n                  m_autoReconnect(autoReconnect), m_connectTimeout(connectTimeout) {}\n        \n        /**\n         * \\brief Returns the list of ZK hosts to connect to.\n         */\n        string getHosts() const { return m_hosts; }\n        \n        /**\n         * \\brief Returns the lease timeout.\n         */\n        int getLeaseTimeout() const { return m_leaseTimeout; }\n        \n        /**\n         * \\brief Returns whether {@link ZooKeeperAdapter} should attempt \n         * \\brief to automatically reconnect in case of a connection failure.\n         */\n        bool getAutoReconnect() const { return m_autoReconnect; }\n\n        /**\n         * \\brief Gets the connect timeout.\n         * \n         * @return the connect timeout\n         */\n        long long int getConnectTimeout() const { return m_connectTimeout; }\n                  \n    private:\n        \n        /**\n         * The host addresses of ZK nodes.\n         */\n        const string m_hosts;\n\n        /**\n         * The ZK lease timeout.\n         */\n        const int m_leaseTimeout;\n        \n        /**\n         * True if this adapater should attempt to autoreconnect in case \n         * the current session has been dropped.\n         */\n        const bool m_autoReconnect;\n        \n        /**\n         * How long to wait, in milliseconds, before a connection \n         * is established to ZK.\n         */\n        const long long int m_connectTimeout;\n        \n};\n\n/**\n * \\brief A data value object representing a watcher event received from the ZK.\n */\nclass ZKWatcherEvent\n{\n    public:\n\n        /**\n         * \\brief The type representing the user's context.\n         */\n        typedef void *ContextType;\n        \n        /**\n         * \\brief Constructor.\n         * \n         * @param type the type of this event\n         * @param state the state of this event\n         * @param path the corresponding path, may be empty for some event types\n         * @param context the user specified context; possibly NULL\n         */\n        ZKWatcherEvent() : \n            m_type(-1), m_state(-1), m_path(\"\"), mp_context(NULL) {}\n                        \n        /**\n         * \\brief Constructor.\n         * \n         * @param type the type of this event\n         * @param state the state of this event\n         * @param path the corresponding path, may be empty for some event types\n         * @param context the user specified context; possibly NULL\n         */\n        ZKWatcherEvent(int type, int state, const string &path, \n                       ContextType context = NULL) :\n            m_type(type), m_state(state), m_path(path), mp_context(context) {}\n        \n        int getType() const { return m_type; }\n        int getState() const { return m_state; }\n        string const &getPath() const { return m_path; }\n        ContextType getContext() const { return mp_context; }\n        \n        bool operator==(const ZKWatcherEvent &we) const {\n            return m_type == we.m_type && m_state == we.m_state \n                    && m_path == we.m_path && mp_context == we.mp_context;\n        }\n        \n    private:\n        \n        /**\n         * The type of this event. It can be either ZOO_CREATED_EVENT, ZOO_DELETED_EVENT,\n         * ZOO_CHANGED_EVENT, ZOO_CHILD_EVENT, ZOO_SESSION_EVENT or ZOO_NOTWATCHING_EVENT. \n         * See zookeeper.h for more details.\n         */\n        const int m_type;\n        \n        /**\n         * The state of ZK at the time of sending this event.\n         * It can be either ZOO_CONNECTING_STATE, ZOO_ASSOCIATING_STATE, \n         * ZOO_CONNECTED_STATE, ZOO_EXPIRED_SESSION_STATE or AUTH_FAILED_STATE.\n         * See {@file zookeeper.h} for more details.\n         */\n        const int m_state;\n        \n        /**\n         * The corresponding path of the node in subject. It may be empty\n         * for some event types.\n         */\n        const string m_path;\n        \n        /**\n         * The pointer to the user specified context, possibly NULL.\n         */\n        ContextType mp_context;\n        \n};\n\n/**\n * \\brief The type definition of ZK event source.\n */\ntypedef EventSource<ZKWatcherEvent> ZKEventSource;\n\n/**\n * \\brief The type definition of ZK event listener.\n */\ntypedef EventListener<ZKWatcherEvent> ZKEventListener;\n           \n/**\n * \\brief This is a wrapper around ZK C synchrounous API.\n */\nclass ZooKeeperAdapter\n    : public ZKEventSource\n{\n    public:\n        /**\n         * \\brief The global function that handles all ZK asynchronous notifications.\n         */\n        friend void zkWatcher(zhandle_t *, int, int, const char *, void *watcherCtx);\n        \n        /**\n         * \\brief The type representing the user's context.\n         */\n        typedef void *ContextType;\n        \n        /**\n         * \\brief The map type of ZK event listener to user specified context mapping.\n         */\n        typedef map<ZKEventListener *, ContextType> Listener2Context;\n        \n        /**\n         * \\brief The map type of ZK path's to listener's contexts.\n         */\n        typedef map<string, Listener2Context> Path2Listener2Context;\n                  \n        /**\n         * \\brief All possible states of this client, in respect to \n         * \\brief connection to the ZK server.\n         */\n        enum AdapterState {\n            //mp_zkHandle is NULL\n            AS_DISCONNECTED = 0,\n            //mp_zkHandle is valid but this client is reconnecting\n            AS_CONNECTING,\n            //mp_zkHandle is valid and this client is connected\n            AS_CONNECTED,\n            //mp_zkHandle is valid, however no more calls can be made to ZK API\n            AS_SESSION_EXPIRED\n        };\n                \n        /**\n         * \\brief Constructor.\n         * Attempts to create a ZK adapter, optionally connecting\n         * to the ZK. Note, that if the connection is to be established\n         * and the given listener is NULL, some events may be lost, \n         * as they may arrive asynchronously before this method finishes.\n         * \n         * @param config the ZK configuration\n         * @param listener the event listener to be used for listening \n         *                 on incoming ZK events;\n         *                 if <code>NULL</code> not used\n         * @param establishConnection whether to establish connection to the ZK\n         * \n         * @throw ZooKeeperException if cannot establish connection to the given ZK\n         */\n        ZooKeeperAdapter(ZooKeeperConfig config, \n                         ZKEventListener *listener = NULL,\n                         bool establishConnection = false) \n            throw(ZooKeeperException);\n\n        /**\n         * \\brief Destructor.\n         */\n        ~ZooKeeperAdapter(); \n                  \n        /**\n         * \\brief Returns the current config.\n         */\n        const ZooKeeperConfig &getZooKeeperConfig() const {\n            return m_zkConfig;                      \n        }\n\n        /**\n         * \\brief Restablishes connection to the ZK. \n         * If this adapter is already connected, the current connection \n         * will be dropped and a new connection will be established.\n         * \n         * @throw ZooKeeperException if cannot establish connection to the ZK\n         */\n        void reconnect() throw(ZooKeeperException);\n        \n        /**\n         * \\brief Disconnects from the ZK and unregisters {@link #mp_zkHandle}.\n         */\n        void disconnect();\n        \n        /**\n         * \\brief Creates a new node identified by the given path. \n         * This method will optionally attempt to create all missing ancestors.\n         * \n         * @param path the absolute path name of the node to be created\n         * @param value the initial value to be associated with the node\n         * @param flags the ZK flags of the node to be created\n         * @param createAncestors if true and there are some missing ancestor nodes, \n         *        this method will attempt to create them\n         * \n         * @return true if the node has been successfully created; false otherwise\n         * @throw ZooKeeperException if the operation has failed\n         */ \n        bool createNode(const string &path, \n                        const string &value = \"\", \n                        int flags = 0, \n                        bool createAncestors = true) \n            throw(ZooKeeperException);\n                  \n        /**\n         * \\brief Creates a new sequence node using the give path as the prefix.\n         * This method will optionally attempt to create all missing ancestors.\n         * \n         * @param path the absolute path name of the node to be created; \n         * @param value the initial value to be associated with the node\n         * @param flags the ZK flags of the sequence node to be created \n         *              (in addition to SEQUENCE)\n         * @param createAncestors if true and there are some missing ancestor \n         *                        nodes, this method will attempt to create them\n         * \n         * @return the sequence number associate with newly created node,\n         *         or -1 if it couldn't be created\n         * @throw ZooKeeperException if the operation has failed\n         */ \n        int64_t createSequence(const string &path, \n                               const string &value = \"\", \n                               int flags = 0, \n                               bool createAncestors = true) \n            throw(ZooKeeperException);\n        \n        /**\n         * \\brief Deletes a node identified by the given path.\n         * \n         * @param path the absolute path name of the node to be deleted\n         * @param recursive if true this method will attempt to remove \n         *                  all children of the given node if any exist\n         * @param version the expected version of the node. The function will \n         *                fail if the actual version of the node does not match \n         *                the expected version\n         * \n         * @return true if the node has been deleted; false otherwise\n         * @throw ZooKeeperException if the operation has failed\n         */\n        bool deleteNode(const string &path, bool recursive = false, int version = -1) \n            throw(ZooKeeperException);\n        \n        /**\n         * \\brief Checks whether the given node exists or not.\n         * \n         * @param path the absolute path name of the node to be checked\n         * @param listener the listener for ZK watcher events; \n         *                 passing non <code>NULL</code> effectively establishes\n         *                 a ZK watch on the given node\n         * @param context the user specified context that is to be passed\n         *                in a corresponding {@link ZKWatcherEvent} at later time; \n         *                not used if <code>listener</code> is <code>NULL</code>\n         * @param stat the optional node statistics to be filled in by ZK\n         * \n         * @return true if the given node exists; false otherwise\n         * @throw ZooKeeperException if the operation has failed\n         */\n        bool nodeExists(const string &path, \n                        ZKEventListener *listener = NULL, \n                        void *context = NULL,\n                        Stat *stat = NULL) \n            throw(ZooKeeperException);\n\n        /**\n         * \\brief Retrieves list of all children of the given node.\n         * \n         * @param path the absolute path name of the node for which to get children\n         * @param listener the listener for ZK watcher events; \n         *                 passing non <code>NULL</code> effectively establishes\n         *                 a ZK watch on the given node\n         * @param context the user specified context that is to be passed\n         *                in a corresponding {@link ZKWatcherEvent} at later time; \n         *                not used if <code>listener</code> is <code>NULL</code>\n         * \n         * @return the list of absolute paths of child nodes, possibly empty\n         * @throw ZooKeeperException if the operation has failed\n         */\n        void getNodeChildren(vector<string> &children,\n                             const string &path, \n                             ZKEventListener *listener = NULL, \n                             void *context = NULL) \n            throw(ZooKeeperException);\n                \n        /**\n         * \\brief Gets the given node's data.\n         * \n         * @param path the absolute path name of the node to get data from\n         * @param listener the listener for ZK watcher events; \n         *                 passing non <code>NULL</code> effectively establishes\n         *                 a ZK watch on the given node\n         * @param context the user specified context that is to be passed\n         *                in a corresponding {@link ZKWatcherEvent} at later time; \n         *                not used if <code>listener</code> is <code>NULL</code>\n         * @param stat the optional node statistics to be filled in by ZK\n         * \n         * @return the node's data\n         * @throw ZooKeeperException if the operation has failed\n         */\n        string getNodeData(const string &path, \n                           ZKEventListener *listener = NULL, \n                           void *context = NULL,\n                           Stat *stat = NULL) \n            throw(ZooKeeperException);\n        \n        /**\n         * \\brief Sets the given node's data.\n         * \n         * @param path the absolute path name of the node to get data from\n         * @param value the node's data to be set\n         * @param version the expected version of the node. The function will \n         *                fail if the actual version of the node does not match \n         *                the expected version\n         * \n         * @throw ZooKeeperException if the operation has failed\n         */\n        void setNodeData(const string &path, const string &value, int version = -1) \n            throw(ZooKeeperException);\n        \n        /**\n         * \\brief Validates the given path to a node in ZK.\n         * \n         * @param the path to be validated\n         * \n         * @throw ZooKeeperException if the given path is not valid\n         *        (for instance it doesn't start with \"/\")\n         */\n        static void validatePath(const string &path) throw(ZooKeeperException);\n\n        /**\n         * Returns the current state of this adapter.\n         * \n         * @return the current state of this adapter\n         * @see AdapterState\n         */\n        AdapterState getState() const {\n            return m_state;\n        }          \n        \n    private:\n        \n        /**\n         * This enum defines methods from this class than can trigger an event.\n         */\n        enum WatchableMethod {\n            NODE_EXISTS = 0,\n            GET_NODE_CHILDREN,\n            GET_NODE_DATA\n        };\n                \n        /**\n         * \\brief Creates a new node identified by the given path. \n         * This method is used internally to implement {@link createNode(...)} \n         * and {@link createSequence(...)}. On success, this method will set\n         * <code>createdPath</code>.\n         * \n         * @param path the absolute path name of the node to be created\n         * @param value the initial value to be associated with the node\n         * @param flags the ZK flags of the node to be created\n         * @param createAncestors if true and there are some missing ancestor nodes, \n         *        this method will attempt to create them\n         * @param createdPath the actual path of the node that has been created; \n         *        useful for sequences\n         * \n         * @return true if the node has been successfully created; false otherwise\n         * @throw ZooKeeperException if the operation has failed\n         */ \n        bool createNode(const string &path, \n                        const string &value, \n                        int flags, \n                        bool createAncestors,\n                        string &createdPath) \n            throw(ZooKeeperException);\n        \n        /**\n         * Handles an asynchronous event received from the ZK.\n         */\n        void handleEvent(int type, int state, const string &path);\n        \n        /**\n         * Handles an asynchronous event received from the ZK.\n         * This method iterates over all listeners and passes the event \n         * to each of them.\n         */\n        void handleEvent(int type, int state, const string &path, \n                         const Listener2Context &listeners);        \n        \n        /**\n         * \\brief Enqueues the given event in {@link #m_events} queue.\n         */\n        void enqueueEvent(int type, int state, const string &path);\n        \n        /**\n         * \\brief Processes all ZK adapter events in a loop.\n         */\n        void processEvents();\n\n        /**\n         * \\brief Processes all user events in a loop.\n         */\n        void processUserEvents();\n\n        /**\n         * \\brief Registers the given context in the {@link #m_zkContexts} \n         * \\brief contexts map.\n         * \n         * @param method the method where the given path is being used\n         * @param path the path of interest\n         * @param listener the event listener to call back later on\n         * @param context the user specified context to be passed back to user\n         */\n        void registerContext(WatchableMethod method, const string &path, \n                             ZKEventListener *listener, ContextType context);\n        \n        /**\n         * \\brief Attempts to find a listener to context map in the contexts' \n         * \\brief map, based on the specified criteria.\n         * If the context is found, it will be removed the udnerlying map.\n         * \n         * @param method the method type identify Listener2Context map\n         * @param path the path to be used to search in the Listener2Context map\n         * \n         * @return the context map associated with the given method and path, \n         *         or empty map if not found\n         */\n        Listener2Context findAndRemoveListenerContext(WatchableMethod method, \n                                                      const string &path);\n\n        /**\n         * Sets the new state in case it's different then the current one.\n         * This method assumes that {@link #m_stateLock} has been already locked.\n         * \n         * @param newState the new state to be set\n         */\n        void setState(AdapterState newState); \n        \n        /**\n         * Waits until this client gets connected. The total wait time \n         * is given by {@link getRemainingConnectTimeout()}.\n         * If a timeout elapses, this method will throw an exception.\n         * \n         * @throw ZooKeeperException if unable to connect within the given timeout\n         */\n        void waitUntilConnected() \n            throw(ZooKeeperException);\n                                      \n        /**\n         * Verifies whether the connection is established,\n         * optionally auto reconnecting.\n         * \n         * @throw ZooKeeperConnection if this client is disconnected\n         *        and auto-reconnect failed or was not allowed\n         */\n        void verifyConnection() throw(ZooKeeperException);\n\n        /**\n         * Returns the remaining connect timeout. The timeout resets\n         * to {@link #m_connectTimeout} on a successfull connection to the ZK.\n         * \n         * @return the remaining connect timeout, in milliseconds\n         */\n        long long int getRemainingConnectTimeout() { \n            return m_remainingConnectTimeout; \n        }\n        \n        /**\n         * Resets the remaining connect timeout to {@link #m_connectTimeout}.\n         */\n        void resetRemainingConnectTimeout() { \n            m_remainingConnectTimeout = m_zkConfig.getConnectTimeout(); \n        }\n        \n        /**\n         * Updates the remaining connect timeout to reflect the given wait time.\n         * \n         * @param time the time for how long waited so far on connect to succeed\n         */\n        void waitedForConnect(long long time) { \n            m_remainingConnectTimeout -= time; \n        }\n                \n    private:\n        \n        /**\n         * The mutex use to protect {@link #m_zkContexts}.\n         */\n        zkfuse::Mutex m_zkContextsMutex;\n        \n        /**\n         * The map of registered ZK paths that are being watched.\n         * Each entry maps a function type to another map of registered contexts.\n         * \n         * @see WatchableMethod\n         */\n        map<int, Path2Listener2Context> m_zkContexts;\n        \n        /**\n         * The current ZK configuration.\n         */\n        const ZooKeeperConfig m_zkConfig;\n\n        /**\n         * The current ZK session.\n         */\n        zhandle_t *mp_zkHandle;\n        \n        /**\n         * The blocking queue of all events waiting to be processed by ZK adapter.\n         */\n        BlockingQueue<ZKWatcherEvent> m_events;\n        \n        /**\n         * The blocking queue of all events waiting to be processed by users\n         * of ZK adapter.\n         */\n        BlockingQueue<ZKWatcherEvent> m_userEvents;\n        \n        /**\n         * The thread that dispatches all events from {@link #m_events} queue.\n         */\n        CXXThread<ZooKeeperAdapter> m_eventDispatcher;\n\n        /**\n         * The thread that dispatches all events from {@link #m_userEvents} queue.\n         */\n        CXXThread<ZooKeeperAdapter> m_userEventDispatcher;\n                \n        /**\n         * Whether {@link #m_eventDispatcher} is terminating.\n         */\n        volatile bool m_terminating;\n        \n        /**\n         * Whether this adapter is connected to the ZK.\n         */\n        volatile bool m_connected;\n        \n        /**\n         * The state of this adapter.\n         */\n        AdapterState m_state;\n        \n        /**\n         * The lock used to synchronize access to {@link #m_state}.\n         */\n        Lock m_stateLock;\n\n        /**\n         * How much time left for the connect to succeed, in milliseconds.\n         */\n        long long int m_remainingConnectTimeout;\n                \n};\n        \n}   /* end of 'namespace zk' */\n\n#endif /* __ZKADAPTER_H__ */\n"
  },
  {
    "path": "src/contrib/zkfuse/src/zkfuse.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#define FUSE_USE_VERSION 26\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#endif\n\n#undef _GNU_SOURCE\n#define _GNU_SOURCE\n\nextern \"C\" {\n#include <fuse.h>\n#include <ulockmgr.h>\n}\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <dirent.h>\n#include <errno.h>\n#include <sys/time.h>\n#ifdef HAVE_SETXATTR\n#include <sys/xattr.h>\n#endif\n\n#include <getopt.h>\n\n#include <iostream>\n#include <sstream>\n#include <map>\n#include <string>\n#include <boost/utility.hpp>\n#include <boost/weak_ptr.hpp>\n\n#include \"log.h\"\n#include \"mutex.h\"\n#include \"zkadapter.h\"\n\n#define ZOOKEEPER_ROOT_CHILDREN_WATCH_BUG\n\n/**\n   Typedef for ZooKeeperAdapter::Data.\n*/\ntypedef std::string Data;\n/**\n   Typedef for ZooKeeperAdapter::NodeNames.\n*/\ntypedef vector<std::string> NodeNames;\n\n#define MAX_DATA_SIZE 1024;\n\nDEFINE_LOGGER(LOG, \"zkfuse\");\n\ninline \nuint64_t millisecsToSecs(uint64_t millisecs)\n{\n    return millisecs / 1000;\n}\ninline\nuint64_t secsToMillisecs(uint64_t secs)\n{\n    return secs * 1000;\n}\ninline\nuint64_t nanosecsToMillisecs(uint64_t nanosecs)\n{\n    return nanosecs / 1000000;\n}\ninline\nuint64_t timespecToMillisecs(const struct timespec & ts)\n{ \n    return secsToMillisecs(ts.tv_sec) + nanosecsToMillisecs(ts.tv_nsec);\n}\n\ntypedef boost::shared_ptr<ZooKeeperAdapter> ZooKeeperAdapterSharedPtr;\n\n/**\n * ZkFuseCommon - holds immutable configuration objects.\n *\n * No locks are required to access these objects.\n * A ZkFuseCommon instance is considered to be a data object and may be copied.\n */\nclass ZkFuseCommon \n{\n  private:\n    /**\n      References the ZooKeeperAdapter instance to be used.\n     */\n    ZooKeeperAdapterSharedPtr _zkAdapter;\n    /** \n      Path to the ZooKeeper root node.\n     */\n    std::string _rootPathName;\n    /**\n      Name used to access data \"file\" when the ZK node has \n      children.\n     */\n    std::string _dataFileName;\n    /**\n      Suffix added to path components to force interpretation of \n      path components as directory. This is usually only required\n      for the last component. For example, ZkFuse may consider\n      a leaf node a regular file, e.g. /a/b/c/leaf. The suffix\n      can be used to create child under this node, e.g.\n      mkdir /a/b/c/leaf{forceDirSuffix}/new_leaf.\n     */\n    std::string _forceDirSuffix;\n    /**\n      Prefix common to all metadata nodes created by ZkFuse.\n     */  \n    std::string _metadataNamePrefix;\n    /**\n      Path component name that identifies a directory metadata node.\n      A directory metadata node is currently empty. It is used by ZkFuse\n      to create a child when mkdir is used. This prevents ZkFuse\n      from interpreting the new child as a regular file.\n     */\n    std::string _dirMetadataName;\n    /**\n      Path component name that identifies a regular file metadata node.\n      A regular metadata node holds metadata required to implement\n      Posix regular file semantics, such as setting mtime.\n     */\n    std::string _regMetadataName;\n    /**\n      Number of not-in-use nodes to cache.\n     */\n    unsigned _cacheSize;\n    /**\n      Assume this userid owns all nodes.\n     */\n    const uid_t _uid;\n    /**\n      Assume this groupid owns all nodes.\n     */\n    const gid_t _gid;\n    /**\n      Blocksize used to calculate number of blocks used for stat.\n     */\n    const unsigned _blkSize;\n\n  public:\n    /**\n      Constructor.\n     */\n    ZkFuseCommon()\n      : _zkAdapter(),\n        _rootPathName(\"/\"),\n        _dataFileName(),\n        _forceDirSuffix(),\n        _metadataNamePrefix(\".zkfuse.\"),\n        _dirMetadataName(_metadataNamePrefix + \"dir\"),\n        _regMetadataName(_metadataNamePrefix + \"file\"),\n        _cacheSize(256),\n        _uid(geteuid()),\n        _gid(getegid()),\n        _blkSize(8192)\n    {\n    }\n    /**\n      Get root path name. Always \"/\".\n      \\see _rootPathName\n     */\n    const std::string & getRootPathName() const\n    {\n        return _rootPathName;\n    }\n    /**\n      Get dataFileName - the name for synthesized files to access\n      ZooKeeper node data.\n      \\see _dataFileName\n     */\n    const std::string & getDataFileName() const\n    {\n        return _dataFileName;\n    }\n    /**\n      Set dataFileName.\n      \\see getDataFileName\n      \\see _dataFileName\n     */\n    void setDataFileName(const std::string & dataFileName)\n    {\n        _dataFileName = dataFileName;\n    }\n    /**\n      Get metadataNamePrefix - the common prefix for all ZkFuse created\n      metadata ZooKeeper nodes.\n      \\see _metadataNamePrefix\n     */\n    const std::string & getMetadataNamePrefix() const\n    {\n        return _metadataNamePrefix;\n    }\n    /**\n      Get forceDirSuffix - the suffix added to a path component to force\n      the path component to be treated like a directory.\n      \\see _forceDirSuffix\n     */\n    const std::string & getForceDirSuffix() const\n    {\n        return _forceDirSuffix;\n    }\n    /**\n      Set forceDirSuffix.\n      \\see getForceDirSuffix\n      \\see _forceDirSuffix\n     */\n    void setForceDirSuffix(const std::string & forceDirSuffix)\n    {\n        _forceDirSuffix = forceDirSuffix;\n    }\n    /**\n      Get dirMetadataName - path component name of all directory \n      metadata ZooKeeper nodes. \n      \\see _dirMetadataname\n     */\n    const std::string & getDirMetadataName() const\n    {\n        return _dirMetadataName;\n    }\n    /**\n      Get regMetadataName - path component name of all regular file \n      metadata ZooKeeper nodes. \n      \\see _regMetadataname\n     */\n    const std::string & getRegMetadataName() const\n    {\n        return _regMetadataName;\n    }\n    /**\n      Get number of not-in-use ZkFuseFile instances to to cache.\n      \\see _cacheSize\n     */\n    unsigned getCacheSize() const\n    {\n        return _cacheSize;\n    }\n    /**\n      Set cache size.\n      \\see getCacheSize\n      \\see _cacheSize\n     */\n    void setCacheSize(unsigned v) \n    {\n        _cacheSize = v;\n    }\n    /** \n      Get userid.\n      \\see _uid\n     */\n    uid_t getUid() const\n    {\n        return _uid;\n    }\n    /**\n      Get groupid.\n      \\see _gid\n     */\n    gid_t getGid() const\n    {\n        return _gid;\n    }\n    /**\n      Get block size.\n      \\see _blkSize\n     */\n    unsigned getBlkSize() const\n    {\n        return _blkSize;\n    }\n    /**\n      Get ZooKeeperAdapter.\n      \\see _zkAdapter.\n     */\n    const ZooKeeperAdapterSharedPtr & getZkAdapter() const\n    {\n        return _zkAdapter;\n    }\n    /**\n      Set ZooKeeperAdapter.\n      \\see _zkAdaptor\n     */\n    void setZkAdapter(const ZooKeeperAdapterSharedPtr & zkAdapter)\n    {\n        _zkAdapter = zkAdapter;\n    }\n};\n\n/**\n  ZkFuseNameType - identifies the type of the ZkFuse path.\n */\nenum ZkFuseNameType {\n    /**\n      ZkFuse path is not syntheiszed. \n      ZkFuse should use its default rules to determine the Posix representation\n      of the path.\n     */\n    ZkFuseNameDefaultType = 0, \n    /**\n      ZkFuse path is synthesized and identifies the data part of a\n      ZooKeeper node, i.e.  Posix regular file semantics is expected.\n     */\n    ZkFuseNameRegType = 1,\n    /**\n      ZkFuse path is synthesized and identifies the chidlren part of a\n      ZooKeeper node, i.e.  Posix directory semantics is expected.\n     */\n    ZkFuseNameDirType = 2\n};\n\nclass ZkFuseFile;\n\ntypedef ZkFuseFile * ZkFuseFilePtr;\n\nclass ZkFuseHandleManagerFactory;\n\n/**\n  ZkFuseHandleManager - keeps track of all the ZkFuseFile instances \n  allocated by a ZkFuseHandleManager instance and provides them\n  with a handle that can be used by FUSE. \n\n  It maps a ZooKeeper path to a handle and a handle to a ZkFuse instance.\n  It also implements the methods that takes path names as arguments, such\n  as open, mknod, rmdir, and rename.\n\n  Memory management\n  - References ZkFuseFile instances using regular pointers\n    Smart pointer is not used because reference counts are needed to\n    determine how many time a node is opened as a regular file or\n    directory. This also avoids circular smart pointer references.\n  - Each ZkFuseFile instance holds a reference to its ZkFuseHandleManager\n    using a boost::shared_ptr. This ensures that the ZkFuseHandleManager\n    instance that has the handle for the ZkFuseFile instance does not\n    get garbage collected while the ZkFuseFile instance exists.\n\n  Concurrency control\n  - Except for the immutable ZkFuseCommon, all other member variables\n    are protected by _mutex.\n  - A method in this class can hold _mutex when it directly or\n    indirectly invokes ZkFuseFile methods. A ZkFuseFile method that holds\n    a ZkFuseFile instance _mutex cannot invoke a ZkFuseHandleManager\n    method that acquires the ZkFuseHandleManager instance's _mutex.\n    Otherwise, this may cause a dead lock.\n  - Methods that with names that begin with \"_\" do not acquire _mutex. \n    They are usually called by public methods that acquire and hold _mutex.\n */\nclass ZkFuseHandleManager : boost::noncopyable\n{\n  private:\n    /**\n      Typedef of handle, which is an int.\n     */\n    typedef int Handle;\n    /**\n      Typedef of std::map used to map path to handle.\n     */\n    typedef std::map<std::string, Handle> Map;\n    /**\n      Typedef of std::vector used to map handle to ZkFuseFile instances.\n     */\n    typedef std::vector<ZkFuseFilePtr> Files;\n    /**\n      Typedef of std::vector used to hold unused handles.\n     */\n    typedef std::vector<Handle> FreeList;\n    /**\n      Typedef of boost::weak_ptr to the ZkFuseHandleManager instance.\n     */\n    typedef boost::weak_ptr<ZkFuseHandleManager> WeakPtr;\n\n    /* Only ZkFuseHandleManagerFactory can create instances of this class */\n    friend class ZkFuseHandleManagerFactory;\n\n    /**\n      Contains common configuration.\n      Immutable so that it can be accessed without locks.\n     */\n    const ZkFuseCommon _common;\n    /**\n      Maps a path name to a Handle.\n     */\n    Map _map;\n    /**\n      Maps a handle to a ZkFuseFile instances.\n      Also holds pointers to all known ZkFuseFile instances.\n      An element may point to an allocated ZkFuseFile instance or be NULL.\n\n      An allocated ZkFuseFile instance may be in one of the following states:\n      - in-use\n        Currently open, i.e. the ZkFuseFile instance's reference count \n        greater than 0.\n      - in-cache\n        Not currently open, i.e. the ZkFuseFile instances's \n        reference count is 0.\n     */\n    Files _files;\n    /**\n      List of free'ed handles.\n     */\n    FreeList _freeList;\n    /**\n      Mutex used to protect this instance.\n     */\n    mutable zkfuse::Mutex _mutex;\n    /**\n      Count of number of in-use entries.\n      It used to calculate number of cached nodes.\n      Number cached nodes is (_files.size() - _numInUse).\n     */\n    unsigned _numInUse;\n    /**\n      WeakPtr to myself.\n     */\n    WeakPtr _thisWeakPtr;\n   \n    /**\n      Obtain a handle for the given path.\n      - If path is not known, then allocate a new handle and increment\n        _numInUse, and set newFile to true. The allocated \n        ZkFuseFile instance's reference count should be 1.\n      - If path is known, increase the corresponding \n        ZkFuseFile instance's reference count.\n\n      \\return the allocated handle.\n      \\param path the path to lookup.\n      \\param newFile indicates whether a new handle has been allocated.\n     */\n    Handle allocate(const std::string & path, bool & newFile);\n\n    /**\n      Constructor.\n\n      \\param common the immutable common configuration.\n      \\param reserve number of elements to pre-allocate for \n                     _files and _freeList.\n     */\n    ZkFuseHandleManager(\n            const ZkFuseCommon & common, \n            const unsigned reserve) \n      : _common(common),\n        _files(), \n        _freeList(), \n        _mutex(),\n        _numInUse(0)\n    {\n        _files.reserve(reserve);\n        _files[0] = NULL; /* 0 never allocated */\n        _files.resize(1); \n        _freeList.reserve(reserve);\n    }\n\n  public:\n    /** \n      Typedef for boost::shared_ptr for this ZkFuseHandleManager class.\n     */\n    typedef boost::shared_ptr<ZkFuseHandleManager> SharedPtr;\n\n    /**\n      Destructor.\n     */\n    ~ZkFuseHandleManager()\n    {\n    }\n    /** \n      Get the ZkFuseFile instance for a handle.\n\n      \\return the ZkFuseFile instance identified by the handle.\n      \\param handle get ZkFuseFile instance for this handle.\n     */\n    ZkFuseFilePtr getFile(Handle handle) const\n    {\n        AutoLock lock(_mutex);\n        return _files[handle];\n    }\n    /**\n      Get the immutable common configuration.\n\n      \\return the common configuration instance.\n     */\n    const ZkFuseCommon & getCommon() const\n    {\n        return _common;\n    }\n    /**\n      Deallocate a previously allocated handle.\n      This decrements the reference count of the corresponding\n      ZkFuseFile instance. If the reference count becomes zero,\n      decrement _numInUse. It may also cause the ZkFuseFile instance\n      to be reclaimed if there are too many cached ZkFuseFile instances.\n\n      The ZkFuseFile instance should be reclaimed if the number of\n      unused ZkFuseFile instances exceeds the configured cache size, i.e.\n      (_files.size() - _numInUse) > _common.getCacheSize()\n      and the ZkFuseFile instance has a reference count of zero.\n\n      Reclaiming a ZkFuseFile instance involves removing the ZkFuseFile\n      instance's path to handle mapping from _map and the handle to the \n      ZkFuseFile instance mapping from _files, adding the handle to \n      the _freeList, and finally deleting the ZkFuseFile instance.\n\n      \\param handle the handle that should be deallocated.\n     */\n    void deallocate(Handle handle);\n    /**\n      Handles ZooKeeper session events.\n      It invokes the known ZkFuseFile instances to let them know\n      that their watches will no longer be valid. \n     */\n    void eventReceived(const ZKWatcherEvent & event);\n    /**\n      Get data from the specified the ZooKeeper path.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path the path of the ZooKeeper node.\n      \\param data return data read.\n     */\n    int getData(const std::string & path, Data & data);\n    /**\n      Set data into the specified ZooKeeper path.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path the path of the ZooKeeper node.\n      \\param data the data to be written.\n      \\param exists set to true if this path exists.\n      \\param doFlush set to true if new data should be flushed to ZooKeeper.\n     */\n    int setData(const std::string & path,\n                const Data & data,\n                bool exists,\n                bool doFlush);\n    /**\n      Create a ZooKeeper node to represent a ZkFuse file or directory.\n\n      \\return handle if successful, otherwise return negative errno.\n      \\param path to create.\n      \\param mode should be either S_IFDIR for directory or \n                  S_IFREG for regular file.\n      \\param mayExist if set and the ZooKeeper node already exist, return\n                      valid handle instead of -EEXIST.\n      \\param created returns whether a new ZooKeeper node had been created.\n     */\n    int mknod(const std::string & path, \n              mode_t mode, \n              bool mayExist, \n              bool & created);\n    /**\n      Open a ZooKeeper node.  \n\n      The justCreated argument is used to differentiate if the _deleted flag \n      of the ZkFuseFile instance is to be trusted  (i.e. the path \n      does not exist in ZooKeeper.) The _deleted flag is trusted \n      if the ZkFuseFile instance is known to exist in ZooKeeper after\n      invoking ZooKeeper with the path. \n      \n      If justCreated is true, then the ZkFuseFile instance was just created. \n      The ZkFuseFile constructor sets the _deleted flag to true because \n      path is not known to exist and hence should not be accessed. \n      The justCreated flag will force the ZkFuseFile instance to invoke \n      ZooKeeper to determine if the path exists.\n\n      \\return handle if successful, otherwise return negative errno.\n      \\param path the path to open.\n      \\param justCreated indicates if this is newly created ZkFuseFile instance.\n     */\n    int open(const std::string & path, bool justCreated);\n    /**\n      Remove a ZkFuse directory.\n\n      If force is not set, then the ZooKeeper node will be removed only\n      if it has no data and no child nodes except ZkFuse metadata nodes.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path the path to remove.\n      \\param force force removal, i.e. bypass checks.\n      */\n    int rmdir(const char * path, bool force = false);\n    /**\n      Make a ZkFuse directory.\n\n      ZkFuse represents a ZooKeeper node with no data and no children \n      as a regular file. In order to differentiate a newly created\n      directory from an empty regular file, mkdir will create a directory\n      metadata node as a child of the directory.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path the path of the directory to create.\n      \\param mode create directory with this mode \n                  (mode currently not implemented).\n     */\n    int mkdir(const char * path, mode_t mode);\n    /**\n      Remove a ZkFuse regular file.\n\n      A file is the abstraction for the data part of a ZooKeeper node.\n      - If ZkFuse represents a ZooKeeper node as a directory, the data part\n        of the node is represented by synthesizing a name for this file. This\n        synthesized name is visible through readdir if the ZooKeeper node's\n        data is not empty. Removing such a file is done by truncating \n        the ZooKeeper node's data to 0 length.\n      - If ZkFuse represents a ZooKeeper node as a file, then removing the\n        is done by removing the ZooKeeper node (and its metadata).\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path the path of the file to remove.\n     */\n    int unlink(const char * path);\n    /**\n      Get attributes of a ZkFuse regular file or directory.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param path get attributes for this path\n      \\param stbuf store attributes here.\n     */\n    int getattr(const char * path, struct stat & stbuf);\n    /**\n      Rename a ZkFuse regular file.\n\n      It creates a new ZooKeeper node at toPath, copies data and file\n      metadata from the ZooKeeper node at fromPath to the new node, \n      and deletes the current ZooKeeper node. If the current ZooKeeper \n      node is not deleted if the new ZooKeeper node cannot be created \n      or the data copy fails.\n\n      It cannot be used to rename a directory.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param fromPath the current path.\n      \\param toPath rename to this path.\n     */\n    int rename(const char * fromPath, const char * toPath);\n    /**\n      Add a child ZooKeeper path to the children information cache\n      of the ZkFuseFile instance that caches the parent ZooKeeper node.\n\n      This is used to add a child path after a new ZooKeeper node has\n      been created to the children information cache of the parent\n      ZooKeeper node. This is needed because waiting for the children\n      changed event to update the cache may result in inconsistent local\n      views of the changes.\n      \\see removeChildFromParent\n\n      \\parama childPath the path of the child ZooKeeper node.\n     */\n    void addChildToParent(const std::string & childPath) const;\n    /**\n      Remove a child ZooKeeper path from the children information cache\n      of the ZkFuseFile instance that caches the parent ZooKeeper node.\n      \n      For example, this should happen whenever a path is deleted.\n      This child information cache of the parent will eventually be \n      invalidated by watches. However, the delivery of the children \n      change event may come after the next access and thus provide \n      the client with an inconsistent view. One example is that \n      client deletes the last file in a directory, but the children\n      changed event is not delivered before the client invokes rmdir.\n      to remove the parent. In this case, the rmdir fails because \n      the cached children information of the parent indicates the \n      \"directory\" is not empty.\n\n      \\param childPath the path of the child ZooKeeper node.\n     */\n    void removeChildFromParent(const std::string & childPath) const;\n    /**\n      Return the path for the parent of the specified ZooKeeper path.\n\n      \\return the parent path.\n      \\param childPath the child path.\n     */\n    std::string getParentPath(const std::string & childPath) const;\n    /**\n      Return the ZooKeeper path from a ZkFuse path.\n\n      The ZkFuse path may be a synthesized path. For example, a synthesized\n      path is required to access the data part of a ZooKeeper node's \n      data when ZkFuse represents the ZooKeeper node as directory. \n      A synthesized path is also required to create a child ZooKeeper node\n      under a ZooKeeper node that is represented by a regular file.\n\n      \\return the ZooKeeper path for path.\n      \\param path the ZkFuse path, which may be a synthesized path.\n      \\param nameType indicate whether the ZkFuse path is synthesized and\n                      whether the synthesized ZkFuse path identifies a\n                      directory or a regular file.\n     */\n    std::string getZkPath(const char * path, ZkFuseNameType & nameType) const;\n};\n\n/**\n  ZkFuseHandleManagerFactory - factory for ZkFuseHandleManager.\n  \n  This is the only way to create a ZkFuseHandleManager instance. \n  to make sure that _thisWeakPtr of the instance is intialized \n  after the instance is created.\n */\nclass ZkFuseHandleManagerFactory\n{\n  public:\n    /**\n      Create an instance of ZkFuseHandleManager.\n      \n      \\return the created ZkFuseHandleManager instance.\n      \\param common the common configuration.\n      \\param reserve initially reserve space for this number of handles.\n     */\n    static ZkFuseHandleManager::SharedPtr create(\n       const ZkFuseCommon & common, \n       unsigned reserve = 1000)\n    {\n        ZkFuseHandleManager::SharedPtr manager\n            (new ZkFuseHandleManager(common, reserve));\n        manager->_thisWeakPtr = manager;\n        return manager;\n    }\n};\n\n/**\n  ZkFuseAutoHandle - automatically closes handle.\n\n  It holds an opened handle and automatically closes this handle\n  when it is destroyed. This enables code that open a handle\n  to be exception safe.\n */\nclass ZkFuseAutoHandle\n{\n  private:\n    /**\n      Typedef for Handle which is an int.\n     */\n    typedef int Handle;\n    /**\n      Holds a reference to the ZkFuseHandlerManager instance that\n      allocated the handle.\n     */\n    ZkFuseHandleManager::SharedPtr _manager;\n    /**\n      The handle that should be closed when this instance is destroyed.\n      A valid handle has value that is equal or greater than 0.\n      A negative value indicates an error condition, usually the value\n      is a negative errno.\n     */\n    Handle _handle;\n    /**\n      Caches a reference to the ZkFuseFile instance with this handle.\n      This is a performance optimization so that _manager.getFile(_handle) \n      is only called once when the handle is initialized.\n     */\n    ZkFuseFilePtr _file;\n\n    /**\n      Initialize reference to the ZkFuseFile instance with this handle.\n     */\n    void _initFile()\n    {\n        if (_handle >= 0) {\n            _file = _manager->getFile(_handle);\n        } else {\n            _file = NULL;\n        }\n    }\n\n  public:\n    /**\n      Constructor - takes an previously opened handle.\n\n      \\param manager the ZkFuseHandleManager instance who allocated the handle.\n      \\param handle the handle.\n     */\n    ZkFuseAutoHandle(\n        const ZkFuseHandleManager::SharedPtr & manager, \n        int handle)\n      : _manager(manager),\n        _handle(handle),\n        _file()\n    {\n        _initFile();\n    }\n    /**\n      Constructor - open path and remember handle.\n\n      \\param manager the ZkFuseHandleManager instance who allocated the handle.\n      \\param path open this path and remember its handle in this instance.\n     */\n    ZkFuseAutoHandle( \n        const ZkFuseHandleManager::SharedPtr & manager, \n        const std::string & path)\n      : _manager(manager),\n        _handle(_manager->open(path, false)),\n        _file()\n    {\n        _initFile();\n    }\n    /**\n      Constructor - create path and remember handle.\n\n      The creation mode indicates whether the path identifies a regular file\n      or a directory.\n\n      \\param manager the ZkFuseHandleManager instance who allocated the handle.\n      \\param path create this path and remember its handle in this instance.\n      \\param mode the creation mode for the path, should be either\n                  S_IFDIR or S_IFDIR.\n      \\param mayExist, if set and the path already exists, \n                       then the ZkFuseAutoHandle will hold the handle\n                       for the path instead of -EEXIST.\n                       If not set and the path does not exist, then the handle\n                       be -EEXIST.\n     */\n    ZkFuseAutoHandle( \n        const ZkFuseHandleManager::SharedPtr & manager, \n        const std::string & path,\n        mode_t mode,\n        bool mayExist)\n      : _manager(manager),\n        _handle(-1),\n        _file()\n    {\n        bool created;\n        _handle = _manager->mknod(path, mode, mayExist, created);\n        _initFile();\n    }\n    /**\n      Destructor - closes the handle.\n     */\n    ~ZkFuseAutoHandle()\n    {\n        reset();\n    }\n    /**\n      Get the handle.\n      \\see _handle\n     */\n    int get() const\n    {\n        return _handle;\n    }\n    /**\n      Get the ZkFuseFile instance of the handle.\n      \\see _file\n     */\n    ZkFuseFilePtr getFile() const\n    {\n        return _file;\n    }\n    /**\n      Forget the handle, don't close the handle.\n     */\n    void release() \n    {\n        _handle = -1;\n        _file = NULL;\n    }\n    /**\n      Change the remembered handle.\n\n      It will close the current handle (if valid).\n     */\n    void reset(int handle = -1);\n};\n\n/**\n  ZkFuseStat - C++ wrapper for ZooKeeper Stat.\n\n  This wrapper provides ZooKeeper Stat will constructors that\n  initializes the instance variables of Stat.\n */\nclass ZkFuseStat : public Stat \n{\n  public:\n    /**\n      Constructor - clear instance variables.\n     */\n    ZkFuseStat() \n    {\n        clear();\n    }\n    /**\n      Destructor - do nothing.\n     */\n    ~ZkFuseStat()\n    {\n    }\n    /**\n      Clear instance variables.\n     */\n    void clear()\n    {\n        czxid = 0;\n        mzxid = 0;\n        ctime = 0;\n        mtime = 0;\n        version = 0;\n        cversion = 0;\n        aversion = 0;\n    }\n};\n\n/**\n  ZkFuseFile - an instance encapsulates the runtime state of an allocated\n  ZooKeeper node.\n\n  Memory management\n  - Referenced by the ZkFuseHandleManager that created this instance.\n  - Uses boost::shared_ptr to reference the ZkFuseHandleManager that \n    created this instance. This makes sure that this ZkFuseHandleManager\n    instance cannot be deleted when it has allocated ZkFuseFile instances.\n  - A ZkFuseHandleManager deletes itself if it can be reclaimed.\n    It can be reclaimed if it has no watches, its reference count is zero,\n    and the ZkFuseHandleManager instance would have more than the \n    configured number of cached ZkFuseFile instances. \n  - A ZkFuseFile instance cannot be deleted if it has active watches on\n    its ZooKeeper node. When one of its watches fires, the ZkFuseFile\n    instance must exist because one of its methods will be invoked \n    to process the event. If the ZkFuseFile instance has been deleted,\n    the method will access previously freed memory.\n\n  Concurrency control\n  - _mutex protects the instance variables of an instance.\n  - Callers should assume that a public method will acquire _mutex. \n  - Methods of this class may not hold _mutex while invoking an\n    ZkFuseHandleManager instance.\n  - Methods that with names that begin with \"_\" do not acquire _mutex. \n    They are usually called by public methods that acquire and hold _mutex.\n*/\nclass ZkFuseFile : boost::noncopyable\n{\n  public:\n    /**\n      Maximum size for the data part of a ZooKeeper node.\n     */\n    static const unsigned maxDataFileSize = MAX_DATA_SIZE;\n\n  private:\n    /**\n      Mode returned by getattr for a ZkFuse directory.\n     */\n    static const mode_t dirMode = (S_IFDIR | 0777);\n    /**\n      Mode returned by getattr for a ZkFuse regular file.\n     */\n    static const mode_t regMode = (S_IFREG | 0777);\n\n    /**\n      References the ZkFuseHandleManager that created this instance.\n     */\n    ZkFuseHandleManager::SharedPtr _manager;\n    /**\n      Handle for this instance.\n     */\n    const int _handle;\n    /**\n      Path of the ZooKeeper node represented by this instance.\n     */\n    const std::string _path;\n    /**\n      Mutex that protects the instance variables of this instance.\n     */\n    mutable zkfuse::Mutex _mutex;\n    /**\n      Reference count for this instance, i.e. the number of opens \n      minus the number of closes.\n     */\n    int _refCount;\n    /**\n      Indicates whether the ZooKeeper node exist.\n      This flag allows caching of deleted ZooKeeper node to avoid\n      repeated ZooKeeper lookups for a non-existent path, and avoid\n      using cached information. \n      \n      Its value is true if \n      - it is verified to exist (by calling ZooKeeper), or\n      - it is existence is unknown because ZooKeeper has not been\n        invoked to verify its path's existence.\n     */\n    bool _deleted;\n    /**\n      Count of current number directory opens minus directory closes.\n     */\n    int _openDirCount;\n    /**\n      Indicates whether cached children information is valid.\n      \n      It is true if the cached children information is valid.\n     */\n    bool _initializedChildren;\n    /**\n      Indicates whether there is an outstanding children watch.\n\n      It is true if it has an outstanding children watch.\n     */\n    bool _hasChildrenListener;\n    /**\n      Cached children information. \n\n      The cache is valid if _initializedChildren is true.\n     */\n    NodeNames _children;\n\n    /**\n      Indicates whether the cached data is valid.\n\n      It is true if the cached data and ZooKeeper Stat are valid.\n     */\n    bool _initializedData;\n    /**\n      Indicates whether there is an outstanding data watch.\n\n      It is true if it has an outstanding data watch.\n     */\n    bool _hasDataListener;\n    /**\n      Indicates whether the cached data (_activeData) has been modified.\n\n      It is true if the cached data has been modified.\n     */\n    bool _dirtyData;\n    /**\n      Currently active data.\n\n      To maintain atomicity of updates and emulate Posix semantics, \n      when a ZkFuse file remains open, the same data will be accessed\n      by the file's clients. The data will be flushed to ZooKeeper when\n      the flush method is called. The flush method may be called\n      explicitly by a client or implicitly when the ZkFuse file is no \n      longer currently open.\n\n      _activeData and _activeStat stores the data and ZooKeeper Stat\n      that will be accessed by the file's clients.\n\n      If there are changes when the ZkFuse file is open, new data is\n      cached as latest data (by _latestData and _latestStat).\n     */\n    Data _activeData;\n    /**\n      Currently active ZooKeeper Stat.\n      \\see _activeData\n     */\n    ZkFuseStat _activeStat;\n    /**\n      Latest data.\n      This is either the same as _activeData or it is newer. It is newer\n      is it has been updated by event triggered by a data watch.\n     */\n    Data _latestData;\n    /**\n      Latest ZooKeeper data.\n      This is either the same as _activeStat or it is newer. It is newer\n      is it has been updated by event triggered by a data watch.\n     */\n    ZkFuseStat _latestStat;\n\n    /**\n      Get userid.\n\n      \\return the userid.\n     */\n    uid_t _getUid() const\n    {\n        return _manager->getCommon().getUid();\n    }\n    /**\n      Get groupid.\n\n      \\return the groupid.\n     */\n    gid_t _getGid() const\n    {\n        return _manager->getCommon().getGid();\n    }\n    /** \n      Get block size.\n\n      \\return the block size.\n     */\n    unsigned _getBlkSize() const\n    {\n        return _manager->getCommon().getBlkSize();\n    }\n    /**\n      Get number of children, include metadata children in the count.\n\n      \\return the number of children including metadata children.\n     */\n    unsigned _numChildrenIncludeMeta() const\n    {\n        unsigned count = _children.size();\n        LOG_DEBUG(LOG, \"numChildrenIncludeMeta() returns %u\", count);\n        return count;\n    }\n    /**\n      Get number of children, exclude metadata children in the count.\n\n      \\return the number of children excluding metadata children.\n     */\n    unsigned _numChildrenExcludeMeta() const\n    {\n        unsigned count = 0;\n        for (NodeNames::const_iterator it = _children.begin();\n             it != _children.end();\n             it++) {\n            if (!_isMeta(*it)) {\n                count++;\n            }\n        }\n        LOG_DEBUG(LOG, \"numChildrenExcludeMeta() returns %u\", count);\n        return count;\n    }\n    /**\n      Whether the ZooKeeper node has children, include metadata\n      children.\n\n      \\return true if it has children including metadata children.\n     */\n    bool _hasChildrenIncludeMeta() const\n    { \n        return _numChildrenIncludeMeta() != 0;\n    }\n    /**\n      Return true if the ZooKeeper node has children, include metadata\n      children.\n\n      \\return true if it has children excluding metadata children.\n     */\n    bool _hasChildrenExcludeMeta() const\n    {\n        return _numChildrenExcludeMeta() != 0;\n    }\n    /**\n      Whether the ZooKeeper node has data.\n\n      \\return true if _activeData is not empty.\n     */\n    bool _hasData() const\n    {\n        return _activeData.empty() == false;\n    }\n    /**\n      Whether the ZooKeeper node has child with the specified path.\n\n      \\return true if the ZooKeeper node has a child with the specified path.\n      \\param childPath the path of the child.\n     */\n    bool _hasChildPath(const std::string & childPath) const\n    {\n        bool hasChild =\n            std::find(_children.begin(), _children.end(), childPath) \n            != _children.end();\n        LOG_DEBUG(LOG, \"hasChild(childPath %s) returns %d\", \n                  childPath.c_str(), hasChild);\n        return hasChild;\n    }\n    /**\n      Whether the given path component is a ZkFuse synthesized path\n      component.\n\n      A ZkFuse synthesized path component will begin with \n      the metadataNamePrefix obtained from the common configuration.\n      \\see _metadataNamePrefix\n\n      \\return true if the path component is a ZkFuse synthesized path\n                   component.\n      \\param childName the path component to check if it is synthesized by\n                       ZkFuse.\n     */\n    bool _isMeta(const std::string & childName) const\n    {\n        bool isMeta;\n        const std::string & prefix = \n            _manager->getCommon().getMetadataNamePrefix();\n        unsigned offset = \n            (_path.length() > 1 ?\n             _path.length() + 1 :\n             1 /* special case for root dir */ ); \n        unsigned minLength = offset + prefix.length();\n        if (childName.length() < minLength ||\n            childName.compare(offset, prefix.length(), prefix) != 0) {\n            isMeta = false;\n        } else {\n            isMeta = true;\n        }\n        LOG_DEBUG(LOG, \"isMeta(childName %s) returns %d\", \n                  childName.c_str(), isMeta);\n        return isMeta;\n    }\n    /**\n      Build a path for a specific child of the ZooKeeper node.\n \n      This is done by appending \"/\" (unless it is the ZooKeeper node\n      is the root node) and the name of the child.\n\n      \\return the path for the specified child of the ZooKeeper node.\n      \\param name the name of the child.\n     */\n    std::string _getChildPath(const std::string & name) const\n    {\n        return buildChildPath(_path, name);\n    }\n    /**\n      Whether the ZooKeeper node has a regular file metadata child node.\n\n      \\return true if the ZooKeeper node has a regular file metadata child\n                   node.\n     */\n    bool _hasRegMetadata() const\n    {\n        bool res = _hasChildPath(\n                _getChildPath(_manager->getCommon().getRegMetadataName()));\n        LOG_DEBUG(LOG, \"hasRegMetadata() returns %d\", res);\n        return res;\n    }\n    /**\n      Whether the ZooKeeper node has a directory metadata child node.\n\n      \\return true if the ZooKeeper node has a directory metadata child\n                   node.\n     */\n    bool _hasDirMetadata() const\n    {\n        bool res = _hasChildPath(\n                _getChildPath(_manager->getCommon().getDirMetadataName()));\n        LOG_DEBUG(LOG, \"hasDirMetadata() returns %d\", res);\n        return res;\n    }\n    /** \n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse regular\n      file.\n     \n      It should be a ZkFuse regular file it has no children or its \n      only children is its regular file metadata child node.\n\n      \\return true if the Zookeeper node should be presented as a ZkFuse\n                   regular file.\n     */\n    bool _isReg() const\n    {\n        unsigned numChildrenIncludeMeta = _numChildrenIncludeMeta();\n        bool res =\n            (numChildrenIncludeMeta == 0) ||\n            (numChildrenIncludeMeta == 1 && _hasRegMetadata() == true);\n        LOG_DEBUG(LOG, \"isReg() returns %d\", res);\n        return res;\n    }\n    /**\n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse directory.\n     \n      It should be a ZkFuse directory if it should not be presented as\n      a ZkFuse regular directory.\n      \\see _isReg\n\n      \\return true if the Zookeeper node should be presented as a ZkFuse\n                   directory.\n     */\n    bool _isDir() const \n    {\n        return !_isReg();\n    }\n    /**\n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse regular\n      file by taking into account the specified ZkFuseNameType.\n\n      The ZkFuseNameType may override the default ZkFuse presentation of\n      a ZooKeeper node. \n\n      \\return true if ZkFuse should present the ZooKeeper node as a ZkFuse\n                   regular file.\n      \\param nameType specifies the ZkFuseNameType.\n      \\param doLock whether _mutex should be acquired, it should be true\n                    if the caller did not acquire _mutex.\n     */\n    bool _isRegNameType(ZkFuseNameType nameType, bool doLock = false) const\n    {\n        bool res;\n        switch (nameType) {\n          case ZkFuseNameRegType:\n            res = true;\n            break;\n          case ZkFuseNameDirType:\n            res = false;\n            break;\n          case ZkFuseNameDefaultType:\n          default: \n            if (doLock) {\n                AutoLock lock(_mutex);\n                res = _isReg();\n            } else {\n                res = _isReg();\n            }\n            break;\n        }\n        LOG_DEBUG(LOG, \"isRegNameType(nameType %d) returns %d\", \n                  int(nameType), res);\n        return res;\n    }\n    /**\n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse \n      directory by taking into account the specified ZkFuseNameType.\n\n      The ZkFuseNameType may override the default ZkFuse presentation of\n      a ZooKeeper node. \n\n      \\return true if ZkFuse should present the ZooKeeper node as a ZkFuse\n                   directory.\n      \\param nameType specifies the ZkFuseNameType.\n      \\param doLock whether _mutex should be acquired, it should be true\n                    if the caller did not acquire _mutex.\n     */\n    bool _isDirNameType(ZkFuseNameType nameType, bool doLock = false) const\n    {\n        bool res;\n        switch (nameType) {\n          case ZkFuseNameRegType:\n            res = false; \n            break;\n          case ZkFuseNameDirType:\n            res = true;\n            break;\n          case ZkFuseNameDefaultType:\n          default: \n            if (doLock) {\n                AutoLock lock(_mutex);\n                res = _isDir();\n            } else {\n                res = _isDir();\n            }\n            break;\n        }\n        LOG_DEBUG(LOG, \"isDirNameType(nameType %d) returns %d\", \n                  int(nameType), res);\n        return res;\n    }\n    /**\n      ZkFuse regular file metadata.\n     */\n    struct Metadata {\n        /**\n          Version of the ZooKeeper node data that this metadata is good for.\n         */\n        uint32_t version;\n        /**\n          Acces time in milliseconds.\n         */\n        uint64_t atime;\n        /**\n          Modified time in milliseconds.\n         */\n        uint64_t mtime;\n\n        /**\n          Constructor.\n         */\n        Metadata() \n          : version(0),\n            atime(0),\n            mtime(0)\n        {\n        }\n    };\n    /**\n      Encode Metadata into Data so that it can be stored in a metadata\n      ZooKeeper node.\n\n      Each Metadata attribute is encoded as \"<key>: <value>\" on single line\n      terminated by newline.\n\n      \\param meta the input Metadata.\n      \\param data the output Data after encoding.\n     */\n    void _encodeMetadata(const Metadata & meta, Data & data) const\n    {\n        LOG_DEBUG(LOG, \"encodeMetadata()\");\n        std::ostringstream oss;\n        oss << \"version: \" << meta.version << endl\n            << \"atime: \" << meta.atime << endl\n            << \"mtime: \" << meta.mtime << endl;\n        data = oss.str();\n    }\n    /**\n      Decode Data from a metadata child ZooKeeper node into Metadata. \n\n      Data is a stream of \"<key>: <value>\" records separated by newline.\n\n      \\param data the input Data.\n      \\param meta the output Metadata after decoding.\n     */\n    void _decodeMetadata(const Data & data, Metadata & meta) const\n    {\n        LOG_DEBUG(LOG, \"decodeMetadata(data %s)\", data.c_str());\n        std::istringstream iss(data);\n        char key[128];\n        char value[1024];\n        while (!iss.eof()) {\n            key[0] = 0;\n            value[0] = 0;\n            iss.get(key, sizeof(key), ' ');\n            if (iss.eof()) {\n                break;\n            }\n            iss.ignore(32, ' ');\n            iss.getline(value, sizeof(value));\n            LOG_DEBUG(LOG, \"key %s value %s\", key, value);\n            if (strcmp(key, \"version:\") == 0) {\n                unsigned long long v = strtoull(value, NULL, 0);\n                LOG_DEBUG(LOG, \"version: %llu\", v);\n                meta.version = v;\n            }\n            else if (strcmp(key, \"atime:\") == 0) {\n                unsigned long long v = strtoull(value, NULL, 0);\n                LOG_DEBUG(LOG, \"atime: %llu\", v);\n                meta.atime = v;\n            }\n            else if (strcmp(key, \"mtime:\") == 0) {\n                unsigned long long v = strtoull(value, NULL, 0);\n                LOG_DEBUG(LOG, \"mtime: %llu\", v);\n                meta.mtime = v;\n            }\n            else {\n                LOG_WARN(LOG, \"decodeMetadata: path %s unknown key %s %s\\n\",\n                         _path.c_str(), key, value);\n            }\n        }\n        LOG_DEBUG(LOG, \"decodeMetadata done\");\n    }\n    /**\n      Flush data to the ZooKeeper node.\n\n      If cached active data has been modified, flush it to the ZooKeeper node.\n      Returns -EIO if the data cannot be written because the cached active\n      data is not the expected version, i.e. ZooKeeper returns ZBADVERSION.\n      -EIO may also indicate a more general failure, such as unable to \n      communicate with ZooKeeper.\n\n      \\return 0 if successful, otherwise negative errno.\n     */\n    int _flush()\n    {\n        LOG_DEBUG(LOG, \"flush() path %s\", _path.c_str());\n\n        int res = 0;\n        try {\n            if (_dirtyData) {\n                LOG_DEBUG(LOG, \"is dirty, active version %d\",\n                          _activeStat.version);\n                _manager->getCommon().getZkAdapter()->\n                    setNodeData(_path, _activeData, _activeStat.version);\n                /* assumes version always increments by one if successful */\n                _deleted = false;\n                _activeStat.version++;\n                _dirtyData = false;\n                res = 0;\n            } \n            else {\n                LOG_DEBUG(LOG, \"not dirty\");\n                res = 0;\n            }\n        } catch (const ZooKeeperException & e) {\n            if (e.getZKErrorCode() == ZBADVERSION) {\n                LOG_ERROR(LOG, \"flush %s bad version, was %d\",\n                          _path.c_str(), _activeStat.version);\n                res = -EIO;\n            } \n            else {\n                LOG_ERROR(LOG, \"flush %s exception %s\", \n                          _path.c_str(), e.what());\n                res = -EIO;\n            }\n        }\n\n        LOG_DEBUG(LOG, \"flush returns %d\", res);\n        return res;\n    }\n    /**\n      Truncate or expand the size of the cached active data.\n\n      This method only changes the size of the cached active data. \n      This change is committed to ZooKeeper when the cached data \n      is written to the ZooKeeper node by flush().\n\n      Return -EFBIG is the requested size exceeds the maximum.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param size the requested size.\n     */\n    int _truncate(off_t size) \n    {\n        LOG_DEBUG(LOG, \"truncate(size %zu) path %s\", size, _path.c_str());\n        \n        int res = 0;\n\n        if (!_isInitialized()) {\n            LOG_DEBUG(LOG, \"not initialized\");\n            res = -EIO;\n        }\n        else if (size > _activeData.size()) {\n            if (size > maxDataFileSize) {\n                LOG_DEBUG(LOG, \"size > maxDataFileSize\");\n                res = -EFBIG;\n            } else {\n                LOG_DEBUG(LOG, \"increase to size\");\n                _activeData.insert(_activeData.begin() + \n                                   (size - _activeData.size()), 0);\n                _dirtyData = true;\n                res = 0;\n            }\n        }\n        else if (size < _activeData.size()) {\n            LOG_DEBUG(LOG, \"decrease to size\");\n            _activeData.resize(size);\n            _dirtyData = true;\n            res = 0;\n        }\n        else {\n            LOG_DEBUG(LOG, \"do nothing, same size\");\n        }\n\n        LOG_DEBUG(LOG, \"truncate returns %d\", res);\n        return res;\n    }\n    /**\n      Remove a ZkFuse directory.\n\n      If force is true, then the ZooKeeper node and its decendants\n      will be deleted.\n\n      If force is false, then this method implements the semantics\n      of removing a ZkFuse directory. It will delete the ZooKeeper node\n      only if the ZooKeeper node have no data and no non-metadata \n      children.\n      - Return -ENOTDIR if the ZooKeeper node is not considered\n        to be a directory (after taking into consideration the specified\n        ZkFuseNameType). \n      - Return -ENOTEMPTY if the ZooKeeper node has data or it has \n        non-metadata children.\n      - Return -ENOENT if the ZooKeeper cannot be deleted, usually this\n        is because it does not exist.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param nameType the ZkFuseNameType of the path used to specify the\n                      directory to be removed. It influences whether ZkFuse\n                      considers the ZooKeeper node to be a regular file or\n                      directory. \\see ZkFuseNameType\n      \\param force    set to true to bypass ZkFuse rmdir semantic check.\n     */\n    int _rmdir(ZkFuseNameType nameType, bool force)\n    {\n        LOG_DEBUG(LOG, \"rmdir(nameType %d, force %d) path %s\", \n                  int(nameType), force, _path.c_str());\n\n        int res = 0;\n        try {\n            if (!force && !_isDirNameType(nameType)) {\n                LOG_DEBUG(LOG, \"failed because not directory\");\n                res = -ENOTDIR;\n            } \n            else if (!force && _hasData()) {\n                /* rmdir cannot occur if there non-empty \"data file\" */\n                LOG_DEBUG(LOG, \"failed because node has data\");\n                res = -ENOTEMPTY;\n            } \n            else if (!force && _hasChildrenExcludeMeta()) {\n                /* rmdir cannot occur if there are \"subdirs\" */\n                LOG_DEBUG(LOG, \"failed because node has children\");\n                res = -ENOTEMPTY;\n            } \n            else {\n                LOG_DEBUG(LOG, \"delete node\");\n                bool deleted = _manager->getCommon().getZkAdapter()->\n                     deleteNode(_path, true);\n                if (deleted) {\n                    _deleted = true;\n                    _clearChildren();\n                    res = 0;\n                } else {\n                    /* TODO: differentiate delete error conditions,\n                     * e.g. access permission, not exists, ... ?\n                     */\n                    LOG_DEBUG(LOG, \"delete failed\");\n                    res = -ENOENT;\n                }\n            }\n        } catch (const std::exception & e) {\n            LOG_ERROR(LOG, \"rmdir %s exception %s\", _path.c_str(), e.what());\n            res = -EIO;\n        }\n\n        LOG_DEBUG(LOG, \"rmdir returns %d\", res);\n        return res;\n    }\n    /**\n      Remove a ZkFuse regular file.\n\n      This method implements the semantics of removing a ZkFuse regular file.\n      - If the ZkFuse regular file represents the data part of the \n        ZooKeeper node which is presented as a ZkFuse directory, \n        the regular file is virtually deleted by truncating the\n        ZooKeeper node's data. Readdir will not synthesize a regular \n        file entry for the data part of a ZooKeeper node if \n        the ZooKeeper node has no data.\n      - If the ZkFuse regular file represents the data part of the \n        ZooKeeper node which is presented as a ZkFuse regular file,\n        the ZooKeeper node and its decendants are deleted.\n\n      Returns -EISDIR if the ZkFuse regular file cannot be deleted\n      because ZkFuse consider it to be a directory.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param nameType the ZkFuseNameType of the path used to specify the\n                      directory to be removed. It influences whether ZkFuse\n                      considers the ZooKeeper node to be a regular file or\n                      directory. \\see ZkFuseNameType\n    */\n    int _unlink(ZkFuseNameType nameType) \n    {\n        LOG_DEBUG(LOG, \"unlink(nameType %d) path %s\", \n                  int(nameType), _path.c_str());\n\n        int res = 0;\n        switch (nameType) {\n          case ZkFuseNameRegType:\n            if (_isDir()) {\n                res = _truncate(0);\n            } else {\n                res = _rmdir(nameType, true);\n            }\n            break;\n          case ZkFuseNameDirType:\n            res = -EISDIR;\n            break;\n          case ZkFuseNameDefaultType:\n          default:\n            if (_isReg()) {\n                res = _rmdir(nameType, true);\n            } else {\n                res = -EISDIR;\n            }\n            break;\n        }\n\n        LOG_DEBUG(LOG, \"unlink returns %d\", res);\n        return res;\n    }\n    /**\n      Whether cached children and data are valid.\n\n      \\return true if cached children and data are valid.\n     */\n    bool _isInitialized() const\n    {\n        return _initializedChildren && _initializedData;\n    }\n    /**\n      Clear and invalidate cached children information.\n     */\n    void _clearChildren()\n    {\n        _initializedChildren = false;\n        _children.clear();\n    }\n    /**\n      Clear and invalidate cached data.\n     */\n    void _clearData() \n    {\n        _initializedData = false;\n        _dirtyData = false;\n        _activeData.clear();\n        _activeStat.clear();\n        _latestData.clear();\n        _latestStat.clear();\n    }\n    /**\n      Whether the ZkFuseFile instance is a zombie.\n      \n      It is a zombie if it is not currently open, i.e. its reference count\n      is 0.\n     */\n    bool _isZombie() const \n    {\n        return (_refCount == 0);\n    }\n    /**\n      Whether the ZkFuseFile instance is currently opened as a regular file\n      only once.\n      \n      It is used to determine when the cached data can be replaced with\n      the latest data. \\see _activeData.\n      \n      \\return true if its currently opened as a regular file only once.\n     */\n    bool _isOnlyRegOpen() const\n    {\n        return ((_refCount - _openDirCount) == 1);\n    }\n    /**\n      Get attributes without accessing metadata.\n      \n      The atime and mtime returned does not take into consideration\n      overrides present in a matadata file.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param stbuf return attributes here.\n      \\param nameType specifies the ZkFuseNameType of the ZkFuse path used\n                      to get attributes. It influences whether the directory\n                      or regular file attributes are returned.\n     */\n    int _getattrNoMetaAccess(struct stat & stbuf, ZkFuseNameType nameType) const\n    {\n        int res = 0;\n        if (_deleted) {\n            LOG_DEBUG(LOG, \"deleted\");\n            res = -ENOENT;\n        } \n        else if (!_isInitialized()) {\n            LOG_DEBUG(LOG, \"not initialized\");\n            res = -EIO;\n        }\n        else {   \n            assert(_isInitialized());\n            bool isRegular = _isRegNameType(nameType);\n            if (isRegular) {\n                LOG_DEBUG(LOG, \"regular\");\n                stbuf.st_mode = regMode;\n                stbuf.st_nlink = 1;\n                stbuf.st_size = _activeData.size();\n            } else {\n                LOG_DEBUG(LOG, \"directory\");\n                stbuf.st_mode = dirMode;\n                stbuf.st_nlink = \n                    _children.size() + (_activeData.empty() ? 0 : 1);\n                stbuf.st_size = stbuf.st_nlink;\n            }\n            stbuf.st_uid = _getUid();\n            stbuf.st_gid = _getGid();\n            /* IMPORTANT:\n             * Conversion to secs from millisecs must occur before \n             * assigning to st_atime, st_mtime, and st_ctime. Otherwise\n             * truncating from 64-bit to 32-bit will cause lost of\n             * most significant 32-bits before converting to secs.\n             */\n            stbuf.st_atime = millisecsToSecs(_activeStat.mtime);\n            stbuf.st_mtime = millisecsToSecs(_activeStat.mtime);\n            stbuf.st_ctime = millisecsToSecs(_activeStat.ctime);\n            stbuf.st_blksize = _getBlkSize();\n            stbuf.st_blocks = \n                (stbuf.st_size + stbuf.st_blksize - 1) / stbuf.st_blksize;\n            res = 0;\n        }\n        return res;\n    }\n    /**\n      Get the context that should be registered with the data and\n      children watches.\n\n      The returned context is a pointer to the ZkFuseFile instance\n      cast to the desired ContextType.\n\n      \\return the context.\n     */\n    ZooKeeperAdapter::ContextType _getZkContext() const\n    {\n        return (ZooKeeperAdapter::ContextType) NULL;\n    }\n\n    /**\n      DataListener - listener that listens for ZooKeeper data events\n      and calls dataEventReceived on the ZkFuseFile instance \n      identified by the event context.\n      \\see dataEventReceived\n     */\n    class DataListener : public ZKEventListener {\n      public:\n       /**\n         Received a data event and invoke ZkFuseFile instance obtained from\n         event context to handle the event.\n        */\n        virtual void eventReceived(const ZKEventSource & source,\n                                   const ZKWatcherEvent & event)\n        {\n            assert(event.getContext() != 0);\n            ZkFuseFile * file = static_cast<ZkFuseFile *>(event.getContext());\n            file->dataEventReceived(event);\n        }\n    };\n    \n    /**\n      DataListener - listener that listens for ZooKeeper children events\n      and calls childrenEventReceived on the ZkFuseFile instance \n      identified by the event context.\n      \\see childrenEventReceived\n     */\n    class ChildrenListener : public ZKEventListener {\n      public:\n       /**\n         Received a children event and invoke ZkFuseFile instance obtained from\n         event context to handle the event.\n        */\n        virtual void eventReceived(const ZKEventSource & source,\n                                   const ZKWatcherEvent & event)\n        {\n            assert(event.getContext() != 0);\n            ZkFuseFile * file = static_cast<ZkFuseFile *>(event.getContext());\n            file->childrenEventReceived(event);\n        }\n    };\n    \n    /**\n      Globally shared DataListener. \n     */\n    static DataListener _dataListener;\n    /**\n      Globally shared ChildrenListener. \n     */\n    static ChildrenListener _childrenListener;\n\n  public:\n    /**\n      Constructor.\n\n      Sets reference count to one, i.e. it has been constructed because\n      a client is trying to open the path. \\see _refCount.\n      Sets deleted to true. \\see _deleted.\n      Sets number of currently directory opens to zero. \\see _openDirCount.\n      Invalidate cach for children information and data. \n\n      \\param manager the ZkFuseHandleManager instance who is creating this \n                     ZkFuseFile instance.\n      \\param handle  the handle assigned by the ZkFuseHandleManager instance\n                     for this ZkFuseFile instance.\n      \\param path    the ZooKeeper path represented by this ZkFuseFile instance.\n     */\n    ZkFuseFile(const ZkFuseHandleManager::SharedPtr & manager,\n               const int handle,\n               const std::string & path)\n      : _manager(manager),\n        _handle(handle),\n        _path(path),\n        _mutex(),\n        _refCount(1),\n        _deleted(true),\n        /* children stuff */\n        _openDirCount(0),\n        _initializedChildren(false),\n        _hasChildrenListener(false),\n        _children(),\n        /* data stuff */\n        _initializedData(false),\n        _hasDataListener(false),\n        _dirtyData(false), \n        _activeData(),\n        _activeStat(),\n        _latestData(),\n        _latestStat()\n    {\n        LOG_DEBUG(LOG, \"constructor() path %s\", _path.c_str());\n    }\n    /**\n      Destructor.\n     */\n    ~ZkFuseFile()\n    {\n        LOG_DEBUG(LOG, \"destructor() path %s\", _path.c_str());\n\n        assert(_isZombie());\n        _clearChildren();\n        _clearData();\n    }\n    /**\n      Whether the ZooKeeper node represented by this ZkFuseFile instance\n      has been deleted.\n      \\see _deleted\n\n      \\return true if it is deleted.\n     */\n    bool isDeleted() const \n    { \n        AutoLock lock(_mutex);\n        return _deleted;\n    }\n    /**\n      Return the path of the ZooKeeper node represented by this ZkFuseFile\n      instance.\n      \\see _path.\n\n      \\return the ZooKeeper node's path.\n     */\n    const string & getPath() const \n    {\n        return _path;\n    }\n    /**\n      Add a childPath to the children information cache.\n      \n      \\return 0 if successful, otherwise return negative errno.\n      \\param childPath the ZooKeeper path of the child.\n     */\n    int addChild(const std::string & childPath) \n    {\n        LOG_DEBUG(LOG, \"addChild(childPath %s) path %s\", \n                  childPath.c_str(), _path.c_str());\n\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            if (_initializedChildren) {\n                NodeNames::iterator it = \n                    std::find(_children.begin(), _children.end(), childPath);\n                if (it == _children.end()) {\n                    LOG_DEBUG(LOG, \"child not found, adding child path\");\n                    _children.push_back(childPath);\n                    res = 0;\n                } \n                else {\n                    LOG_DEBUG(LOG, \"child found\");\n                    res = -EEXIST;\n                }\n            }\n        }\n        \n        LOG_DEBUG(LOG, \"addChild returns %d\", res);\n        return res;\n    }\n    /**\n      Remove a childPath from the children information cache.\n      \n      \\return 0 if successful, otherwise return negative errno.\n      \\param childPath the ZooKeeper path of the child.\n     */\n    int removeChild(const std::string & childPath) \n    {\n        LOG_DEBUG(LOG, \"removeChild(childPath %s) path %s\", \n                  childPath.c_str(), _path.c_str());\n\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            if (_initializedChildren) {\n                NodeNames::iterator it = \n                    std::find(_children.begin(), _children.end(), childPath);\n                if (it != _children.end()) {\n                    LOG_DEBUG(LOG, \"child found\");\n                    _children.erase(it);\n                    res = 0;\n                } \n                else {\n                    LOG_DEBUG(LOG, \"child not found\");\n                    res = -ENOENT;\n                }\n            }\n        }\n        \n        LOG_DEBUG(LOG, \"removeChild returns %d\", res);\n        return res;\n    }\n    /**\n      Invalidate the cached children information and cached data.\n      \\see _clearChildren\n      \\see _clearData\n\n      \\param clearChildren set to true to invalidate children information cache.\n      \\param clearData set to true to invalidate data cache.\n     */\n    void clear(bool clearChildren = true, bool clearData = true)\n    {\n        LOG_DEBUG(LOG, \"clear(clearChildren %d, clearData %d) path %s\", \n                  clearChildren, clearData, _path.c_str());\n\n        {\n            AutoLock lock(_mutex);\n            if (clearChildren) {\n                _clearChildren();\n            }\n            if (clearData) {\n                _clearData();\n            }\n        }\n    }\n    /** \n      Whether reference count is zero.\n      \\see _refCount\n\n      \\return true if reference count is zero.\n     */\n    bool isZombie() const \n    {\n        AutoLock lock(_mutex);\n\n        return (_refCount == 0);\n    }\n    /**\n      Increment the reference count of the ZkFuseFile instance.\n\n      This method may be called by a ZkFuseFileManager instance while\n      holding the ZkFuseFileManager's _mutex. To avoid deadlocks, \n      this methods must never invoke a ZkFuseFileManager instance \n      directly or indirectly while holding the ZkFuseFile instance's\n      _mutex.\n      \\see _refCount\n\n      \\return the post-increment reference count.\n      \\param count value to increment the reference count by.\n     */\n    int incRefCount(int count = 1)\n    {\n        LOG_DEBUG(LOG, \"incRefCount(count %d) path %s\", count, _path.c_str());\n\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            _refCount += count;\n            assert(_refCount >= 0);\n            res = _refCount;\n        }\n\n        LOG_DEBUG(LOG, \"incRefCount returns %d\", res); \n        return res;\n    }\n    /**\n      Decrement the reference count of the ZkFuseFile instance.\n\n      This method may be called by a ZkFuseFileManager instance while\n      holding the ZkFuseFileManager's _mutex. To avoid deadlocks, \n      this methods must never invoke a ZkFuseFileManager instance \n      directly or indirectly while holding the ZkFuseFile instance's\n      _mutex.\n      \\see _refCount\n\n      \\return the post-decrement reference count.\n      \\param count value to decrement the reference count by.\n     */\n    int decRefCount(int count = 1)\n    {\n        return incRefCount(-count);\n    }\n    /**\n      Increment the count of number times the ZkFuseFile instance has\n      been opened as a directory.\n      \n      This count is incremented by opendir and decremented by releasedir.\n      \\see _openDirCount.\n\n      \\return the post-increment count.\n      \\param count the value to increment the count by.\n     */\n    int incOpenDirCount(int count = 1)\n    {\n        LOG_DEBUG(LOG, \"incOpenDirCount(count %d) path %s\", \n                  count, _path.c_str());\n\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            _openDirCount += count;\n            assert(_openDirCount >= 0);\n            res = _openDirCount;\n            assert(_openDirCount <= _refCount);\n        }\n\n        LOG_DEBUG(LOG, \"incOpenDirCount returns %d\", res); \n        return res;\n\n    }\n    /**\n      Decrement the count of number times the ZkFuseFile instance has\n      been opened as a directory.\n      \n      This count is incremented by opendir and decremented by releasedir.\n      \\see _openDirCount.\n\n      \\return the post-decrement count.\n      \\param count the value to decrement the count by.\n     */\n    int decOpenDirCount(int count = 1)\n    {\n        return incOpenDirCount(-count);\n    }\n    /**\n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse \n      directory by taking into account the specified ZkFuseNameType.\n\n      The ZkFuseNameType may override the default ZkFuse presentation of\n      a ZooKeeper node. \n      \\see _isDirNameType\n\n      \\return true if ZkFuse should present the ZooKeeper node as a ZkFuse\n                   directory.\n      \\param nameType specifies the ZkFuseNameType.\n     */\n    bool isDirNameType(ZkFuseNameType nameType) const\n    {\n        return _isDirNameType(nameType, true);\n    }\n    /**\n      Whether ZkFuse should present the ZooKeeper node as a ZkFuse \n      regular file by taking into account the specified ZkFuseNameType.\n\n      The ZkFuseNameType may override the default ZkFuse presentation of\n      a ZooKeeper node. \n      \\see _isRegNameType\n\n      \\return true if ZkFuse should present the ZooKeeper node as a ZkFuse\n                   regular file.\n      \\param nameType specifies the ZkFuseNameType.\n     */\n    bool isRegNameType(ZkFuseNameType nameType) const\n    {\n        return _isRegNameType(nameType, true);\n    }\n    /**\n      Get the active data.\n      \\see _activeData\n\n      \\param data return data here.\n     */\n    void getData(Data & data) const\n    {\n        AutoLock lock(_mutex);\n\n        data = _activeData;\n    }\n    /**\n      Set the active data.\n      \\see _activeData\n\n      Return -EFBIG is the data to be written is bigger than the maximum\n      permitted size (and no data is written).\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param data set to this data.\n      \\param doFlush whether to flush the data to the ZooKeeper node.\n     */\n    int setData(const Data & data, bool doFlush)\n    {\n        LOG_DEBUG(LOG, \"setData(doFlush %d) path %s\", doFlush, _path.c_str());\n        int res = 0;\n\n        if (data.size() > maxDataFileSize) {\n            res = -EFBIG;\n        } \n        else {\n            AutoLock lock(_mutex);\n            _activeData = data;\n            _dirtyData = true;\n            if (doFlush) {\n                res = _flush();\n            }\n        }\n\n        LOG_DEBUG(LOG, \"setData() returns %d\", res);\n        return res;\n    }\n    /**\n      Update the children information and the data caches as needed.\n\n      This method is invoked when a ZkFuse regular file or directory \n      implemented by this ZkFuseFile instance is opened, e.g.\n      using open or opendir. It attempts to:\n      - make sure that the cache has valid children information\n      - register for watches for changes if no previous watches have\n        been registered.\n\n      The newFile flag indicates if the ZkFuseFile instance has just\n      been constructed and that ZooKeeper has not been contacted to\n      determine if the ZooKeeper path for this file really exist.\n      When a ZkFuseFile instance is created, the _deleted flag is set to\n      true because it is safer to assume that the ZooKeeper node does\n      not exist. The newFile flag causes the _deleted flag to be\n      ignored and ZooKeeper to be contacted to update the caches.\n\n      If the newFile flag is false, then the ZkFuseFile instance is\n      currently open and have been opened before. Hence, these previous\n      opens should have contacted ZooKeeper and would like learned from\n      ZooKeeper whether the ZooKeeper path exists. Therefore, \n      the _deleted flag should be trustworthy, i.e. it has accurate \n      information on whether the ZooKeeper path actually exists.\n\n      \\return 0 if successful, otherwise return negative errno.\n      \\param newFile set to true if the ZkFuseFile instance is newly created.\n     */\n    int update(bool newFile)\n    {\n        LOG_DEBUG(LOG, \"update(newFile %d) path %s\", newFile, _path.c_str());\n\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n\n            /* At this point, cannot be zombie.\n             */\n            assert(!_isZombie());\n            if (!newFile && _deleted) {\n                /* Deleted file, don't bother to update caches */\n                LOG_DEBUG(LOG, \"deleted, not new file\"); \n                res = -ENOENT;\n            }\n            else {\n                try {\n                    LOG_DEBUG(LOG, \"initialized children %d, data %d\",\n                              _initializedChildren, _initializedData);\n                    LOG_DEBUG(LOG, \"has children watch %d, data watch %d\",\n                              _hasChildrenListener, _hasDataListener);\n                    /*\n                     * Children handling starts here.\n                     * If don't have children listener,\n                     *    then must establish listener.\n                     * If don't have cached children information, \n                     *    then must get children information. \n                     * It just happens, that the same ZooKeeper API \n                     * is used for both.\n                     */\n                    if (_initializedChildren == false ||\n                        _hasChildrenListener == false\n#ifdef ZOOKEEPER_ROOT_CHILDREN_WATCH_BUG\n                        /* HACK for root node because changes to children\n                         * on a root node does not cause children watches to\n                         * fire.\n                         */\n                        || _path.length() == 1\n#endif // ZOOKEEPER_ROOT_CHILDREN_WATCH_BUG\n                    ) {\n                        LOG_DEBUG(LOG, \"update children\");\n                        NodeNames children;\n                        _manager->getCommon().getZkAdapter()->\n                          getNodeChildren( children, _path, \n                                          &_childrenListener, _getZkContext());\n                        _hasChildrenListener = true;\n                        LOG_DEBUG(LOG, \"update children done\"); \n                        _children.swap(children);\n                        _initializedChildren = true;\n                        /* Since getNodeChildren is successful, the\n                         * path must exist */\n                        _deleted = false;\n                    }\n                    else {\n                        /* Children information is fresh since \n                         * it is initialized and and have been \n                         * updated by listener.\n                         */\n                    }\n                    /*\n                     * Data handling starts here.\n                     */\n                    assert(newFile == false || _isOnlyRegOpen());\n                    if (!_isOnlyRegOpen()) {\n                        /* If is already currently opened by someone,\n                         * then don't update data with latest from ZooKeeper,\n                         * use current active data (which may be initialized \n                         * or not).\n                         * \\see _activeData\n                         */\n                        LOG_DEBUG(LOG, \"node currently in-use, no data update\");\n                    } \n                    else {\n                        /* If not opened/reopened by someone else, \n                         *    then perform more comprehensive checks of\n                         *    to make data and listener is setup correctly.\n                         * If don't have data listener,\n                         *    then must establish listener.\n                         * If don't have cached data, \n                         *    then must get data.\n                         * It just happens, that the same ZooKeeper API \n                         * is used for both.  \n                         */\n                        LOG_DEBUG(LOG, \"node first use or reuse\");\n                        if (_initializedData == false ||\n                            _hasDataListener == false) {\n                            /* Don't have any data for now or need to register\n                             * for callback */\n                            LOG_DEBUG(LOG, \"update data\");\n                            _latestData = \n                                _manager->getCommon().getZkAdapter()->\n                                getNodeData(_path, &_dataListener, \n                                            _getZkContext(), \n                                            &_latestStat);\n                            _hasDataListener = true;\n                            LOG_DEBUG(LOG, \n                                      \"update data done, latest version %d\",\n                                      _latestStat.version);\n                            /* Since getNodeData is successful, the\n                             * path must exist. */\n                            _deleted = false;\n                        } \n                        else {\n                            /* Data is fresh since it is initialized and\n                             * and have been updated by listener.\n                             */\n                        }\n                        /* Update active data to the same as the most \n                         * recently acquire data.\n                         */\n                        _activeData = _latestData;\n                        _activeStat = _latestStat;\n                        _initializedData = true;\n                        _dirtyData = false;\n                        LOG_DEBUG(LOG, \"update set active version %d\",\n                                  _activeStat.version);\n                    } \n                    res = 0;\n                } catch (const ZooKeeperException & e) {\n                    /* May have ZNONODE exception if path does exist. */\n                    if (e.getZKErrorCode() == ZNONODE) {\n                        LOG_DEBUG(LOG, \"update %s exception %s\", \n                                  _path.c_str(), e.what());\n                        /* Path does not exist, set _deleted, \n                         * clear children information cache \n                         */\n                        _deleted = true;\n                        _clearChildren();\n                        res = -ENOENT;\n                    } else {\n                        LOG_ERROR(LOG, \"update %s exception %s\", \n                                  _path.c_str(), e.what());\n                        res = -EIO;\n                    }\n                }\n            }\n        }\n    \n        LOG_DEBUG(LOG, \"update returns %d\", res);\n        return res;\n    }\n    /**\n      Process a data event.\n\n      This method may:\n      - Invalidate the data cache.\n      - Invoke ZooKeeper to update the data cache and register a new\n        data watch so that the cache can be kept in-sync with the\n        ZooKeeper node's data.\n\n      This method does not change the active data. Active data will be\n      changed to a later version by update() at the appropriate time.\n      \\see update.\n     */\n    void dataEventReceived(const ZKWatcherEvent & event) \n    {\n        bool reclaim = false;\n        int eventType = event.getType();\n        int eventState = event.getState();\n\n        /*\n          IMPORTANT: \n          \n          Do not mark ZkFuseFile instance as deleted when a ZOO_DELETED_EVENT \n          is received without checking with ZooKeeper. An example of \n          problematic sequence would be:\n\n          1. Create node.\n          2. Set data and watch.\n          3. Delete node.\n          4. Create node.\n          5. Deleted event received.\n\n          It is a bug to mark the ZkFuseFile instance as deleted after \n          step 5 because the node exists.\n          \n          Therefore, this method should always contact ZooKeeper to keep the\n          data cache (and deleted status) up-to-date if necessary.\n         */\n        LOG_DEBUG(LOG, \"dataEventReceived() path %s, type %d, state %d\",\n                  _path.c_str(), eventType, eventState);\n        {\n            AutoLock lock(_mutex);\n\n            _hasDataListener = false;\n            /* If zombie, then invalidate cached data.\n             * This clears _initializedData and eliminate \n             * the need to get the latest data from ZooKeeper and\n             * re-register data watch. \n             */\n            if (_isZombie() && _initializedData) {\n                LOG_DEBUG(LOG, \"invalidate data\");\n                _clearData();\n            }\n            else if ((_refCount - _openDirCount) > 0) {\n                /* Don't invalidate cached data because clients of currently\n                 * open files don't expect the data to change from under them.\n                 * If data acted upon by these clients have become stale,\n                 * then the clients will get an error when ZkFuse attempts to\n                 * flush dirty data. The clients will not get error \n                 * notification if they don't modify the stale data.\n                 *\n                 * If data cache is cleared here, then the following code \n                 * to update data cache and re-register data watch will not \n                 * be executed and may result in the cached data being\n                 * out-of-sync with ZooKeeper.\n                 */\n                LOG_WARN(LOG, \n                         \"%s data has changed while in-use, \"\n                         \"type %d, state %d, refCount %d\",\n                         _path.c_str(), eventType, eventState, _refCount);\n            }\n            /* If cache was valid and still connected\n             * then get the latest data from ZooKeeper \n             * and re-register data watch. This is required to keep \n             * the data cache in-sync with ZooKeeper.\n             */ \n            if (_initializedData && \n                eventState == ZOO_CONNECTED_STATE \n               ) {\n                try {\n                    LOG_DEBUG(LOG, \"register data watcher\");\n                    _latestData = \n                        _manager->getCommon().getZkAdapter()->\n                        getNodeData(_path, &_dataListener, _getZkContext(), \n                                    &_latestStat);\n                    _hasDataListener = true;\n                    LOG_DEBUG(LOG, \n                              \"get data done, version %u, cversion %u done\",\n                              _latestStat.version, _latestStat.cversion);\n                    _deleted = false;\n                } catch (const ZooKeeperException & e) {\n                    if (e.getZKErrorCode() == ZNONODE) {\n                        _deleted = true;\n                        _clearChildren();\n                    }\n                    LOG_ERROR(LOG, \"dataEventReceived %s exception %s\", \n                              _path.c_str(), e.what());\n                }\n            }\n        }\n        LOG_DEBUG(LOG, \"dataEventReceived return %d\", reclaim);\n    }\n    /**\n      Process a children event.\n\n      This method may:\n      - Invalidate the children information cache.\n      - Invoke ZooKeeper to update the children cache and register a new\n        data watch so that the cache can be kept in-sync with the\n        ZooKeeper node's children information.\n     */\n    void childrenEventReceived(const ZKWatcherEvent & event) \n    {\n        bool reclaim = false;\n        int eventType = event.getType();\n        int eventState = event.getState();\n\n        LOG_DEBUG(LOG, \"childrenEventReceived() path %s, type %d, state %d\",\n                  _path.c_str(), eventType, eventState);\n        {\n            AutoLock lock(_mutex);\n\n            _hasChildrenListener = false;\n            /* If zombie or disconnected, then invalidate cached children \n             * information. This clears _initializedChildren and eliminate \n             * the need to get the latest children information and\n             * re-register children watch.\n             */\n            if (_initializedChildren && \n                (_isZombie() || eventState != ZOO_CONNECTED_STATE)) {\n                LOG_DEBUG(LOG, \"invalidate children\");\n                _clearChildren();\n            }\n            else if (_initializedChildren) {\n                /* Keep cached children information so that we have some\n                 * children information if get new children information\n                 * fails. If there is failure, then on next open, \n                 * update() will attempt again to get children information\n                 * again because _hasChildrenListener will be false.\n                 *\n                 * If children information cache is cleared here, then\n                 * the following code to update children information cache\n                 * and re-register children watch will not be executed\n                 * and may result in the cached children information being\n                 * out-of-sync with ZooKeeper.\n                 *\n                 * The children cache will be cleared if unable to \n                 * get children and re-establish watch.\n                 */\n                LOG_WARN(LOG, \n                         \"%s children has changed while in-use, \"\n                         \"type %d, state %d, refCount %d\",\n                         _path.c_str(), eventType, eventState, _refCount);\n            }\n            /* If children cache was valid and still connected, \n             * then get the latest children information from ZooKeeper \n             * and re-register children watch. This is required to \n             * keep the children information cache in-sync with ZooKeeper.\n             */ \n            if (_initializedChildren && \n                eventState == ZOO_CONNECTED_STATE \n               ) {\n                /* Should try to keep the cache in-sync, register call \n                 * callback again and get current children.\n                 */ \n                try {\n                    LOG_DEBUG(LOG, \"update children\");\n                    NodeNames children;\n                    _manager->getCommon().getZkAdapter()->\n                      getNodeChildren(children, _path, \n                                      &_childrenListener, _getZkContext());\n                    _hasChildrenListener = true;\n                    LOG_DEBUG(LOG, \"update children done\");\n                    _children.swap(children);\n                    _deleted = false;\n                } catch (const ZooKeeperException & e) {\n                    if (e.getZKErrorCode() == ZNONODE) {\n                        _deleted = true;\n                        _clearChildren();\n                    }\n                    LOG_ERROR(LOG, \"childrenEventReceived %s exception %s\", \n                              _path.c_str(), e.what());\n                    _children.clear();\n                }\n            }\n        }\n        LOG_DEBUG(LOG, \"childrenEventReceived returns %d\", reclaim);\n    }\n    /**\n      Truncate or expand the size of the cached active data.\n\n      This method only changes the size of the cached active data. \n      This change is committed to ZooKeeper when the cached data \n      is written to the ZooKeeper node by flush().\n\n      Return -EFBIG is the requested size exceeds the maximum.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param size the requested size.\n     */\n    int truncate(off_t size) \n    {\n        int res = 0;\n\n        {\n            AutoLock lock(_mutex); \n            res = _truncate(size);\n        }\n\n        return res;\n    }\n    /**\n      Copy range of active data into specified output buffer.\n\n      \\return if successful, return number of bytes copied, otherwise\n              return negative errno.\n      \\param buf  address of the output buffer.\n      \\param size size of the output buffer and desired number of bytes to copy.\n      \\param offset offset into active data to start copying from.\n     */\n    int read(char *buf, size_t size, off_t offset) const\n    {\n        LOG_DEBUG(LOG, \"read(size %zu, off_t %zu) path %s\", \n                  size, offset, _path.c_str());\n\n        int res = 0;\n\n        {\n            AutoLock lock(_mutex);\n            if (!_initializedData) {\n                LOG_DEBUG(LOG, \"not initialized\");\n                res = -EIO;\n            }\n            else {\n                off_t fileSize = _activeData.size();\n                if (offset > fileSize) {\n                    LOG_DEBUG(LOG, \"offset > fileSize %zu\", fileSize);\n                    res = 0;\n                } \n                else {\n                    if (offset + size > fileSize) {\n                        size = fileSize - offset;\n                        LOG_DEBUG(LOG, \n                                  \"reducing read size to %zu for fileSize %zu\",\n                                  size, fileSize);\n                    }\n                    copy(_activeData.begin() + offset,\n                         _activeData.begin() + offset + size,\n                         buf);\n                    res = size;\n                }\n            }\n        }\n\n        LOG_DEBUG(LOG, \"read returns %d\", res);\n        return res; \n    }\n    /**\n      Copy buffer content to active data.\n\n      \\return if successful, return number of bytes copied, otherwise\n              return negative errno.\n      \\param buf  address of the buffer.\n      \\param size size of the input buffer and desired number of bytes to copy.\n      \\param offset offset into active data to start copying to.\n     */\n    int write(const char *buf, size_t size, off_t offset)\n    {\n        LOG_DEBUG(LOG, \"write(size %zu, off_t %zu) path %s\", \n                  size, offset, _path.c_str());\n\n        int res = 0;\n\n        {\n            AutoLock lock(_mutex);\n            if (!_initializedData) {\n                LOG_DEBUG(LOG, \"not initialized\");\n                res = -EIO;\n            }\n            else if (offset >= maxDataFileSize) {\n                LOG_DEBUG(LOG, \"offset > maxDataFileSize %u\", maxDataFileSize);\n                res = -ENOSPC;\n            }\n            else {\n                if (offset + size > maxDataFileSize) {\n                    LOG_DEBUG(LOG, \n                              \"reducing write size to %zu \"\n                              \"for maxDataFileSize %u\",\n                              size, maxDataFileSize);\n                    size = maxDataFileSize - offset;\n                }\n                off_t fileSize = _activeData.size();\n                if (offset + size > fileSize) {\n                    LOG_DEBUG(LOG, \"resizing to %zu\", offset + size);\n                    _activeData.resize(offset + size);\n                } \n                copy(buf, buf + size, _activeData.begin() + offset);\n                memcpy(&_activeData[offset], buf, size);\n                _dirtyData = true;\n                res = size;\n            }\n        }\n\n        LOG_DEBUG(LOG, \"write returns %d\", res);\n        return res; \n    }\n    /**\n      Flush data to the ZooKeeper node.\n\n      If cached active data has been modified, flush it to the ZooKeeper node.\n      Returns -EIO if the data cannot be written because the cached active\n      data is not the expected version, i.e. ZooKeeper returns ZBADVERSION.\n      -EIO may also indicate a more general failure, such as unable to \n      communicate with ZooKeeper.\n\n      \\return 0 if successful, otherwise negative errno.\n     */\n    int flush()\n    {\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            res = _flush();\n        }\n        return res;\n    }\n    /**\n      Close of the ZkFuse regular file represented by the ZkFuseFile instance.\n\n      This may: \n      - Flush dirty data to the ZooKeeper node, and return the result of the\n        flush operation.\n      - Reclaim the ZkFuseFile instance. \n        \\see ZkFuseHandleManaer::reclaimIfNecessary\n\n      \\return result of flush operation - 0 if successful, \n              otherwise negative errno.\n     */\n    int close()\n    {\n        LOG_DEBUG(LOG, \"close() path %s\", _path.c_str());\n        int res = 0;\n\n        bool reclaim = false;\n        {\n            AutoLock lock(_mutex);\n            res = _flush();\n            if (_deleted) {\n                _clearData();\n                _clearChildren();\n            }\n        }\n        _manager->deallocate(_handle);\n\n        LOG_DEBUG(LOG, \"close returns %d\", res);\n        return res;\n    }\n    /**\n      Get ZkFuse regular file or directory attributes.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param stbuf return attributes here.\n      \\param nameType specifies the ZkFuseNameType of the ZkFuse path used\n                      to get attributes. It influences whether the directory\n                      or regular file attributes are returned.\n     */\n    int getattr(struct stat & stbuf, ZkFuseNameType nameType) const\n    {\n        LOG_DEBUG(LOG, \"getattr(nameType %d) path %s\", \n                  int(nameType), _path.c_str());\n\n        int res = 0;\n        int version = 0;\n        std::string metaPath;\n        {\n            AutoLock lock(_mutex);\n\n            res = _getattrNoMetaAccess(stbuf, nameType);\n            if (res == 0) {\n                version = _activeStat.version;\n                metaPath = _getChildPath( \n                    ((stbuf.st_mode & S_IFMT) == S_IFREG) ? \n                    _manager->getCommon().getRegMetadataName() :\n                    _manager->getCommon().getDirMetadataName());\n                if (_hasChildPath(metaPath) == false) {\n                    metaPath.clear();\n                }\n            }\n        }\n        if (res == 0 && metaPath.empty() == false) {\n            Data data;\n            int metaRes = _manager->getData(metaPath, data);\n            LOG_DEBUG(LOG, \"metaRes %d dataSize %zu\",\n                      metaRes, data.size());\n            if (metaRes == 0 && data.empty() == false) {\n                 Metadata metadata; \n                 _decodeMetadata(data, metadata);\n                 LOG_DEBUG(LOG, \"metadata version %u active version %u\",\n                           metadata.version, version);\n                 if (metadata.version == version) {\n                     /* IMPORTANT: \n                      * Must convert from millisecs to secs before setting\n                      * st_atime and st_mtime to avoid truncation error\n                      * due to 64-bit to 32-bit conversion.\n                      */\n                     stbuf.st_atime = millisecsToSecs(metadata.atime);\n                     stbuf.st_mtime = millisecsToSecs(metadata.mtime);\n                }\n            }\n        }\n    \n        LOG_DEBUG(LOG, \"getattr returns %d\", res);\n        return res;\n    }\n    /**\n      Read directory entries.\n      This interface is defined by FUSE.\n      \n      \\return 0 if successful, otherwise negative errno.\n      \\param buf output buffer to store output directory entries.\n      \\param filler function used to fill the output buffer.\n      \\param offset start filling from a specific offset.\n     */\n    int readdir(void *buf, fuse_fill_dir_t filler, off_t offset) const\n    {\n        LOG_DEBUG(LOG, \"readdir(offset %zu) path %s\", offset, _path.c_str());\n        int res = 0;\n\n        int dataFileIndex = -1;\n        unsigned leftTrim = 0;\n        typedef std::pair<std::string, int> DirEntry;\n        typedef std::vector<DirEntry> DirEntries; \n        DirEntries dirEntries;\n\n        /* Get directory entries in two phase to avoid invoking\n         * ZkFuseHandleManager while holding _mutex.\n         * In first phase, get all the names of child nodes starting\n         * at offset. Also remember their index for use in second phase.\n         * The first phase hold _mutex.\n         */\n        {\n            AutoLock lock(_mutex);\n            if (!_isInitialized()) {\n                LOG_DEBUG(LOG, \"not initialized\");\n                res = -EIO;\n            }\n            else {\n                leftTrim = (_path.length() == 1 ? 1 : _path.length() + 1);\n                unsigned start = offset;\n                unsigned i;\n                for (i = start; i < _children.size(); i++) { \n                    const std::string & childName = _children[i];\n                    if (_isMeta(childName)) {\n                        continue;\n                    }\n                    dirEntries.push_back(DirEntry(childName, i));\n                }\n                if (i == _children.size() && !_activeData.empty()) {\n                    dataFileIndex = i + 1;\n                }\n                res = 0;\n            }\n        }\n        \n        /* Second phase starts here.\n         * DONOT hold _mutex as this phase invokes ZkFuseHandleManager to\n         * get attributes for the directory entries.\n         */ \n        if (res == 0) {\n            bool full = false;\n            for (DirEntries::const_iterator it = dirEntries.begin();\n                it != dirEntries.end();\n                it++) {\n               \n                ZkFuseAutoHandle childAutoHandle(_manager, it->first);\n                int childRes = childAutoHandle.get();\n                if (childRes >= 0) {\n                    struct stat stbuf; \n                    int attrRes = childAutoHandle.getFile()->\n                        getattr(stbuf, ZkFuseNameDefaultType);\n                    if (attrRes == 0) {\n                        if (filler(buf, it->first.c_str() + leftTrim, \n                                   &stbuf, it->second + 1)) {\n                            LOG_DEBUG(LOG, \"filler full\");\n                            full = true;\n                            break;\n                        } \n                    }\n                }\n            } \n            if (full == false && dataFileIndex != -1) { \n                LOG_DEBUG(LOG, \"include data file name\");\n                struct stat stbuf; \n                int attrRes = getattr(stbuf, ZkFuseNameRegType); \n                if (attrRes == 0) {\n                    filler(buf, \n                           _manager->getCommon().getDataFileName().c_str(), \n                           &stbuf, dataFileIndex + 1);\n                }\n            }\n        }\n    \n        LOG_DEBUG(LOG, \"readdir returns %d\", res);\n        return res;\n    }\n    /**\n      Set the access time and modified time.\n\n      Set the access and modifieds times on the ZkFuse regular file\n      or directory represented by this ZkFuseFile instance.\n      \n      Since there is no interface to change these times on a \n      ZooKeeper node, ZkFuse simulates this by writing to a \n      metadata node which is a child node of the ZooKeeper node.\n      ZkFuse writes the current version, the specified access \n      and modified times to the metadata node. \n      \n      When get attributes is invoked, get attributes will check \n      for the presence of this metadata node and if the version\n      number matches the current data version, then get attributes\n      will return the access and modified times stored in the \n      metadata node.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param atime access time in milliseconds.\n      \\param mtime modified time in milliseconds.\n      \\param nameType specifies the ZkFuseNameType of the ZkFuse path used\n                      to set access and modified times. It influences \n                      whether the directory or regular file access and\n                      modified times are set.\n     */\n    int utime(uint64_t atime, uint64_t mtime, ZkFuseNameType nameType) \n    {\n        LOG_DEBUG(LOG, \n                  \"utime(atime %llu, mtime %llu, nameType %d) path %s\",\n                  (unsigned long long) atime, \n                  (unsigned long long) mtime, \n                  (int) nameType, _path.c_str());\n\n        int res = 0;\n        std::string metaPath;\n        bool exists = false;\n        Data data;\n        {\n            AutoLock lock(_mutex);\n    \n            if (!_isInitialized()) {\n                LOG_DEBUG(LOG, \"not initialized\");\n                res = -EIO;\n            }\n            else {\n                bool isRegular = _isRegNameType(nameType);\n                Metadata metadata;\n                metadata.version = _activeStat.version;\n                metadata.atime = atime;\n                metadata.mtime = mtime;\n                metaPath = _getChildPath( \n                    isRegular ?  \n                    _manager->getCommon().getRegMetadataName() :\n                    _manager->getCommon().getDirMetadataName());\n                exists = _hasChildPath(metaPath);\n                _encodeMetadata(metadata, data);\n                res = 0;\n            }\n        }\n        if (res == 0 && metaPath.empty() == false) { \n            res = _manager->setData(metaPath, data, exists, true);\n        }\n\n        LOG_DEBUG(LOG, \"utime returns %d\", res);\n        return res;\n    }\n    /**\n      Remove a ZkFuse directory.\n\n      If force is true, then the ZooKeeper node and its decendants\n      will be deleted.\n\n      If force is false, then this method implements the semantics\n      of removing a ZkFuse directory. It will delete the ZooKeeper node\n      only if the ZooKeeper node have no data and no non-metadata \n      children.\n      - Return -ENOTDIR if the ZooKeeper node is not considered\n        to be a directory (after taking into consideration the specified\n        ZkFuseNameType). \n      - Return -ENOTEMPTY if the ZooKeeper node has data or it has \n        non-metadata children.\n      - Return -ENOENT if the ZooKeeper cannot be deleted, usually this\n        is because it does not exist.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param nameType the ZkFuseNameType of the path used to specify the\n                      directory to be removed. It influences whether ZkFuse\n                      considers the ZooKeeper node to be a regular file or\n                      directory. \\see ZkFuseNameType\n      \\param force    set to true to bypass ZkFuse rmdir semantic check.\n     */\n    int rmdir(ZkFuseNameType nameType, bool force)\n    {\n        int res = 0;\n\n        {\n            AutoLock lock(_mutex);\n            res = _rmdir(nameType, force);\n        }\n        if (res == 0) {\n            _manager->removeChildFromParent(_path);\n        }\n        return res;\n    }\n    /**\n      Remove a ZkFuse regular file.\n\n      This method implements the semantics of removing a ZkFuse regular file.\n      - If the ZkFuse regular file represents the data part of the \n        ZooKeeper node which is presented as a ZkFuse directory, \n        the regular file is virtually deleted by truncating the\n        ZooKeeper node's data. Readdir will not synthesize a regular \n        file entry for the data part of a ZooKeeper node if \n        the ZooKeeper node has no data.\n      - If the ZkFuse regular file represents the data part of the \n        ZooKeeper node which is presented as a ZkFuse regular file,\n        the ZooKeeper node and its decendants are deleted.\n\n      Returns -EISDIR if the ZkFuse regular file cannot be deleted\n      because ZkFuse consider it to be a directory.\n\n      \\return 0 if successful, otherwise negative errno.\n      \\param nameType the ZkFuseNameType of the path used to specify the\n                      directory to be removed. It influences whether ZkFuse\n                      considers the ZooKeeper node to be a regular file or\n                      directory. \\see ZkFuseNameType\n    */\n    int unlink(ZkFuseNameType nameType) \n    {\n        int res = 0;\n        {\n            AutoLock lock(_mutex);\n            res = _unlink(nameType);\n        }\n        if (res == 0) {\n            _manager->removeChildFromParent(_path);\n        }\n        return res;\n    }\n    /**\n      Utility function to construct a ZooKeeper path for a child\n      of a ZooKeeper node.\n      \n      \\return the full path of the child.\n      \\param  parent the parent's full path.\n      \\param  child  the child's parent component.\n     */\n    static std::string buildChildPath(const std::string & parent,\n                                      const std::string & child)\n    {\n        std::string s;\n        s.reserve(parent.length() + child.length() + 32);\n        if (parent.length() > 1) {\n            // special case for root dir\n            s += parent;\n        }\n        s += \"/\";\n        s += child;\n        return s;\n    }\n};\n\nZkFuseFile::DataListener ZkFuseFile::_dataListener;\nZkFuseFile::ChildrenListener ZkFuseFile::_childrenListener;\n\nvoid ZkFuseAutoHandle::reset(int handle)\n{\n    int old = _handle;\n    ZkFuseFilePtr oldFile = _file;\n    _handle = handle;\n    _initFile();\n    if (old >= 0) {\n        assert(oldFile != NULL);\n        oldFile->close();\n    }\n}\n\nZkFuseHandleManager::Handle \nZkFuseHandleManager::allocate(const std::string & path, bool & newFile)\n{\n    LOG_DEBUG(LOG, \"allocate(path %s)\", path.c_str());\n\n    Handle handle;\n    {\n        AutoLock lock(_mutex);\n        Map::iterator it = _map.find(path);\n        if (it == _map.end()) {\n            LOG_DEBUG(LOG, \"not found\");\n            if (_freeList.empty()) {\n                handle = _files.size();\n                _files.resize(handle + 1);\n                LOG_DEBUG(LOG, \"free list empty, resize handle %d\", handle);\n            } else {\n                handle = _freeList.back();\n                _freeList.pop_back();\n                LOG_DEBUG(LOG, \"get from free list, handle %d\", handle);\n            }\n            assert(_files[handle] == NULL);\n            _files[handle] = \n                new ZkFuseFile(SharedPtr(_thisWeakPtr), handle, path);\n            /* Not really supposed to invoke the new ZkFuseFile instance \n             * because this method is not supposed to invoke ZkFuseFile\n             * methods that while holding _mutex. However, it is safe\n             * to do without casuing deadlock because these methods\n             * are known not to invoke other methods, especially one\n             * that invoke this ZkFuseHandleManager instance.\n             */\n            assert(_files[handle]->incRefCount(0) == 1);\n            _map[path] = handle;\n            _numInUse++;\n            LOG_DEBUG(LOG, \"numInUse %u\", _numInUse);\n            newFile = true;\n        } else {\n            LOG_DEBUG(LOG, \"found\");\n            handle = it->second;\n            assert(_files[handle] != NULL);\n            int refCount = _files[handle]->incRefCount();\n            if (refCount == 1) {\n                _numInUse++;\n                LOG_DEBUG(LOG, \"resurrecting zombie, numInUse %u\", _numInUse);\n            }\n            newFile = false;\n        }\n    }\n\n    LOG_DEBUG(LOG, \"allocate returns %d, newFile %d\", handle, newFile);\n    return handle;\n}\n\nvoid ZkFuseHandleManager::deallocate(Handle handle) \n{\n    LOG_DEBUG(LOG, \"deallocate(handle %d)\", handle);\n\n    if (handle >= 0) {\n        bool reclaim = false;\n        ZkFuseFilePtr file; \n        {\n            AutoLock lock(_mutex);\n            file = _files[handle];\n            assert(file != NULL);\n            int refCount = file->decRefCount();\n            const std::string & path = file->getPath();\n            LOG_DEBUG(LOG, \"path %s ref count %d\", path.c_str(), refCount);\n            if (refCount == 0) {\n                _numInUse--;\n                unsigned numCached = _files.size() - _numInUse;\n                if (numCached > _common.getCacheSize()) {\n                   LOG_TRACE(LOG, \n                             \"reclaim path %s, cacheSize %u, filesSize %zu, \"\n                             \"numInUse %u\", \n                             path.c_str(),\n                             _common.getCacheSize(), _files.size(), _numInUse);\n                   _map.erase(path); \n                   _files[handle] = NULL;\n                   _freeList.push_back(handle); \n                   reclaim = true;\n                }\n            }\n        } \n        if (reclaim) {\n            delete file;\n        }\n    }\n    else {\n        LOG_DEBUG(LOG, \"handle invalid\");\n    }\n\n    LOG_DEBUG(LOG, \"deallocate done\");\n}\n\nvoid ZkFuseHandleManager::eventReceived(const ZKWatcherEvent & event)\n{\n    int eventType = event.getType();\n    int eventState = event.getState();\n    const std::string & path = event.getPath();\n    LOG_DEBUG(LOG, \"eventReceived() eventType %d, eventState %d, path %s\",\n              eventType, eventState, path.c_str());\n\n    if (eventType == ZOO_DELETED_EVENT ||\n        eventType == ZOO_CHANGED_EVENT ||\n        eventType == ZOO_CHILD_EVENT) {\n        {\n            AutoLock lock(_mutex);\n            Map::iterator it = _map.find(path);\n            if (it != _map.end()) {\n                LOG_DEBUG(LOG, \"path found\");\n                Handle handle = it->second;\n                ZkFuseFilePtr file = _files[handle];\n                assert(file != NULL);\n                /* Prevent the ZkFuseFile instance from being\n                 * deleted while handling the event.\n                 */\n                int refCount = file->incRefCount();\n                if (refCount == 1) {\n                    _numInUse++;\n                }\n                /* Pretent to be dir open.\n                 */\n                int dirCount = file->incOpenDirCount();\n                {\n                    /* _mutex is unlocked in this scope */\n                    AutoUnlockTemp autoUnlockTemp(lock);\n                    if (eventType == ZOO_CHILD_EVENT) {\n                        file->childrenEventReceived(event);\n                    }\n                    else if (eventType == ZOO_CHANGED_EVENT) {\n                        file->dataEventReceived(event);\n                    }\n                    else {\n                        assert(eventType == ZOO_DELETED_EVENT);\n                        file->dataEventReceived(event);\n                        // file->childrenEventReceived(event);\n                    }\n                    file->decOpenDirCount();\n                    deallocate(handle);\n                }\n            }\n            else {\n                LOG_WARN(LOG, \n                         \"path %s not found for event type %d, event state %d\",\n                          path.c_str(), eventType, eventState);\n            }\n        }\n    } \n    else if (eventType == ZOO_SESSION_EVENT) {\n        if (eventState == ZOO_CONNECTING_STATE) {\n            LOG_TRACE(LOG, \"*** CONNECTING ***\");\n            {\n                AutoLock lock(_mutex);\n                for (int handle = 0; handle < _files.size(); handle++) { \n                    ZkFuseFilePtr file = _files[handle];\n                    if (file != NULL) {\n                        /* prevent the ZkFuseFile instance from being \n                         * deleted while handling the event. \n                         */\n                        int refCount = file->incRefCount();\n                        if (refCount == 1) {\n                             _numInUse++;\n                        }\n                        /* Pretent to be dir open.\n                         */ \n                        int dirCount = file->incOpenDirCount();\n                        {\n                            /* _mutex is unlocked in this scope */\n                            AutoUnlockTemp autoUnlockTemp(lock);\n                            file->dataEventReceived(event);\n                            file->childrenEventReceived(event);\n                            file->decOpenDirCount();\n                            deallocate(handle);\n                        }\n                        /* this will eventually call decrement ref count */\n                    }\n                }\n            }\n        }\n        else if (eventState == ZOO_CONNECTED_STATE) {\n            LOG_TRACE(LOG, \"*** CONNECTED ***\");\n        }\n    }\n    else {\n        LOG_WARN(LOG, \n                 \"eventReceived ignoring event type %d, event state %d, \"\n                 \"path %s\", eventType, eventState, path.c_str());\n    }\n}\n\nint ZkFuseHandleManager::getData(const std::string & path, \n                                 Data & data) \n{\n    LOG_DEBUG(LOG, \"getData(path %s)\", path.c_str());\n\n    int res = 0;\n    data.clear();\n    ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), path);\n    res = autoHandle.get();\n    if (res >= 0) {\n        autoHandle.getFile()->getData(data);\n        res = 0;\n    }\n\n    LOG_DEBUG(LOG, \"getData returns %d\", res);\n    return res;\n}\n\nint ZkFuseHandleManager::setData(const std::string & path, \n                                 const Data & data, \n                                 bool exists, \n                                 bool doFlush) \n{\n    LOG_DEBUG(LOG, \"setData(path %s, exists %d)\\n%s\", \n              path.c_str(), exists, data.c_str());\n\n    int res = 0;\n    if (exists) {\n        res = open(path, false);\n    } else {\n        bool created;\n        res = mknod(path, S_IFREG, true, created);\n    }\n    if (res >= 0) {\n        ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), res);\n        res = autoHandle.getFile()->setData(data, doFlush);\n    }\n\n    LOG_DEBUG(LOG, \"setData returns %d\", res);\n    return res;\n}\n\nint ZkFuseHandleManager::mknod(const std::string & path, \n                               mode_t mode, \n                               bool mayExist,\n                               bool & created)\n{\n    LOG_DEBUG(LOG, \"mknod(path %s, mode %o, mayExist %d)\", \n              path.c_str(), mode, mayExist);\n\n    int res = 0;\n    created = false;\n    try {\n        if (S_ISREG(mode) == false && S_ISDIR(mode) == false) {\n            LOG_DEBUG(LOG, \"bad mode %o\", mode);\n            res = -EINVAL;\n        } \n        else {\n            Data data;\n            LOG_DEBUG(LOG, \"create %s\", path.c_str());\n            created = \n                _common.getZkAdapter()->createNode(path, data, 0, false);\n            if (created) {\n                LOG_DEBUG(LOG, \"created\");\n                if (S_ISDIR(mode)) {\n                    /* is mkdir - create directory marker */\n                    std::string dirMetaPath = ZkFuseFile::buildChildPath\n                        (path, _common.getDirMetadataName());\n                    LOG_DEBUG(LOG, \"create %s\", dirMetaPath.c_str());\n                    bool created;\n                    int metaRes = mknod(dirMetaPath, S_IFREG, true, created);\n                    if (metaRes >= 0) {\n                        getFile(metaRes)->close();\n                    }\n                }\n                addChildToParent(path);\n                LOG_DEBUG(LOG, \"open after create\");\n                res = open(path, true);\n            } else {\n                LOG_DEBUG(LOG, \"create failed\");\n                int openRes = open(path, false);\n                if (openRes >= 0) {\n                    if (mayExist == false) {\n                        LOG_DEBUG(LOG, \"create failed because already exist\");\n                        getFile(openRes)->close();\n                        res = -EEXIST;\n                    } else {\n                        res = openRes;\n                    }\n                } else {\n                    LOG_DEBUG(LOG, \"create failed but does not exist\");\n                    res = -ENOENT;\n                }\n            }\n        }\n    } catch (const ZooKeeperException & e) {\n        LOG_ERROR(LOG, \"mknod %s exception %s\", path.c_str(), e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"mknod returns %d created %d\", res, created);\n    return res;\n}\n\nint ZkFuseHandleManager::mkdir(const char * path, mode_t mode)\n{\n    LOG_DEBUG(LOG, \"mkdir(path %s, mode %o)\", path, mode);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = getZkPath(path, nameType);\n        mode = (mode & ~S_IFMT) | S_IFDIR;\n        ZkFuseAutoHandle autoHandle\n            (SharedPtr(_thisWeakPtr), zkPath, mode, false);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = 0;\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"mkdir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"mkdir returns %d\", res);\n    return res;\n}\n\nint ZkFuseHandleManager::open(const std::string & path, bool justCreated)\n{\n    LOG_DEBUG(LOG, \"open(path %s, justCreated %d)\", \n              path.c_str(), justCreated);\n\n    int res = 0;\n    try {\n        bool newFile;\n        Handle handle = allocate(path, newFile);\n        ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), handle);\n        res = getFile(handle)->update(newFile || justCreated);\n        if (res == 0) {\n            res = handle;\n            autoHandle.release();\n        }\n    } catch (const ZooKeeperException & e) {\n        LOG_ERROR(LOG, \"open %s exception %s\", path.c_str(), e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"open returns %d\", res);\n    return res;\n}\n\nint ZkFuseHandleManager::rmdir(const char * path, bool force)\n{\n    LOG_DEBUG(LOG, \"rmdir(path %s, force %d)\", path, force);\n\n    int res = 0;\n\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), zkPath);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = autoHandle.getFile()->rmdir(nameType, force);\n        } \n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"rmdir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"rmdir returns %d\", res);\n    return res;\n}\n\n\nint \nZkFuseHandleManager::unlink(const char * path)\n{\n    LOG_DEBUG(LOG, \"unlink(path %s)\", path);\n\n    ZkFuseNameType nameType;\n    std::string zkPath = getZkPath(path, nameType);\n    ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), zkPath);\n    int res = autoHandle.get();\n    if (res >= 0) {\n        res = autoHandle.getFile()->unlink(nameType);\n    }\n\n    LOG_DEBUG(LOG, \"unlink returns %d\", res);\n    return res;\n}\n\nint ZkFuseHandleManager::getattr(const char *path, struct stat &stbuf)\n{\n    LOG_DEBUG(LOG, \"getattr(path %s)\", path);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(SharedPtr(_thisWeakPtr), zkPath);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = autoHandle.getFile()->getattr(stbuf, nameType);\n        } \n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"getattr %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"getattr returns %d\", res);\n    return res;\n}\n\nint \nZkFuseHandleManager::rename(const char * fromPath, const char * toPath)\n{\n    LOG_DEBUG(LOG, \"rename(fromPath %s, toPath %s)\", fromPath, toPath);\n\n    ZkFuseNameType fromNameType;\n    std::string fromZkPath = getZkPath(fromPath, fromNameType);\n    ZkFuseAutoHandle fromAutoHandle(SharedPtr(_thisWeakPtr), fromZkPath);\n    int res = fromAutoHandle.get();\n    if (res >= 0) {\n        LOG_DEBUG(LOG, \"good fromPath\");\n        if (fromAutoHandle.getFile()->isDirNameType(fromNameType)) {\n            LOG_DEBUG(LOG, \"fromPath is directory\");\n            res = -EISDIR;\n        }\n    }\n    if (res >= 0) {\n        ZkFuseNameType toNameType;\n        std::string toZkPath = getZkPath(toPath, toNameType);\n        bool created;\n        res = mknod(toZkPath.c_str(), S_IFREG, true, created);\n        if (res >= 0) {\n            ZkFuseAutoHandle toAutoHandle(SharedPtr(_thisWeakPtr), res);\n            if (toAutoHandle.getFile()->isDirNameType(toNameType)) {\n                LOG_DEBUG(LOG, \"toPath is directory\");\n                res = -EISDIR;\n            }\n            if (res >= 0) {\n                LOG_DEBUG(LOG, \"copy data\");\n                Data data; \n                fromAutoHandle.getFile()->getData(data);\n                toAutoHandle.getFile()->setData(data, true);\n                LOG_DEBUG(LOG, \"copy metadata\");\n                struct stat stbuf;\n                int metaRes = \n                    fromAutoHandle.getFile()->getattr(stbuf, fromNameType);\n                if (metaRes < 0) {\n                    LOG_DEBUG(LOG, \"get metadata failed\");\n                } \n                else {\n                    metaRes = toAutoHandle.getFile()->\n                        utime(secsToMillisecs(stbuf.st_atime),\n                              secsToMillisecs(stbuf.st_mtime),\n                              toNameType);\n                    if (metaRes < 0) {\n                        LOG_DEBUG(LOG, \"set metadata failed\");\n                    }\n                }\n            }\n            if (created && res < 0) {\n                LOG_DEBUG(LOG, \"undo create because copy data failed\");\n                int rmRes = toAutoHandle.getFile()->rmdir(toNameType, true);\n            }\n        }\n    }\n    if (res >= 0) {\n        LOG_DEBUG(LOG, \"copy successful, unlink fromPath\");\n        res = fromAutoHandle.getFile()->unlink(fromNameType);\n    }\n\n    LOG_DEBUG(LOG, \"rename returns %d\", res);\n    return res;\n}\n\nvoid\nZkFuseHandleManager::addChildToParent(const std::string & childPath) const\n{\n    LOG_DEBUG(LOG, \"addChildToParent(childPath %s)\", childPath.c_str());\n\n    std::string parentPath = getParentPath(childPath);\n    if (!parentPath.empty()) {\n        AutoLock lock(_mutex);\n        Map::const_iterator it = _map.find(parentPath);\n        if (it != _map.end()) {\n            Handle handle = it->second;\n            assert(_files[handle] != NULL);\n            _files[handle]->addChild(childPath);\n        } \n    }\n    \n    LOG_DEBUG(LOG, \"addChildToParent done\");\n}\n\nvoid\nZkFuseHandleManager::removeChildFromParent(const std::string & childPath) const\n{\n    LOG_DEBUG(LOG, \"removeChildFromParent(childPath %s)\", childPath.c_str());\n\n    std::string parentPath = getParentPath(childPath);\n    if (!parentPath.empty()) {\n        AutoLock lock(_mutex);\n        Map::const_iterator it = _map.find(parentPath);\n        if (it != _map.end()) {\n            Handle handle = it->second;\n            assert(_files[handle] != NULL);\n            _files[handle]->removeChild(childPath);\n        } \n    }\n    \n    LOG_DEBUG(LOG, \"removeChildFromParent done\");\n}\n\nstd::string\nZkFuseHandleManager::getParentPath(const std::string & childPath) const\n{\n    std::string::size_type lastPos = childPath.rfind('/');\n    if (lastPos > 0) {\n        return std::string(childPath, 0, lastPos);\n    }\n    else {\n        assert(childPath[0] == '/');\n        return std::string();\n    }\n}\n\nstd::string \nZkFuseHandleManager::getZkPath(const char * path, ZkFuseNameType & nameType)\n    const\n{\n    LOG_DEBUG(LOG, \"getZkPath(path %s)\", path);\n\n    std::string res;\n    unsigned pathLen = strlen(path);\n    const std::string & dataFileName = _common.getDataFileName();\n    unsigned dataSuffixLen = dataFileName.length();\n    const char * dataSuffix = dataFileName.c_str();\n    unsigned dataSuffixIncludeSlashLen = dataSuffixLen + 1;\n    const std::string & forceDirSuffix = _common.getForceDirSuffix();\n    unsigned forceDirSuffixLen = _common.getForceDirSuffix().length();\n    /* Check if path is \"/\". If so, it is always a directory.\n     */\n    if (pathLen == 1) {\n        assert(path[0] == '/');\n        res = _common.getRootPathName();\n        nameType = ZkFuseNameDirType;\n    }\n    /* Check if path ends of /{dataSuffix}, e.g. /foo/bar/{dataSuffix}.\n     * If so remove dataSuffix and nameType is ZkFuseNameRegType. \n     */\n    else if (\n        (pathLen >= dataSuffixIncludeSlashLen) && \n        (path[pathLen - dataSuffixIncludeSlashLen] == '/') &&\n        (strncmp(path + (pathLen - dataSuffixLen), \n                 dataSuffix, dataSuffixLen) == 0) \n       ) {\n        if ((pathLen - dataSuffixIncludeSlashLen) == 0) {\n            res = _common.getRootPathName();\n        } else { \n            res.assign(path, pathLen - dataSuffixIncludeSlashLen);\n        }\n        nameType = ZkFuseNameRegType;\n    }\n    /* If not ZkFuseNameRegType, then check if path ends of \n     * {forceDirSuffix}, e.g. /foo/bar{forceDirSuffix}.\n     * If so remove forceDirSuffix and nameType is ZkFuseNameDirType.\n     */\n    else if (forceDirSuffixLen > 0 &&\n        pathLen >= forceDirSuffixLen &&\n        strncmp(path + (pathLen - forceDirSuffixLen),\n                forceDirSuffix.c_str(), forceDirSuffixLen) == 0) {\n        res.assign(path, pathLen - forceDirSuffixLen);\n        nameType = ZkFuseNameDirType;\n    } \n    /* If not ZkFuseNameRegType and not ZkFuseNameDirType, then\n     * it is ZkFuseNameDefaultType. ZkFuse will infer type from\n     * ZooKeeper node's content.\n     */\n    else {\n        res = path;\n        nameType = ZkFuseNameDefaultType;\n    }\n    /* Intermediate components of the path name may have \n     * forceDirSuffix, e.g. /foo/bar{forceDirSuffix}/baz.\n     * If so, remove the intermediate {forceDirSuffix}es.\n     */\n    if (forceDirSuffixLen > 0) {\n        /* pos is an optimization to avoid always scanning from \n         * beginning of path\n         */\n        unsigned pos = 0;\n        while ((res.length() - pos) > forceDirSuffixLen + 1) {\n            const char * found = \n                strstr(res.c_str() + pos, forceDirSuffix.c_str());\n            if (found == NULL) {\n                break;\n            } \n            if (found[forceDirSuffixLen] == '/' ||\n                found[forceDirSuffixLen] == '\\0') {\n                pos = found - res.c_str();\n                res.erase(pos, forceDirSuffixLen);\n            }\n            else {\n                pos += forceDirSuffixLen;\n            }\n        }\n    }\n\n    LOG_DEBUG(LOG, \"getZkPath returns %s, nameType %d\", \n              res.c_str(), int(nameType));\n    return res;\n}\n\nstatic ZkFuseHandleManager::SharedPtr singletonZkFuseHandleManager;\n\ninline const ZkFuseHandleManager::SharedPtr & zkFuseHandleManager()\n{\n    return singletonZkFuseHandleManager;\n}\n\nstatic \nint zkfuse_getattr(const char *path, struct stat *stbuf)\n{\n    LOG_DEBUG(LOG, \"zkfuse_getattr(path %s)\", path);\n\n    int res = 0;\n    try {\n        res = zkFuseHandleManager()->getattr(path, *stbuf);\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_getattr %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_getattr returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_fgetattr(const char *path, struct stat *stbuf,\n\t            struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_fgetattr(path %s)\", path);\n\n    int res = 0;\n    int handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            res = zkFuseHandleManager()->getFile(handle)->\n                getattr(*stbuf, ZkFuseNameDefaultType);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_fgetattr %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_fgetattr returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_access(const char *path, int mask)\n{\n    /* not implemented */\n    return -1;\n}\n\nstatic \nint zkfuse_readlink(const char *path, char *buf, size_t size)\n{\n    /* not implemented */\n    return -1;\n}\n\nstatic \nint zkfuse_opendir(const char *path, struct fuse_file_info *fi)\n{ \n    LOG_DEBUG(LOG, \"zkfuse_opendir(path %s)\", path);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = zkFuseHandleManager()->getZkPath(path, nameType);\n        if (nameType == ZkFuseNameRegType) {\n            res = -ENOENT;\n        }\n        else {\n            ZkFuseAutoHandle autoHandle(zkFuseHandleManager(), zkPath);\n            res = autoHandle.get();\n            if (res >= 0) {\n                autoHandle.getFile()->incOpenDirCount();\n                autoHandle.release();\n                fi->fh = res;\n                res = 0;\n            }\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_opendir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_opendir returns %d\", res);\n    return res;\n}\n\nstatic int \nzkfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, \n               off_t offset, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_readdir(path %s, offset %zu)\", path, offset);\n\n    int res = 0;\n    int handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            res = zkFuseHandleManager()->getFile(handle)->\n                readdir(buf, filler, offset);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_readdir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_readdir returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_releasedir(const char *path, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_releasedir(path %s)\", path);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            zkFuseHandleManager()->getFile(handle)->decOpenDirCount();\n            zkFuseHandleManager()->getFile(handle)->close();\n        } \n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_releasedir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_releasedir returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_mknod(const char *path, mode_t mode, dev_t rdev)\n{\n    LOG_DEBUG(LOG, \"zkfuse_mknod(path %s, mode %o)\", path, mode);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = zkFuseHandleManager()->getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(zkFuseHandleManager(), zkPath, mode, false);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = 0;\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_mknod %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_mknod returns %d\", res);\n    return res;\n}\n\nstatic int zkfuse_mkdir(const char *path, mode_t mode)\n{\n    LOG_DEBUG(LOG, \"zkfuse_mkdir(path %s, mode %o\", path, mode);\n\n    int res = 0;\n    try {\n        res = zkFuseHandleManager()->mkdir(path, mode);\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_mkdir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_mkdir returns %d\", res);\n    return res;\n}\n\nstatic int zkfuse_unlink(const char *path)\n{\n    LOG_DEBUG(LOG, \"zkfuse_unlink(path %s)\", path);\n\n    int res = 0;\n    try {\n        res = zkFuseHandleManager()->unlink(path);\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_unlink %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_unlink returns %d\", res);\n    return res;\n}\n\nstatic int zkfuse_rmdir(const char *path)\n{\n    LOG_DEBUG(LOG, \"zkfuse_rmdir(path %s)\", path);\n\n    int res = 0;\n    try {\n        res = zkFuseHandleManager()->rmdir(path);\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_rmdir %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_rmdir returns %d\", res);\n\n    return res;\n}\n\nstatic int zkfuse_symlink(const char *from, const char *to)\n{\n    /* not implemented */\n    return -1;\n}\n\nstatic int zkfuse_rename(const char *from, const char *to)\n{\n    LOG_DEBUG(LOG, \"zkfuse_rename(from %s, to %s)\", from, to);\n\n    int res = 0;\n    try {\n        res = zkFuseHandleManager()->rename(from, to);\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_rename %s %s exception %s\", from, to, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_rename returns %d\", res);\n\n    return res;\n}\n\nstatic int zkfuse_link(const char *from, const char *to)\n{\n    /* not implemented */\n    return -1;\n}\n\nstatic int zkfuse_chmod(const char *path, mode_t mode)\n{\n    LOG_DEBUG(LOG, \"zkfuse_chmod(path %s, mode %o)\", path, mode);\n    int res = 0;\n\n    LOG_DEBUG(LOG, \"zkfuse_chmod returns %d\", res);\n    return res;\n}\n\nstatic int zkfuse_chown(const char *path, uid_t uid, gid_t gid)\n{\n    LOG_DEBUG(LOG, \"zkfuse_chown(path %s, uid %d, gid %d)\", path, uid, gid);\n\n    int res = 0;\n\n    if (zkFuseHandleManager()->getCommon().getUid() == uid &&\n        zkFuseHandleManager()->getCommon().getGid() == gid) {\n        res = 0;\n    }\n    else {\n        res = -EPERM;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_chown returns %d\", res);\n    return 0;\n}\n\nstatic int zkfuse_truncate(const char *path, off_t size)\n{\n    LOG_DEBUG(LOG, \"zkfuse_truncate(path %s, size %zu)\", path, size);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = zkFuseHandleManager()->getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(zkFuseHandleManager(), zkPath);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = autoHandle.getFile()->truncate(size);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_truncate %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_truncate returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_ftruncate(path %s, size %zu)\", path, size);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            res = zkFuseHandleManager()->getFile(handle)->truncate(size);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_ftruncate %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_ftruncate returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_utimens(const char *path, const struct timespec ts[2])\n{\n    LOG_DEBUG(LOG, \"zkfuse_utimens(path %s)\", path);\n\n    int res = 0;\n    try {\n        uint64_t atime = timespecToMillisecs(ts[0]);\n        uint64_t mtime = timespecToMillisecs(ts[1]);\n        ZkFuseNameType nameType;\n        std::string zkPath = zkFuseHandleManager()->getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(zkFuseHandleManager(), zkPath);\n        res = autoHandle.get();\n        if (res >= 0) {\n            res = autoHandle.getFile()->utime(atime, mtime, nameType);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_utimens %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_utimens returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_create(const char *path, mode_t mode, struct fuse_file_info *fi)\n{\n\tint fd;\n\n\tfd = open(path, fi->flags, mode);\n\tif (fd == -1)\n\t\treturn -errno;\n\n\tfi->fh = fd;\n\treturn 0;\n}\n\nstatic \nint zkfuse_open(const char *path, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_open(path %s, flags %o)\", path, fi->flags);\n\n    int res = 0;\n    try {\n        ZkFuseNameType nameType;\n        std::string zkPath = zkFuseHandleManager()->getZkPath(path, nameType);\n        ZkFuseAutoHandle autoHandle(zkFuseHandleManager(), zkPath);\n        res = autoHandle.get();\n        if (res >= 0) {\n            if (autoHandle.getFile()->isDirNameType(nameType)) {\n                res = -ENOENT;\n            }\n        } \n        if (res >= 0) {\n            autoHandle.release();\n            fi->fh = res;\n            res = 0;\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_open %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_open returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_read(const char *path, char *buf, size_t size, off_t offset,\n\t\tstruct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_read(path %s, size %zu, offset %zu)\", \n              path, size, offset);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            res = zkFuseHandleManager()->getFile(handle)-> \n                read(buf, size, offset);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_read %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_read returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_write(const char *path, const char *buf, size_t size,\n                 off_t offset, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_write(path %s, size %zu, offset %zu)\", \n              path, size, offset);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        } \n        else {\n            res = zkFuseHandleManager()->getFile(handle)-> \n                write(buf, size, offset);\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_write %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_write returns %d\", res);\n    return res;\n}\n\nstatic int zkfuse_statfs(const char *path, struct statvfs *stbuf)\n{\n    /* not implemented */\n    return -1;\n}\n\nstatic \nint zkfuse_flush(const char *path, struct fuse_file_info *fi)\n{\n    /* This is called from every close on an open file, so call the \n       close on the underlying filesystem. But since flush may be\n       called multiple times for an open file, this must not really\n       close the file.  This is important if used on a network \n       filesystem like NFS which flush the data/metadata on close() */\n\n    LOG_DEBUG(LOG, \"zkfuse_flush(path %s)\", path);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            res = zkFuseHandleManager()->getFile(handle)->flush();\n        }\n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_flush %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_flush returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_release(const char *path, struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_release(path %s)\", path);\n\n    int res = 0;\n    unsigned handle = fi->fh;\n    try {\n        if (handle <= 0) {\n            res = -EINVAL;\n        }\n        else {\n            zkFuseHandleManager()->getFile(handle)->close();\n        } \n    } catch (const std::exception & e) {\n        LOG_ERROR(LOG, \"zkfuse_release %s exception %s\", path, e.what());\n        res = -EIO;\n    }\n\n    LOG_DEBUG(LOG, \"zkfuse_release returns %d\", res);\n    return res;\n}\n\nstatic \nint zkfuse_fsync(const char *path, int isdatasync, \n                 struct fuse_file_info *fi)\n{\n    LOG_DEBUG(LOG, \"zkfuse_fsync(path %s, isdatasync %d)\", path, isdatasync);\n\n    (void) isdatasync;\n    int res = zkfuse_flush(path, fi);\n\n    LOG_DEBUG(LOG, \"zkfuse_fsync returns %d\", res);\n    return res;\n}\n\n#ifdef HAVE_SETXATTR\n/* xattr operations are optional and can safely be left unimplemented */\nstatic int zkfuse_setxattr(const char *path, const char *name, const char *value,\n\t\t\tsize_t size, int flags)\n{\n\tint res = lsetxattr(path, name, value, size, flags);\n\tif (res == -1)\n\t\treturn -errno;\n\treturn 0;\n}\n\nstatic int zkfuse_getxattr(const char *path, const char *name, char *value,\n\t\t\tsize_t size)\n{\n\tint res = lgetxattr(path, name, value, size);\n\tif (res == -1)\n\t\treturn -errno;\n\treturn res;\n}\n\nstatic int zkfuse_listxattr(const char *path, char *list, size_t size)\n{\n\tint res = llistxattr(path, list, size);\n\tif (res == -1)\n\t\treturn -errno;\n\treturn res;\n}\n\nstatic int zkfuse_removexattr(const char *path, const char *name)\n{\n\tint res = lremovexattr(path, name);\n\tif (res == -1)\n\t\treturn -errno;\n\treturn 0;\n}\n#endif /* HAVE_SETXATTR */\n\nstatic \nint zkfuse_lock(const char *path, struct fuse_file_info *fi, int cmd,\n                struct flock *lock)\n{ \n    (void) path;\n    return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,\n\t\t       sizeof(fi->lock_owner));\n}\n\n\nstatic \nvoid init_zkfuse_oper(fuse_operations & fo)\n{\n        memset(&fo, 0, sizeof(fuse_operations));\n\tfo.getattr = zkfuse_getattr;\n\tfo.fgetattr = zkfuse_fgetattr;\n\t// fo.access = zkfuse_access;\n\t// fo.readlink = zkfuse_readlink;\n\tfo.opendir = zkfuse_opendir;\n\tfo.readdir = zkfuse_readdir;\n\tfo.releasedir = zkfuse_releasedir;\n\tfo.mknod = zkfuse_mknod;\n\tfo.mkdir = zkfuse_mkdir;\n\t// fo.symlink = zkfuse_symlink;\n\tfo.unlink = zkfuse_unlink;\n\tfo.rmdir = zkfuse_rmdir;\n\tfo.rename = zkfuse_rename;\n\t// fo.link = zkfuse_link;\n\tfo.chmod = zkfuse_chmod;\n\tfo.chown = zkfuse_chown;\n\tfo.truncate = zkfuse_truncate;\n\tfo.ftruncate = zkfuse_ftruncate;\n\tfo.utimens = zkfuse_utimens;\n\t// fo.create = zkfuse_create;\n\tfo.open = zkfuse_open;\n\tfo.read = zkfuse_read;\n\tfo.write = zkfuse_write;\n\tfo.statfs = zkfuse_statfs;\n\tfo.flush = zkfuse_flush;\n\tfo.release = zkfuse_release;\n\tfo.fsync = zkfuse_fsync;\n#ifdef HAVE_SETXATTR\n\t// fo.setxattr = zkfuse_setxattr;\n\t// fo.getxattr = zkfuse_getxattr;\n\t// fo.listxattr = zkfuse_listxattr;\n\t// fo.removexattr = zkfuse_removexattr;\n#endif\n\tfo.lock = zkfuse_lock;\n};\n\n\n/**\n * The listener of ZK events.\n */\nclass SessionEventListener : public ZKEventListener \n{\n  private:\n    /** \n      References the ZkFuseHandleManager instance that should be\n      invoked to service events.\n     */\n    ZkFuseHandleManager::SharedPtr _manager;\n\n  public:\n    /**\n      Sets the ZkFuseHandleManager instance that should be invoked\n      to service events.\n     */\n    void setManager(const ZkFuseHandleManager::SharedPtr & manager) \n    {\n        _manager = manager;\n    }\n    /**\n      Received an event and invoke ZkFuseHandleManager instance to handle\n      received event.\n     */\n    virtual void eventReceived(const ZKEventSource & source,\n                               const ZKWatcherEvent & event)\n    {\n        _manager->eventReceived(event);\n    }\n};\n\nvoid \nusage(int argc, char *argv[])\n{\n    cout \n        << argv[0] \n        << \" usage: \" \n        << argv[0] \n        << \" [args-and-values]+\" << endl\n        << \"nodepath == a complete path to a ZooKeeper node\" << endl\n        << \"\\t--cachesize=<cachesize> or -c <cachesize>:\" << endl\n        << \"    number of ZooKeeper nodes to cache.\" << endl\n        << \"\\t--debug or -d: \" << endl\n        << \"\\t  enable fuse debug mode.\" << endl\n        << \"\\t--help or -h: \" << endl\n        << \"\\t  print this message.\" << endl\n        << \"\\t--mount=<mountpoint> or -m <mountpoint>: \" << endl\n        << \"\\t  specifies where to mount the zkfuse filesystem.\" << endl\n        << \"\\t--name or -n: \" << endl\n        << \"\\t  name of file for accessing node data.\" << endl\n        << \"\\t--zookeeper=<hostspec> or -z <hostspec>: \" << endl\n        << \"\\t  specifies information needed to connect to zeekeeper.\" << endl;\n}\n\nint \nmain(int argc, char *argv[])\n{\n    /**\n     * Initialize log4cxx \n     */\n    const std::string file(\"log4cxx.properties\");\n    PropertyConfigurator::configureAndWatch( file, 5000 );\n    LOG_INFO(LOG, \"Starting zkfuse\");\n\n    /**\n     * Supported operations.\n     */\n    enum ZkOption {\n        ZkOptionCacheSize = 1000,\n        ZkOptionDebug = 1001,\n        ZkOptionForceDirSuffix = 1002,\n        ZkOptionHelp = 1003,\n        ZkOptionMount = 1004,\n        ZkOptionName = 1005,\n        ZkOptionZookeeper = 1006,\n        ZkOptionInvalid = -1\n    };\n    \n    static const char *shortOptions = \"c:df:hm:n:z:\";\n    static struct option longOptions[] = {\n        { \"cachesize\", 1, 0, ZkOptionCacheSize },\n        { \"debug\", 0, 0, ZkOptionDebug },\n        { \"forcedirsuffix\", 1, 0, ZkOptionForceDirSuffix },\n        { \"help\", 0, 0, ZkOptionHelp },\n        { \"mount\", 1, 0, ZkOptionMount },\n        { \"name\", 1, 0, ZkOptionName },\n        { \"zookeeper\", 1, 0, ZkOptionZookeeper },\n        { 0, 0, 0, 0 }\n    };\n    \n    /**\n     * Parse arguments \n     */\n    bool debugFlag = false;\n    std::string mountPoint = \"/tmp/zkfuse\";\n    std::string nameOfFile = \"_data_\";\n    std::string forceDirSuffix = \"._dir_\";\n    std::string zkHost;\n    unsigned cacheSize = 256;\n\n    while (true) {\n        int c;\n\n        c = getopt_long(argc, argv, shortOptions, longOptions, 0);\n        if (c == -1) {\n            break;\n        }\n\n        switch (c) {\n          case ZkOptionInvalid:\n            cerr \n                << argv[0]\n                << \": ERROR: Did not specify legal argument!\"\n                << endl;\n            return 99;\n          case 'c':\n          case ZkOptionCacheSize:\n            cacheSize = strtoul(optarg, NULL, 0);\n            break;\n          case 'd':\n          case ZkOptionDebug:\n            debugFlag = true;\n            break;\n          case 'f':\n          case ZkOptionForceDirSuffix:\n            forceDirSuffix = optarg;\n            break;\n          case 'h':\n          case ZkOptionHelp: \n            usage(argc, argv);\n            return 0;\n          case 'm':\n          case ZkOptionMount:\n            mountPoint = optarg;\n            break;\n          case 'n':\n          case ZkOptionName:\n            nameOfFile = optarg;\n            break;\n          case 'z':\n          case ZkOptionZookeeper:\n            zkHost = optarg;\n            break;\n        }\n    }\n\n    /**\n     * Check that zkHost has a value, otherwise abort.\n     */\n    if (zkHost.empty()) {\n        cerr \n            << argv[0] \n            << \": ERROR: \" \n            << \"required argument \\\"--zookeeper <hostspec>\\\" was not given!\"\n            << endl;\n        return 99;\n    }\n    /**\n     * Check that zkHost has a value, otherwise abort.\n     */\n    if (forceDirSuffix.empty()) {\n        cerr \n            << argv[0] \n            << \": ERROR: \" \n            << \"required argument \\\"--forcedirsuffix <suffix>\\\" \" \n               \"not cannot be empty!\"\n            << endl;\n        return 99;\n    }\n    /**\n     * Check nameOfFile has no forward slash\n     */\n    if (nameOfFile.find_first_of('/') != std::string::npos) {\n        cerr \n            << argv[0] \n            << \": ERROR: \" \n            << \"'/' present in name which is not allowed\"\n            << endl;\n        return 99;\n    }\n\n    if (debugFlag) {\n        cout\n            << \"cacheSize = \" \n            << cacheSize  \n            << \", debug = \"\n            << debugFlag \n            << \", forceDirSuffix = \\\"\"\n            << forceDirSuffix\n            << \"\\\", mount = \\\"\"\n            << mountPoint\n            << \"\\\", name = \\\"\"\n            << nameOfFile\n            << \"\\\", zookeeper = \\\"\"\n            << zkHost\n            << \"\\\", optind = \"\n            << optind\n            << \", argc = \"\n            << argc\n            << \", current arg = \\\"\"\n            << (optind >= argc ? \"NULL\" : argv[optind])\n            << \"\\\"\"\n            << endl;\n    }\n\n    SessionEventListener listener;\n    SynchronousEventAdapter<ZKWatcherEvent> eventAdapter;\n    LOG_INFO(LOG, \"Create ZK adapter\");\n    try {\n        /**\n         * Create an instance of ZK adapter.\n         */\n        std::string h(zkHost);\n        ZooKeeperConfig config(h, 1000, true, 10000);\n        ZkFuseCommon zkFuseCommon;\n        ZooKeeperAdapterSharedPtr zkPtr(\n            new ZooKeeperAdapter(\n                config, \n                &listener,\n                false\n                )\n            );\n        zkFuseCommon.setZkAdapter(zkPtr);\n        zkFuseCommon.setDataFileName(nameOfFile);\n        zkFuseCommon.setForceDirSuffix(forceDirSuffix);\n        zkFuseCommon.setCacheSize(cacheSize);\n        singletonZkFuseHandleManager =\n            ZkFuseHandleManagerFactory::create(zkFuseCommon);\n        listener.setManager(singletonZkFuseHandleManager);\n        zkPtr->reconnect();\n\n    } catch (const ZooKeeperException & e) {\n        cerr \n            << argv[0]\n            << \": ERROR: ZookKeeperException caught: \"\n            << e.what() \n            << endl;\n    } catch (std::exception & e) {\n        cerr \n            << argv[0]\n            << \": ERROR: std::exception caught: \"\n            << e.what() \n            << endl;\n    }\n\n#ifdef ZOOKEEPER_ROOT_CHILDREN_WATCH_BUG\n    cerr << \"ZOOKEEPER_ROOT_CHILDREN_WATCH_BUG enabled\" << endl;\n#endif \n    /**\n     * Initialize fuse \n     */\n    LOG_INFO(LOG, \"Initialize fuse\");\n    umask(0); \n    fuse_operations zkfuse_oper; \n    init_zkfuse_oper(zkfuse_oper); \n    int fakeArgc = debugFlag ? 3 : 2;\n    char * fakeArgv[] = {\n        argv[0],\n        strdup(mountPoint.c_str()),\n        debugFlag ? strdup(\"-d\") : NULL,\n        NULL\n    };\n    int res = fuse_main(fakeArgc, fakeArgv, &zkfuse_oper, NULL);\n    for (unsigned i = 1; i <= 2; i++) {\n        if (fakeArgv[i] != NULL) {\n            free(fakeArgv[i]);\n        }\n    }\n\n    return res;\n}\n"
  },
  {
    "path": "src/contrib/zkperl/Changes",
    "content": "Net::ZooKeeper - Perl extension for Apache ZooKeeper\n\nRevision history\n================\n\n0.01  Dec 5, 2008\n        - initial version\n\n0.02  Dec 16, 2008\n        - support connection to ZooKeeper and get() method\n\n0.03  Jan 9, 2009\n        - implemented watch mechanism for get()\n\n0.04  Jan 15, 2009\n        - all basic ZooKeeper methods supported\n\n0.05  Jan 21, 2009\n        - converted from T_PTROBJ to T_ZK_HASH with PERL_MAGIC_ext,\n          allows DESTROY() to be called repeatedly\n\n0.06  Jan 27, 2009\n        - converted from attribute accessor methods to inner and outer hashes\n          with PERL_MAGIC_tied\n\n0.07  Jan 29, 2009\n        - all tied hash methods completed\n\n0.08  Jan 30, 2009\n        - simple thread safety enforced with CLONE_SKIP\n\n0.09  Feb 12, 2009\n        - ACL constants\n\n0.10  Feb 18, 2009\n        - ACL support\n\n0.11  Feb 21, 2009\n        - ZooKeeper version check\n\n0.20  Feb 25, 2009\n        - refactored watches as subclass\n\n0.30  Feb 27, 2009\n        - refactored stats as subclass\n\n0.31  Mar 6, 2009\n        - test suite completed\n\n0.32  Mar 25, 2009\n        - initial documentation completed, first public release\n\n0.33  Apr 20, 2009\n        - copyright donated to ASF\n\n0.34  Jul 14, 2009\n        - support ZooKeeper 3.2.0 release\n\n0.35  Jul 15, 2009\n        - support multiple include and library locations\n\n0.36  Mar 27, 2011\n        - Fix zookeeper version check, but only warn since we haven't been enforcing it in a while\n        - Look for zookeeper includes in some sane places by default\n\n"
  },
  {
    "path": "src/contrib/zkperl/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/contrib/zkperl/MANIFEST",
    "content": "Changes\nLICENSE\nMakefile.PL\nMANIFEST\nNOTICE\nREADME\ntypemap\nZooKeeper.pm\nZooKeeper.xs\nbuild/check_zk_version.c\nbuild/check_zk_version.h\nt/10_invalid.t\nt/15_thread.t\nt/20_tie.t\nt/22_stat_tie.t\nt/24_watch_tie.t\nt/30_connect.t\nt/35_log.t\nt/40_basic.t\nt/45_class.t\nt/50_access.t\nt/60_watch.t\nt/util.pl\n"
  },
  {
    "path": "src/contrib/zkperl/Makefile.PL",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse 5.008_008;\n\nuse Config;\nuse ExtUtils::MakeMaker;\nuse Getopt::Long;\n\nmy $ZOO_MAJOR_VERSION = 3;\nmy $ZOO_REQUIRED_VERSION = qr{^$ZOO_MAJOR_VERSION\\.\\d+.\\d+$}ismx;\n\nmy @zk_inc_paths;\nmy @zk_lib_paths;\n\nGetOptions(\n    'zookeeper-include=s' => \\@zk_inc_paths,\n    'zookeeper-lib=s' => \\@zk_lib_paths\n);\n\nmy $zk_inc_paths = join(' ', map(\"-I$_\", @zk_inc_paths));\nmy $zk_lib_paths = join(' ', map(\"-L$_\", @zk_lib_paths));\n\n$zk_inc_paths .= ' ' unless ($zk_inc_paths eq '');\n$zk_lib_paths .= ' ' unless ($zk_lib_paths eq '');\n\nmy $cc = $Config{'cc'};\nmy $check_file = 'build/check_zk_version';\n\nmy $check_out = qx($cc $zk_inc_paths $zk_lib_paths -I. -o $check_file $check_file.c 2>&1);\n\nif ($?) {\n    if ($check_out =~ /zookeeper_version\\.h/) {\n        die(\"Could not determine ZooKeeper version:\\n\\n$check_out\");\n    }\n    else {\n        ## keep in sync with build/check_zk_version.h\n        die(\"Net::ZooKeeper requires at least ZooKeeper version 3.1.1\\n\");\n    }\n}\n\nchomp(my $zk_ver = qx($check_file));\n\nif ($? >> 8 != 0) {\n  die \"Couldn't check zookeeper version: $zk_ver: $r\";\n}\nelsif ($zk_ver !~ $ZOO_REQUIRED_VERSION) {\n  warn \"Net::ZooKeeper requires ZooKeeper 3.x, found $zk_ver!\";\n}\n\nWriteMakefile(\n    'INC'          => \"$zk_inc_paths-I.\",\n    'LIBS'         => [ \"$zk_lib_paths-lzookeeper_mt\" ],\n    'NAME'         => 'Net::ZooKeeper',\n    'VERSION_FROM' => 'ZooKeeper.pm',\n    'clean'        => { 'FILES' => 'build/check_zk_version.o' }\n);\n\n"
  },
  {
    "path": "src/contrib/zkperl/NOTICE",
    "content": "Net::ZooKeeper - Perl extension for Apache ZooKeeper\nCopyright 2009 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n\n"
  },
  {
    "path": "src/contrib/zkperl/README",
    "content": "Net::ZooKeeper - Perl extension for Apache ZooKeeper\n====================================================\n\nNet::ZooKeeper provides a Perl interface to the synchronous C API\nof Apache ZooKeeper.  ZooKeeper is coordination service for\ndistributed applications.\nFor details see the ZooKeeper home page at:\n\nhttp://zookeeper.apache.org/\n\nINSTALLATION\n\nTo install this module type the following, first install the\nzookeeper C client, then:\n\n    perl Makefile.PL\n    make\n    ZK_TEST_HOSTS=host:port,... make test\n    make install\n\nIf the C headers and library are installed in non-standard\nlocations, specify them as arguments to Makefile.PL:\n    \n    perl Makefile.PL \\\n        --zookeeper-include=/path/to/zookeeper/client/include \\\n        --zookeeper-lib=/path/to/zookeeper/client/lib\n\nThe path supplied to the --zookeeper-include option should\nidentify the directory that contains the zookeeper.h and other\nZooKeeper C include files.\n\nThe path supplied to the --zookeeper-lib option should identify\nthe directory that contains the libzookeeper_mt library.\n\nWhen running \"make test\", if no ZK_TEST_HOSTS environment\nvariable is set, many tests will be skipped because no connection\nto a ZooKeeper server is available.  To execute these tests,\nthe ZK_TEST_HOSTS variable may be assigned a list of one or more\nZooKeeper host:port pairs, e.g., \"localhost:7100,otherhost:7200\".\n\nThe ZK_TEST_PATH environment variable, if defined, specifies\nthe ZooKeeper path under which all test nodes should be created.\nThe tests expect to have full read/write/create/delete/admin\nZooKeeper permissions under this path.  If no ZK_TEST_PATH\nvariable is defined, the root ZooKeeper path (\"/\") is used.\n\nDEPENDENCIES\n\nVersion 3.1.1 of ZooKeeper is required at a minimum.\n\nFor version 3.1.1, you may also want to apply some of these\nadditional patches to the ZooKeeper C API code:\n\nhttps://issues.apache.org/jira/browse/ZOOKEEPER-262\nhttps://issues.apache.org/jira/browse/ZOOKEEPER-318\n\nFor version 3.1.1, you may also want to apply some of these\nadditional patches to the ZooKeeper C API code:\n\nhttps://issues.apache.org/jira/browse/ZOOKEEPER-262\nhttps://issues.apache.org/jira/browse/ZOOKEEPER-466\n\nThis module requires that the multi-threaded version of the\nZooKeeper C API client library be available on your system.\n\nThis in turn implies that the POSIX pthread library is available\nas well.\n\nCOPYRIGHT AND LICENCE\n\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n"
  },
  {
    "path": "src/contrib/zkperl/ZooKeeper.pm",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse 5.008_008;\n\nuse strict;\nuse warnings;\n\npackage Net::ZooKeeper;\n\nrequire Exporter;\nrequire XSLoader;\n\nour $VERSION = '0.36';\n\nour @ISA = qw(Exporter);\n\nour %EXPORT_TAGS = (\n    'errors' => [qw(\n        ZOK\n        ZSYSTEMERROR\n        ZRUNTIMEINCONSISTENCY\n        ZDATAINCONSISTENCY\n        ZCONNECTIONLOSS\n        ZMARSHALLINGERROR\n        ZUNIMPLEMENTED\n        ZOPERATIONTIMEOUT\n        ZBADARGUMENTS\n        ZINVALIDSTATE\n        ZAPIERROR\n        ZNONODE\n        ZNOAUTH\n        ZBADVERSION\n        ZNOCHILDRENFOREPHEMERALS\n        ZNODEEXISTS\n        ZNOTEMPTY\n        ZSESSIONEXPIRED\n        ZINVALIDCALLBACK\n        ZINVALIDACL\n        ZAUTHFAILED\n        ZCLOSING\n        ZNOTHING\n    )],\n    'node_flags' => [qw(\n        ZOO_EPHEMERAL\n        ZOO_SEQUENCE\n    )],\n    'acl_perms' => [qw(\n        ZOO_PERM_READ\n        ZOO_PERM_WRITE\n        ZOO_PERM_CREATE\n        ZOO_PERM_DELETE\n        ZOO_PERM_ADMIN\n        ZOO_PERM_ALL\n    )],\n    'acls' => [qw(\n        ZOO_OPEN_ACL_UNSAFE\n        ZOO_READ_ACL_UNSAFE\n        ZOO_CREATOR_ALL_ACL\n    )],\n    'events' => [qw(\n        ZOO_CREATED_EVENT\n        ZOO_DELETED_EVENT\n        ZOO_CHANGED_EVENT\n        ZOO_CHILD_EVENT\n        ZOO_SESSION_EVENT\n        ZOO_NOTWATCHING_EVENT\n    )],\n    'states' => [qw(\n        ZOO_EXPIRED_SESSION_STATE\n        ZOO_AUTH_FAILED_STATE\n        ZOO_CONNECTING_STATE\n        ZOO_ASSOCIATING_STATE\n        ZOO_CONNECTED_STATE\n    )],\n    'log_levels' => [qw(\n        ZOO_LOG_LEVEL_OFF\n        ZOO_LOG_LEVEL_ERROR\n        ZOO_LOG_LEVEL_WARN\n        ZOO_LOG_LEVEL_INFO\n        ZOO_LOG_LEVEL_DEBUG\n    )]\n);\n\n{\n    my %tags;\n\n    push @{$EXPORT_TAGS{'all'}},\n        grep {!$tags{$_}++} @{$EXPORT_TAGS{$_}} foreach (keys(%EXPORT_TAGS));\n}\n\nour @EXPORT_OK = ( @{$EXPORT_TAGS{'all'}} );\n\nXSLoader::load('Net::ZooKeeper', $VERSION);\n\n1;\n\n__END__\n\n=head1 NAME\n\nNet::ZooKeeper - Perl extension for Apache ZooKeeper\n\n=head1 SYNOPSIS\n\n  use Net::ZooKeeper qw(:node_flags :acls);\n\n  my $zkh = Net::ZooKeeper->new('localhost:7000');\n\n  $zkh->create('/foo', 'bar',\n               'flags' => ZOO_EPHEMERAL,\n               'acl' => ZOO_OPEN_ACL_UNSAFE) or\n    die(\"unable to create node /foo: \" . $zkh->get_error() . \"\\n\");\n\n  print \"node /foo has value: \" . $zkh->get('/foo') . \"\\n\";\n\n  $zkh->set('/foo', 'baz');\n\n  print \"node / has child nodes:\\n\";\n  foreach my $path ($zkh->get_children('/')) {\n    print \"  /$path\\n\";\n  }\n\n  my $stat = $zkh->stat();\n  if ($zkh->exists('/foo', 'stat' => $stat)) {\n    print \"node /foo has stat info:\\n\";\n    while (my($key,$value) = each(%{$stat})) {\n      print \"  $key: $value\\n\";\n    }\n  }\n\n  foreach my $acl_entry ($zkh->get_acl('/foo')) {\n    print \"node /foo has ACL entry:\\n\";\n    print \"  perms:  $acl_entry->{perms}\\n\";\n    print \"  scheme: $acl_entry->{scheme}\\n\";\n    print \"  id:     $acl_entry->{id}\\n\";\n  }\n\n  my $watch = $zkh->watch('timeout' => 10000);\n  $zkh->exists('/foo', 'watch' => $watch);\n\n  if ($watch->wait()) {\n    print \"watch triggered on node /foo:\\n\";\n    print \"  event: $watch->{event}\\n\";\n    print \"  state: $watch->{state}\\n\";\n  }\n  else {\n    print \"watch timed out after 10 seconds\\n\";\n  }\n\n  $zkh->delete('/foo');\n\n=head1 DESCRIPTION\n\nNet::ZooKeeper provides a Perl interface to the synchronous C API\nof Apache ZooKeeper.  ZooKeeper is coordination service for\ndistributed applications.\n\nEach connection to ZooKeeper is represented as a handle object\nof the class Net::ZooKeeper, similar to the manner in which database\nconnections are represented in the DBI module.\n\nTo disconnect from ZooKeeper, simply destroy the Net::ZooKeeper\nhandle object by undefining it or by explicitly calling the\nC<DESTROY()> method.\n\nThe methods which may be invoked on Net::ZooKeeper handles\ncorrespond to the functions of the synchronous ZooKeeper C API;\ne.g., the Net::ZooKeeper method C<create()> calls the ZooKeeper\nC function C<zoo_create()>, C<delete()> calls C<zoo_delete()>,\nand so forth.\n\nThe synchronous API functions wait for a response from the ZooKeeper\ncluster before returning a result to the caller.  Using these\nfunctions permits Net::ZooKeeper to provide an interface similar\nto that of a DBI driver module.\n\n=head2 Internal POSIX Threads\n\nThe use of the synchronous ZooKeeper C API still requires that\nthe ZooKeeper C client code create several POSIX threads which run\nconcurrently with the main thread containing the Perl interpreter.\n\nThe synchronous API functions are wrappers of the asynchronous\nfunctions in the ZooKeeper C API.  When a request is made by the\ncaller's thread (i.e., the one with the running Perl interpreter),\nit is enqueued for delivery at a later time by the ZooKeeper C client\ncode's IO thread.  The caller's thread then waits for notification\nbefore returning from the synchronous API function.\n\nThe IO thread dequeues the request and sends it to the ZooKeeper\ncluster, while also ensuring that a regular \"heartbeat\" is maintained\nwith the cluster so that the current session does not time out.\nWhen the IO thread receives a response from\nthe ZooKeeper cluster, it enqueues the response for delivery to the\nclient by the second thread of the ZooKeeper client code, the\ncompletion thread.\n\nIf the caller is using the asynchronous API, the completion thread\ninvokes the appropriate callback function provided by the caller\nfor the given request.  In the case of Net::ZooKeeper, it is not\nviable for the completion thread to invoke a Perl callback function\nat arbitrary times; this could interfere with the state of the\nPerl interpreter.\n\nFor this reason Net::ZooKeeper uses the synchronous API only.  After\nenqueuing requests the synchronous API functions wait for notification\nof the corresponding response.  The completion thread delivers these\nnotifications, at which point the synchronous functions return to\ntheir caller.\n\nNote that the IO and completion threads are POSIX threads, not\nPerl ithreads.  Net::ZooKeeper defined a C<CLONE_SKIP()> function so\nthat if Perl ithreads are spawned while a Net::ZooKeeper connection\nis active, the Net::ZooKeeper handle objects inherited by the\nspawned ithread contain undefined values so that they can not be used.\nThus each ithread will need to create its own private connections to a\nZooKeeper cluster.\n\nNote also that before invoking C<fork()> to spawn a new process,\nall Net::ZooKeeper handles should be destroyed so that all\nconnections to ZooKeeper are closed and all internal POSIX threads\nhave exited.  If a child process needs to communicate with\nZooKeeper it should open its own private connections after it is\ncreated by C<fork()>.\n\n=head2 Signals\n\nThe ZooKeeper C API uses TCP connections to communicate with\nthe ZooKeeper cluster.  These connections may generate SIGPIPE\nsignals when they encounter errors, such as when a connection\nis terminated by a ZooKeeper server.  Therefore most applications\nwill want to trap or ignore SIGPIPE signals, e.g.:\n\n  local $SIG{'PIPE'} = 'IGNORE';\n\nIgnoring SIGPIPE signals (or providing a signal handler that returns\ncontrol to the interrupted program after receiving the signal)\nwill allow the ZooKeeper C client code to detect the connection error\nand report it upon return from the next Net::ZooKeeper method.\n\n=head2 Error Handling\n\nNet::ZooKeeper methods return different values in the case of an\nerror depending on their purpose and context.  For example,\nC<exists()> returns true if the node exists and false otherwise,\nwhich may indicate either that the node does not exist or that\nan error occurred.\n\nAfter any method returns a false, empty, or undefined value which\nmight indicate an error has occurred, the C<get_error()> method\nmay be called to examine the specific error code, if any.\n\nIf C<get_error()> returns C<ZOK>, no error has occurred.  If the\nerror code is less than C<ZAPIERROR>, it indicates a normal error\ncondition reported by the ZooKeeper server, such as C<ZNONODE>\n(node does not exist) or C<ZNODEEXISTS> (node already exists).\n\nIf the error code is greater than C<ZAPIERROR>, then a connection\nerror or server error has occurred and the client should probably\nclose the connection by undefining the Net::ZooKeeper handle object\nand, if necessary, attempt to create a new connection to the\nZooKeeper cluster.\n\n=head2 Access Control\n\nIf the ZooKeeper cluster is not configured with C<skipACL=yes> then\nit will respect the access controls set for each node in the\nZooKeeper hierarchy.  These access controls are defined using ACLs\n(Access Control Lists); see the ZooKeeper documentation for compete\ndetails.\n\nIn Net::ZooKeeper, ACLs are represented as arrays of hashes, where\neach hash is an ACL entry that must contain three attributes,\nC<perms>, C<scheme>, and C<id>.  The C<perms> attribute's value\nshould be composed by combining ACL permission flags using the\nbitwise OR operator.  See C<:acl_perms> for a list of the\navailable ACL permission flags.\n\nThe ACL for a node may be read using the C<get_acl()> method.  A\nnode's ACL may be set when the node is created by passing an ACL\narray as the value of the C<'acl'> option to the C<create()> method,\nand may be updated by passing an ACL array to the C<set_acl()> method.\n\nWhen a client connects to a ZooKeeper cluster it is automatically\nassigned authentication credentials based on its IP address.\nAdditional authentication credentials may be added using\nthe C<add_auth()> method.  Once a credential has been added for\nthe current session, there is no way to disable it.\n\nAs an example, digest authentication may be enabled for a session\nby calling C<add_auth()> as follows:\n\n  $zkh->add_auth('digest', \"$username:$password\");\n\nNote that the username and password are transmitted in cleartext\nto the ZooKeeper cluster.\n\nSuch authentication credentials would enable access to a node\nwhose ACL contained an entry with a C<scheme> attribute of\nC<'digest'> and an C<id> attribute containing a Base64-encoded\nSHA1 digest of the string C<\"$username:$password\">.  The\nPerl modules Digest and MIME::Base64 may be used to create\nsuch ACL ID values as follows:\n\n  use Digest qw();\n  use MIME::Base64 qw();\n\n  my $ctx = Digest->new('SHA-1')->add(\"$username:$password\");\n  my $digest = MIME::Base64::encode($ctx->digest());\n\nNote that using the C<b64digest()> method of the Digest module\nwill not result in digest strings with the \"=\" suffix characters\nrequired by ZooKeeper.\n\n=head2 Logging\n\nAs of ZooKeeper version 3.1.1, logging in the C client code is\nimplemented with a single, shared file handle to which all\nof the internal POSIX threads write log messages; by default,\nthis file handle is attached to STDERR.\n\nMoreover, this file handle is shared by all active ZooKeeper\nconnections (each of which has its own private IO and completion\nthreads; see L</Internal POSIX Threads> above).\n\nNet::ZooKeeper therefore does not provide per-connection handle\nattributes related to logging.  The global function\nC<Net::ZooKeeper::set_log_level()> may be used to set the current\nlog level.  See C<:log_levels> for a list of the available log\nlevels.  The default log level is C<ZOO_LOG_LEVEL_OFF>.\n\nTo capture ZooKeeper log messages to a file instead of STDERR,\nredirect STDERR to a new file handle in the normal Perl manner:\n\n  open(OLDERR, '>&', fileno(STDERR)) or\n    die(\"unable to dup STDERR: $!\");\n  open(STDERR, '>', $log_file) or\n    die(\"unable to redirect STDERR: $!\");  \n\n=head2 Connection Order\n\nZooKeeper clusters are typically made up of an odd number of\nZooKeeper servers.  When connecting to such a cluster, the\nC<new()> method should be passed a comma-separated list of\nthe hostnames and ports for each of the servers in the cluster,\ne.g., C<'host1:7000,host2:7000,host2:7100'>.\n\nThe default behaviour of the ZooKeeper client code is to\nreorder this list randomly before making any connections.\nA connection is then made to the first server in the reordered\nlist.  If that connection fails, the IO thread will\nautomatically attempt to reconnect to the cluster, this time\nto the next server in the list; when the last server in the list\nis reached, the IO thread will continue again with the first\nserver.\n\nFor certain purposes it may be necessary for ZooKeeper clients\nto know the exact order in which the IO thread will attempt to\nconnect to the servers of a cluster.  To do so, call\nC<Net::ZooKeeper::set_deterministic_conn_order(1)>.  Note,\nhowever, that this will affect all Net::ZooKeeper object\nhandles created by the current process.\n\n=head1 ATTRIBUTES\n\n=head2 Net::ZooKeeper\n\nThe Net::ZooKeeper class provides the main interface to the\nZooKeeper client API.  The following attributes are available\nfor each Net::ZooKeeper handle object and are specific to\nthat handle and the method calls invoked on it.  As with DBI\nhandle objects, attributes may be read and written through\na hash interface, e.g.:\n\n  print sprintf(\"Session timeout is %.2f seconds.\\n\",\n    $zkh->{session_timeout} / 1000);\n\n  $zkh->{watch_timeout} = 10000;\n\n=over 4\n\n=item hosts\n\nThe comma-separated list of ZooKeeper server hostnames and ports\nas passed to the C<new()> method.  Note that by default the\nZooKeeper C client code will reorder this list before attempting\nto connect for the first time; see L</Connection Order> for details.\n\nThis attribute is B<read-only> and may not be modified.\n\n=item session_timeout\n\nThe session timeout value, in milliseconds, as set by the\nZooKeeper server after connection.  This value may not be\nexactly the same as what was requested in the C<'session_timeout'>\noption of the C<new()> method; the server will adjust the\nrequested timeout value so that it is within a certain range\nof the server's C<tickTime> setting.  See the ZooKeeper\ndocumentation for details.\n\nBecause the actual connection to the ZooKeeper server is\nnot made during the C<new()> method call but shortly\nthereafter by the IO thread, note that this value may not\nbe initialized to its final value until at least one\nother method which requires communication with the server\n(such as C<exists()>) has succeeded.\n\nThis attribute is B<read-only> and may not be modified.\n\n=item session_id\n\nThe client's session ID value as set by the ZooKeeper server\nafter connection.  This is a binary data string which may\nbe passed to subsequent C<new()> calls as the value of\nthe C<'session_id'> option, if the user wishes to attempt to\ncontinue a session after a failure.  Note that the server\nmay not honour such an attempt.\n\nBecause the actual connection to the ZooKeeper server is\nnot made during the C<new()> method call but shortly\nthereafter by the IO thread, note that this value may not\nbe initialized to its final value until at least one\nother method which requires communication with the server\n(such as C<exists()>) has succeeded.\n\nThis attribute is B<read-only> and may not be modified.\n\n=item data_read_len\n\nThe maximum length of node data that will be returned to\nthe caller by the C<get()> method.  If a node's data exceeds\nthis length, the returned value will be shorter than the\nactual node data as stored in the ZooKeeper cluster.\n\nThe default maximum length of the node data returned by\nC<get()> is 1023 bytes.  This may be changed by setting\nthe C<data_read_len> attribute to a different value.\n\nPassing a value for the C<'data_read_len'> option when calling\nthe C<get()> method will temporarily override the per-handle\nmaximum.\n\n=item path_read_len\n\nThe maximum length of a newly created node's path that will\nbe returned to the caller by the C<create()> method.  If the path\nof the newly created node exceeds this length, the returned\nvalue will be shorter than the actual path of the node as stored\nin the ZooKeeper cluster.\n\nThe default maximum length of the node path returned by\nC<create()> is 1023 bytes.  This may be changed by setting\nthe C<path_read_len> attribute to a different value.\n\nPassing a value for the C<'path_read_len'> option when calling\nthe C<create()> method will temporarily override the current\nvalue of this attribute.\n\n=item watch_timeout\n\nThe C<timeout> attribute value, in milliseconds, inherited by\nall watch objects (of class Net::ZooKeeper::Watch) created by\ncalls to the C<watch()> method.  When a watch object's\nC<wait()> method is invoked without a C<'timeout'> option,\nit waits for an event notification from the ZooKeeper cluster\nfor no longer than the timeout period specified by the value of\nthe watch object's C<timeout> attribute.\n\nThe default C<timeout> attribute value for all watch objects\ncreated by the C<watch()> method is 1 minute (60000\nmilliseconds).  This may be changed for a particular handle\nobject by setting this attribute to a different value; afterwards,\nthe new value will be inherited by any watch objects created\nby the handle object's C<watch()> method.  Previously\ncreated watch objects will not be affected.\n\nPassing a value for the C<'timeout'> option when calling\nthe C<watch()> method will temporarily override the current\nvalue of this attribute and cause the newly created watch object\nto inherit a different value.\n\nSee also the C<watch()> method, and the C<timeout> attribute\nand C<wait()> method of the Net::ZooKeeper::Watch class.\n\n=item pending_watches\n\nThe number of internal ZooKeeper watches created for this handle\nobject that are still awaiting an event notification from the\nZooKeeper cluster.\n\nNote that this number may be different than the number of\nextant watch objects created by the handle object's C<watch()>\nmethod, not only because some event notifications may have\noccurred, but also if any watch objects have been reassigned\nby reusing them in more than one call to any of the C<exists()>,\nC<get_children()>, or C<get()> methods.\n\nThis attribute is B<read-only> and may not be modified.\n\n=back\n\n=head2 Net::ZooKeeper::Stat\n\nThe Net::ZooKeeper::Stat class provides a hash interface to\nthe individual pieces of information which together compose the\nstate of a given ZooKeeper node.  Net::ZooKeeper::Stat objects\nare created by calling the C<stat()> method on a Net::ZooKeeper\nhandle object, and may then be passed to any methods which accept\na C<'stat'> option value, such as C<exists()>.\n\nNet::ZooKeeper::Stat objects may be reused multiple times.\nIf the Net::ZooKeeper method to which the stat object is\npassed succeeds, then the stat object is updated with the newly\nretrieved node state information, and any state information\npreviously stored in the stat object is overwritten.\n\nAll of the attributes of stat objects are B<read-only>.\n\n=over 4\n\n=item ctime\n\nThe creation time of the node in milliseconds since the epoch.\n\n=item mtime\n\nThe time of the last modification of the node's data in\nmilliseconds since the epoch.\n\n=item data_len\n\nThe length of the node's data in bytes.\n\n=item num_children\n\nThe number of child nodes beneath of the current node.\n\n=item ephemeral_owner\n\nIf the node was created with the C<ZOO_EPHEMERAL> flag,\nthis attribute holds the session ID of the ZooKeeper client\nwhich created the node.  If the node was not created with\nthe C<ZOO_EPHEMERAL> flag, this attribute is set to zero.\n\n=item version\n\nThe number of revisions of the node's data.  The ZooKeeper\ncluster will increment this version number whenever the\nnode's data is changed.  When the node is first created this\nversion number is initialized to zero.\n\n=item acl_version\n\nThe number of revisions of the node's ACL.  The ZooKeeper\ncluster will increment this version number whenever the\nnode's ACL is changed.  When the node is first created this\nversion number is initialized to zero.\n\n=item children_version\n\nThe number of revisions of the node's list of child nodes.\nThe ZooKeeper cluster will increment this version number\nwhenever the list of child nodes is changed.  When the node\nis first created this version number is initialized to zero.\n\n=item czxid\n\nThe ZooKeeper transaction ID (ZXID) of the transaction which\ncreated the node.\n\n=item mzxid\n\nThe ZooKeeper transaction ID (ZXID) of the transaction which\nlast modified the node's data.  This is initially set to\nthe same transaction ID as the C<czxid> attribute by the\nC<create()> method.\n\n=item children_zxid\n\nThe ZooKeeper transaction ID (ZXID) of the transaction which\nlast modified the node's list of child nodes.  This is\ninitially set to the same transaction ID as the C<czxid>\nattribute by the C<create()> method.\n\n=back\n\n=head2 Net::ZooKeeper::Watch\n\nThe Net::ZooKeeper::Watch class provides a hash interface\nto the data returned by event notifications from the ZooKeeper\ncluster.  Net::ZooKeeper::Watch objects are created by calling\nthe C<watch()> method on a Net::ZooKeeper handle object, and\nmay then be passed to any methods which accept a C<'watch'>\noption value, such as C<exists()>.\n\nNet::ZooKeeper::Watch objects may be reused multiple times.\nRegardless of whether the Net::ZooKeeper method to which the\nwatch object is passed succeeds, the watch object will be\nupdated to receive an event notification exclusively for the\nnode referenced in that method call.  In the case of an error,\nhowever, the watch object may never receive any event\nnotification.\n\n=over 4\n\n=item timeout\n\nThe default timeout value, in milliseconds, for all\ninvocations of the C<wait()> method made on the watch object.\nWhen the C<wait()> method is invoked without a\nC<'timeout'> option value, it waits for an\nevent notification from the ZooKeeper cluster for no longer\nthan the timeout period specified by this attribute.\nThis default timeout period may be altered by setting this\nattribute to a different value.\n\nPassing a value for the C<'timeout'> option when calling\nthe C<wait()> method will temporarily override the current\nvalue of this attribute and cause the C<wait()> method to\nuse a different timeout period.\n\nWhen a Net::ZooKeeper handle object's C<watch()> method is\ninvoked without a C<'timeout'> option, it returns a newly\ncreated watch object whose C<timeout> attribute value\nis initialized to the current value of the handle object's\nC<watch_timeout> attribute.  When the C<watch()> method is invoked\nwith a C<'timeout'> option, the new watch object's C<timeout>\nattribute value is initialized to the value specified by\nthe C<'timeout'> option.\n\nSee also the C<wait()> method, and the C<watch_timeout> attribute\nand C<watch()> method of the Net::ZooKeeper class.\n\n=item event\n\nThe type of event which triggered the notification, such\nas C<ZOO_CHANGED_EVENT> if the node's data was changed.\nSee C<:events> for a list of the possible event types.\nIf zero, no event notification has occurred yet.\n\nNote that the events which will trigger a notification\nwill depend on the Net::ZooKeeper method to which\nthe watch object was passed.  Watches set through the\nC<exists()> and C<get()> methods will report events relating\nto the node's data, while watches set through the\nC<get_children()> method will report events relating to the\ncreation or deletion of child nodes of the watched node.\n\nThis attribute is B<read-only> and may not be modified.\n\n=item state\n\nThe state of the Net::ZooKeeper connection at the time of\nthe event notification.  See C<:states> for a list of\nthe possible connection states.  If zero, no event\nnotification has occurred yet.\n\nThis attribute is B<read-only> and may not be modified.\n\n=back\n\n=head1 METHODS\n\n=head2 Net::ZooKeeper\n\nThe following methods are defined for the Net::ZooKeeper class.\n\n=over 4\n\n=item new()\n\n  $zkh = Net::ZooKeeper->new('host1:7000,host2:7000');\n  $zkh = Net::ZooKeeper->new('host1:7000,host2:7000',\n                             'session_timeout' => $session_timeout,\n                             'session_id' => $session_id);\n\nCreates a new Net::ZooKeeper handle object and attempts to\nconnect to the one of the servers of the given ZooKeeper\ncluster.  As described in the L</Internal POSIX Threads> and\nL</Connection Order> sections, the ZooKeeper client code will\ncreate an IO thread which maintains the connection with a\nregular \"heartbeat\" request.  In the event of a connection error\nthe IO thread will also attempt to reconnect to another one of\nthe servers using the same session ID.  In general, these actions\nshould be invisible to the user, although Net::ZooKeeper methods\nmay return transient errors while the IO thread\nreconnects with another server.\n\nTo disconnect, undefine the Net::ZooKeeper handle object\nor call the C<DESTROY()> method.  (After calling C<DESTROY()>\nthe handle object can not be reused.)\n\nThe ZooKeeper client code will send a \"heartbeat\" message\nif a third of the session timeout period has elapsed without\nany communication with the ZooKeeper server.  A specific\nsession timeout period may be requested when creating a\nNet::ZooKeeper handle object by supplying a value, in\nmilliseconds, for the C<'session_timeout'> option.  The\nZooKeeper server adjust the requested timeout value so that\nit is within a certain range of the server's C<tickTime> setting;\nthe actual session timeout value will be available as the\nvalue of the handle's C<session_timeout> attribute after at\nleast one method call has succeeded.  See the C<session_timeout>\nattribute for more information.\n\nIf no C<'session_timeout'> option is provided, the default\nvalue of 10 seconds (10000 milliseconds) will be used in the\ninitial connection request; again, the actual timeout period to\nwhich the server agrees will be available subsequently as the\nvalue of the C<session_timeout> attribute.\n\nUpon successful connection (i.e., after the success of a method\nwhich requires communication with the server), the C<session_id>\nattribute will hold a short binary string which represents the\nclient's session ID as set by the server.  All ephemeral nodes\ncreated by the session are identified by this ID in the\nC<ephemeral_owner> attribute of any Net::ZooKeeper::Stat objects\nused to query their state.\n\nThe ZooKeeper client code will use this session ID internally\nwhenever it tries to reconnect to another server in the ZooKeeper\ncluster after detecting a failed connection.  If it successfully\nreconnects with the same session ID, the session will continue\nand ephemeral nodes belonging to it will not be deleted.\n\nHowever, if the server determines that the session has timed\nout (for example because no \"heartbeat\" requests have been\nreceived within the agreed-upon session timeout period), the\nsession will be terminated by the cluster and all ephemeral nodes\nowned by the current session automatically deleted.\n\nOn occasion the ZooKeeper client code may not be able to quickly\nreconnect to a live server and the caller may want to destroy\nthe existing Net::ZooKeeper handle object and attempt a\nfresh connection using the same session ID as before with a\nnew Net::ZooKeeper object.  To do so, save the C<session_id>\nattribute value before undefining the old handle object\nand then pass that binary string as the value of the\nC<'session_id'> option to the C<new()> method when creating the\nnext handle object.  After the successful completion of a\nmethod which requires communication with the server, if the\nnew handle object's C<session_id> attribute value matches the\nold session ID then the session has been successfully maintained;\notherwise, the old session was expired by the cluster.\n\n=item get_error()\n\n  $code = $zkh->get_error();\n\nReturns the ZooKeeper error code, if any, from the most\nrecent Net::ZooKeeper method invocation.  The returned value\nwill be zero (equivalent to C<ZOK>) if no error occurred,\notherwise non-zero.  Non-zero values may be compared to\nthe error code names exported by the C<:errors> tagset.\n\nSee L</Error Handling> for more details.\n\n=item add_auth()\n\n  $zkh->add_auth('digest', \"$username:$password\");\n\nThe C<add_auth()> method may be used to add authentication\ncredentials to a session.  Once a credential has been added for\nthe current session, there is no way to disable it.\n\nWhen using the digest authentication scheme, note that the\nusername and password are transmitted in cleartext\nto the ZooKeeper cluster.\n\nSee L</Access Control> for additional details.\n\n=item create()\n\n  $path = $zkh->create($req_path, $data);\n  $path = $zkh->create($req_path, $data,\n                       'flags' => (ZOO_EPHEMERAL | ZOO_SEQUENCE),\n                       'acl' => ZOO_OPEN_ACL_UNSAFE,\n                       'path_read_len' => 100);\n\nRequests that a node be created in the ZooKeeper cluster's\nhierarchy with the given path and data.  Upon success,\nthe returns the node's path, otherwise undef.\n\nThe path returned by a successful C<create()> method call\nmay not be the new node's full path as it appears in the\nZooKeeper hierarchy, depending on the length of the actual\npath and the value of the handle object's C<path_read_len>\nattribute.  If the length of the actual path exceeds the\ncurrent value of the C<path_read_len> attribute, the path\nreturned by the C<create()> method will be truncated; note\nthat the node's path in the ZooKeeper hierarchy is not\naffected by this truncation.\n\nSpecifying a value for the C<'path_read_len'> option will\ntemporarily override the value of the C<path_read_len>\nattribute for the duration of the C<create()> method.\n\nThe flag values available for use with the C<'flags'> option\nare C<ZOO_EPHEMERAL> and C<ZOO_SEQUENCE>; both are\nincluded in the C<:flags> tagset.  The flags should be\ncombined with the bitwise OR operator if more than one\nis required.\n\nThe C<ZOO_EPHEMERAL> flag causes the node to be marked as\nephemeral, meaning it will be automatically deleted if it\nstill exists when the client's session ends.  The\nC<ZOO_SEQUENCE> flag causes a unique integer to be appended\nto the node's final path component.  See the ZooKeeper\ndocumentation for additional advice on how to use these flags.\n\nWhen creating a node it may be important to define an ACL\nfor it; to do this, pass a reference to an ACL array (as\ndescribed in L</Access Control>) using the C<'acl'> option.\nSee also the C<:acl_perms> and C<:acls> tagsets for lists\nof the available ACL permission flags and pre-defined ACLs.\n\n=item delete()\n\n  $ret = $zkh->delete($path);\n  $ret = $zkh->delete($path, 'version' => $version);\n\nRequests that a node be deleted from the ZooKeeper hierarchy.\nReturns true upon success, false otherwise.  \n\nIf a value for the C<'version'> option is supplied, the node\nwill only be deleted if its version number matches the given\nvalue.  See the C<version> attribute of the Net::ZooKeeper::Stat\nclass for details on node version numbering.\n\n=item exists()\n\n  $ret = $zkh->exists($path);\n  $ret = $zkh->exists($path, 'stat' => $stat, 'watch' => $watch);\n\nTests whether a given node exists.  Returns true if the node\nexists, otherwise false.  When the C<exists()> method is successful\nbut the node does not exist, it returns false, and C<get_error()>\nwill return C<ZNONODE> until another method is called on the\nhandle object.\n\nThe C<'stat'> option may be used to request that a\nNet::ZooKeeper::Stat object be updated with the node's\ncurrent state information.  The stat object will only be\nupdated if the node exists and the C<exists()> method\nsucceeds.  The stat object must first have been created\nusing the C<stat()> method.\n\nThe C<'watch'> option may be used to request that a\nNet::ZooKeeper::Watch object be assigned to receive\nnotification of an event which alters the node's data.\nThe watch object must first have been created using the\nC<watch()> method.  If the watch object was previously\nassigned to receive notifications for another node, it\nwill be reassigned even if the C<exists()> method fails.\n\n=item get_children()\n\n  @child_names  = $zkh->get_children($path);\n  $num_children = $zkh->get_children($path, 'watch' => $watch);\n\nQueries the names or number of the child nodes stored beneath\na given node in the ZooKeeper hierarchy.  In a list context,\nreturns a list of the child nodes' names upon success, otherwise\nan empty list.  When the C<get_children()> method is successful\nbut there are no child nodes, it returns an empty list, and\nC<get_error()> will return C<ZOK> until another method is called\non the handle object.\n\nIn a scalar context, C<get_children()> returns the number\nof child nodes upon success, otherwise undef.\n\nThe names of the child nodes are simply the final component\nof the nodes' paths, i.e., the portion of their path which\nfollows the path of the given parent node, excluding the\n\"/\" delimiter.\n\nThe C<'watch'> option may be used to request that a\nNet::ZooKeeper::Watch object be assigned to receive\nnotification of an event which alters the node's list of\nchild nodes.  The watch object must first have been created\nusing the C<watch()> method.  If the watch object was\npreviously assigned to receive notifications for another node,\nit will be reassigned even if the C<get_children()> method fails.\n\n=item get()\n\n  $data = $zkh->get($path);\n  $data = $zkh->get($path, 'data_read_len' => 100,\n                    'stat' => $stat, 'watch' => $watch);\n\nQueries the data stored in a given node.  Returns the\ndata as a string upon success, otherwise undef.  Note\nthat the data may contain nulls if the node's data is\nnot a text string.\n\nIf the length of the node's data exceeds the current value\nof the handle object's C<data_read_len> attribute, the\nstring returned by the C<get()> method will be truncated;\nnote that the node's data in the ZooKeeper cluster is not\naffected by this truncation.\n\nSpecifying a value for the C<'data_read_len'> option will\ntemporarily override the value of the C<data_read_len>\nattribute for the duration of the C<get()> method.\n\nThe C<'stat'> option may be used to request that a\nNet::ZooKeeper::Stat object be updated with the node's\ncurrent state information.  The stat object will only be\nupdated if the C<get()> method succeeds.  The stat object\nmust first have been created using the C<stat()> method.\n\nThe C<'watch'> option may be used to request that a\nNet::ZooKeeper::Watch object be assigned to receive\nnotification of an event which alters the node's data.\nThe watch object must first have been created using the\nC<watch()> method.  If the watch object was previously\nassigned to receive notifications for another node, it\nwill be reassigned even if the C<get()> method fails.\n\n=item set()\n\n  $ret = $zkh->set($path, $data);\n  $ret = $zkh->set($path, $data, 'version' => $version,\n                   'stat' => $stat);\n\nRequests that a node's data be updated in the ZooKeeper\nhierarchy.  Returns true upon success, false otherwise.  \n\nIf a value for the C<'version'> option is supplied, the node's\ndata will only be updated if its version number matches the\ngiven value.  See the C<version> attribute of the\nNet::ZooKeeper::Stat class for details on node version numbering.\n\nThe C<'stat'> option may be used to request that a\nNet::ZooKeeper::Stat object be updated with the node's\ncurrent state information.  The stat object will only be\nupdated if the C<set()> method succeeds.  The stat object\nmust first have been created using the C<stat()> method.\n\n=item get_acl()\n\n  @acl = $zkh->get_acl($path);\n  $num_acl_entries = $zkh->get_acl($path, 'stat' => $stat);\n\nQueries the ACL associated with a node in the ZooKeeper\nhierarchy, if any.  In a list context, returns an array with\nthe node's ACL entries upon success, otherwise\nan empty list.  When the C<get_acl()> method is successful\nbut there are no ACL entries, it returns an empty list, and\nC<get_error()> will return C<ZOK> until another method is called\non the handle object.\n\nThe elements of the returned array are hashes, each of which\nrepresents one ACL entry.  Each hash contains C<perms>,\nC<scheme>, and C<id> elements.  See the L</Access Control>\nsection for additional details, and the\nC<:acl_perms> and C<:acls> tagsets for lists of the\navailable ACL permission flags and pre-defined ACLs.\n\nIn a scalar context, C<get_acl()> returns the number\nof ACL entries upon success, otherwise undef.\n\nThe C<'stat'> option may be used to request that a\nNet::ZooKeeper::Stat object be updated with the node's\ncurrent state information.  The stat object will only be\nupdated if the C<get_acl()> method succeeds.  The stat object\nmust first have been created using the C<stat()> method.\n\n=item set_acl()\n\n  $acl = [{\n    'perms' => (ZOO_PERM_READ | ZOO_PERM_WRITE),\n    'scheme' => 'digest',\n    'id' => \"$username:$digest\"\n  }];\n  $ret = $zkh->set_acl($path, $acl);\n  $ret = $zkh->set_acl($path, ZOO_OPEN_ACL_UNSAFE,\n                       'version' => $version);\n\nRequests that a node's ACL be updated in the ZooKeeper\nhierarchy.  Returns true upon success, false otherwise.\n\nThe ACL should be passed as a reference to an array of\nhashes, where each hash represents one ACL entry.  Each\nhash should contain  C<perms>, C<scheme>, and C<id> elements\nas described in the L</Access Control> section.\nSee also the C<:acl_perms> and C<:acls> tagsets for lists\nof the available ACL permission flags and pre-defined ACLs.\n\nIf a value for the C<'version'> option is supplied, the node's\nACL will only be updated if its version number matches the\ngiven value.  See the C<version> attribute of the\nNet::ZooKeeper::Stat class for details on node version numbering.\n\n=item stat()\n\n  $stat = $zkh->stat();\n\nCreates a new Net::ZooKeeper::Stat object which may be used\nwith the C<'stat'> option of the C<exists()>, C<get()>,\nC<set()>, and C<get_acl()> methods.  When the stat object\nis passed to any of these methods, upon success its attribute\nvalues are updated to reflect the current state of the\nnode specified in the method call.  The stat object is not\nupdated if the method call does not succeed.\n\n=item watch()\n\n  $watch = $zkh->watch();\n  $watch = $zkh->watch('timeout' => $timeout);\n\nCreates a new Net::ZooKeeper::Watch object which may be\nused to wait for event notifications from the ZooKeeper\ncluster.  Each time the watch object is passed to any\nof the C<exists()>, C<get_children()>, or C<get()> methods,\nits attribute values are immediately reset to zero, and will\nlater be updated upon receipt of an appropriate event\nnotification for the node specified in the method call.\n\nThe specific types of events which cause notifications to be\nsent by the ZooKeeper cluster depend on the method call used.\nAfter use with the C<exists()> and C<get()> methods, the\nwatch object will be set to receive an event notification\ncaused by a modification of the node's data or the node itself\n(e.g., deletion of the node).  After use with the\nC<get_children()> method, the watch object will be set to\nreceive an event notification caused by a modification\nof the node's list of child nodes.\n\nWatch objects receive at most one event notification after\ntheir assignment to a node by one of the C<exists()>,\nC<get_children()>, or C<get()> methods.  Note that in the\ncase of an error, the watch object may never receive any\nevent notification.  However, when the parent Net::ZooKeeper\nhandle object experiences a connection error, the ZooKeeper\nclient code will notify all pending watches with an event of\ntype C<ZOO_SESSION_EVENT>.  See C<wait()> for more information\nregarding the watch object's attribute values after a\nconnection error.\n\nA watch object may be reused with another C<exists()>,\nC<get_children()>, or C<get()> method call at any time,\nin which case the watch object's attribute values\nare reset to zero and the watch object will no longer be updated\nby any event notification relevant to the previous method call.\n\nWhen the C<watch()> method is invoked without a C<'timeout'>\noption, it returns a newly created watch object whose C<timeout>\nattribute value is initialized to the current value of the\nNet::ZooKeeper handle object's C<watch_timeout> attribute.\nOtherwise, when the C<watch()> method is invoked with a\nC<'timeout'> option, the new watch object's C<timeout> attribute\nvalue is initialized to the value specified by the\nC<'timeout'> option.\n\nSee also the C<watch_timeout> attribute, and the C<timeout>\nattribute and C<wait()> method of the Net::ZooKeeper::Watch\nclass.\n\n=back\n\n=head2 Net::ZooKeeper::Stat\n\nNo methods are defined for the Net::ZooKeeper::Stat class.\n\n=head2 Net::ZooKeeper::Watch\n\nOnly one method is defined for the Net::ZooKeeper::Watch class.\n\n=over 4\n\n=item wait()\n\n  $ret = $watch->wait();\n  $ret = $watch->wait('timeout' => $timeout);\n\nWaits for an event notification from the ZooKeeper cluster\nfor the node most recently associated with the watch object.\nNodes are associated with a watch object by passing the\nwatch object as the value of a C<'watch'> option to a\nNet::ZooKeeper method; methods which accept a C<'watch'> option\nare C<exists()>, C<get_children()>, and C<get()>.\n\nWhen the C<wait()> method is invoked with a C<'timeout'>\noption, it waits for no more than the number of milliseconds\nspecified by the C<'timeout'> option.\nOtherwise, when the C<wait()> method is invoked without a\nC<'timeout'> option, it waits for no more than the timeout\nperiod specified by the value of the watch object's C<timeout>\nattribute.\n\nThe C<wait()> method returns true if an event notification\nwas received, otherwise false.  When C<wait()> returns true,\nthe C<event> and C<state> attributes of the watch object\nwill be updated with the event's type and the current\nconnection state.\n\nWhen the parent Net::ZooKeeper handle object experiences a\nconnection error, the ZooKeeper client code will notify all\npending watches with an event of type C<ZOO_SESSION_EVENT>.\nIn this case, the C<state> attribute will report the current\nstate of the connection to the ZooKeeper cluster.\n\nSee also the C<timeout> attribute, and the C<watch()> method\nand C<watch_timeout> attribute of the Net::ZooKeeper class.\n\n=back\n\n=head1 FUNCTIONS\n\nThe following functions have global scope and affect all\nNet::ZooKeeper handle objects.\n\n=over 4\n\n=item set_log_level()\n\n  Net::ZooKeeper::set_log_level($level);\n\nThe C<Net::ZooKeeper::set_log_level()> function may be called to\nalter the number and type of messages written to the current log\nfile handle (if any).  The default value is C<ZOO_LOG_LEVEL_OFF>\nwhich disables all logging.\n\nSee the L</Logging> section for more details and C<:log_levels>\nfor a list of the available log levels.\n\n=item set_deterministic_conn_order()\n\n  Net::ZooKeeper::set_deterministic_conn_order(1);\n\nThe C<Net::ZooKeeper::set_deterministic_conn_order()> function\nmay be called to indicate whether or not the list of ZooKeeper\nservers passed to the C<new()> method should be randomly permuted.\nIf set to a true value, the list of servers will not be altered.\nThe default false value indicates the list of servers will\nbe randomly reordered prior to connection.\n\nSee the L</Connection Order> section for more details.\n\n=back\n\n=head1 EXPORTS\n\nNothing is exported by default.  Various tagsets exist which\ngroup the tags available for export into different categories:\n\n=over 4\n\n=item :errors\n\nZooKeeper error codes.  These may be compared to the values\nreturned by the C<get_error()> method.\n\n=item :node_flags\n\nThe ZooKeeper node flags C<ZOO_EPHEMERAL> and C<ZOO_SEQUENCE>,\nwhich may be passed in the C<'flags'> option to the C<create()>\nmethod.  When more than node flag is required they\nshould be combined using the bitwise OR operator.\n\n=item :acl_perms\n\nThe ZooKeeper ACL permission flags which may be used in\nthe value of the C<perms> attribute of an ACL entry hash.\nWhen more than one ACL permission flag is required they\nshould be combined using the bitwise OR operator.\n\nThe available ACL permission flags are C<ZOO_PERM_READ>,\nC<ZOO_PERM_WRITE>, C<ZOO_PERM_CREATE>, C<ZOO_PERM_DELETE>,\nand C<ZOO_PERM_ADMIN>.  For convenience, C<ZOO_PERM_ALL> is\ndefined as the bitwise OR of all of these flags.\n\n=item :acls\n\nCommon ZooKeeper ACLs which may be useful.  C<ZOO_OPEN_ACL_UNSAFE>\nspecifies a node which is entirely open to all users with no\nrestrictions at all.  C<ZOO_READ_ACL_UNSAFE> specifies\na node which is readable by all users; permissions for other actions\nare not defined in this ACL.  C<ZOO_CREATOR_ALL_ACL> specifies a node\nfor which all actions require the same authentication credentials as\nheld by the session which created the node; this implies that a\nsession should authenticate with an appropriate scheme before\ncreating a node with this ACL.\n\n=item :events\n\nThe ZooKeeper event types which are returned in value of\nthe C<event> attribute a Net::ZooKeeper::Watch object after\nan event occurs on a watched node.\n\n=item :states\n\nThe ZooKeeper connection states which are returned in value of\nthe C<state> attribute of a Net::ZooKeeper::Watch object after\nan event occurs on a watched node.\n\n=item :log_levels\n\nThe ZooKeeper log levels which may be passed to the\nC<Net::ZooKeeper::set_log_level()> function.  The available\nlog levels are, from least to most verbose, C<ZOO_LOG_LEVEL_OFF>\n(the default), C<ZOO_LOG_LEVEL_ERROR>, C<ZOO_LOG_LEVEL_WARN>,\nC<ZOO_LOG_LEVEL_INFO>, and C<ZOO_LOG_LEVEL_DEBUG>.\n\n=item :all\n\nEverything from all of the above tagsets.\n\n=back\n\n=head1 SEE ALSO\n\nThe Apache ZooKeeper project's home page at\nL<http://zookeeper.apache.org/> provides a wealth of detail\non how to develop applications using ZooKeeper.\n\n=head1 AUTHOR\n\nChris Darroch, E<lt>chrisd@apache.orgE<gt>\n\n=head1 COPYRIGHT AND LICENSE\n\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n=cut\n\n"
  },
  {
    "path": "src/contrib/zkperl/ZooKeeper.xs",
    "content": "/* Net::ZooKeeper - Perl extension for Apache ZooKeeper\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#define PERL_NO_GET_CONTEXT\n\n#include \"EXTERN.h\"\n#include \"perl.h\"\n#include \"XSUB.h\"\n\n#include <pthread.h>                    /* pthread_mutex_lock(), etc. */\n#include <string.h>                     /* memset(), etc. */\n#include <limits.h>                     /* CHAR_BIT */\n#include <sys/time.h>                   /* gettimeofday() */\n\n#include <zookeeper/zookeeper.h>\n\n#include \"build/check_zk_version.h\"\n\n\n#define PACKAGE_NAME \"Net::ZooKeeper\"\n#define PACKAGE_SIGNATURE 19631123\n\n#define STAT_PACKAGE_NAME \"Net::ZooKeeper::Stat\"\n#define STAT_PACKAGE_SIGNATURE 19960512\n\n#define WATCH_PACKAGE_NAME \"Net::ZooKeeper::Watch\"\n#define WATCH_PACKAGE_SIGNATURE 20050326\n\n#define MAX_KEY_NAME_LEN 16             /* \"children_version\" */\n\n#define NUM_ACL_ENTRY_KEYS 3\n#define NUM_KEYS 7\n#define NUM_STAT_KEYS 11\n#define NUM_WATCH_KEYS 3\n\n#define DEFAULT_RECV_TIMEOUT_MSEC 10000\n\n#define DEFAULT_DATA_BUF_LEN 1023\n#define DEFAULT_PATH_BUF_LEN 1023\n#define DEFAULT_WATCH_TIMEOUT 60000\n\n#define ZOO_LOG_LEVEL_OFF 0\n\n#ifndef strcaseEQ\n#define strcaseEQ(a,b) (!strcasecmp((a),(b)))\n#endif\n\n\ntypedef struct Stat zk_stat_t;\n\ntypedef HV* Net__ZooKeeper__Stat;\n\ntypedef struct zk_watch_t zk_watch_t;\n\nstruct zk_watch_t {\n    pthread_mutex_t mutex;\n    pthread_cond_t cond;\n    int done;\n    int ret;\n    int event_type;\n    int event_state;\n    unsigned int timeout;\n    zk_watch_t *prev;\n    zk_watch_t *next;\n    int ref_count;\n};\n\ntypedef HV* Net__ZooKeeper__Watch;\n\ntypedef struct {\n    zhandle_t *handle;\n    zk_watch_t *first_watch;\n    int data_buf_len;\n    int path_buf_len;\n    unsigned int watch_timeout;\n    const char *hosts;\n    int hosts_len;\n    int last_ret;\n    int last_errno;\n} zk_t;\n\ntypedef HV* Net__ZooKeeper;\n\ntypedef struct {\n    I32 signature;\n    union {\n        zk_t *zk;\n        zk_stat_t *stat;\n        zk_watch_t *watch;\n    } handle;\n} zk_handle_t;\n\ntypedef struct {\n    const char name[MAX_KEY_NAME_LEN + 1];\n    U32 name_len;\n    size_t offset;\n    size_t size;\n    U32 hash;\n} zk_key_t;\n\n\nstatic zk_key_t zk_acl_entry_keys[NUM_ACL_ENTRY_KEYS] = {\n    {\"perms\", 0, 0, 0, 0},\n    {\"scheme\", 0, 0, 0, 0},\n    {\"id\", 0, 0, 0, 0}\n};\n\nstatic zk_key_t zk_keys[NUM_KEYS] = {\n    {\"data_read_len\", 0, 0, 0, 0},\n    {\"path_read_len\", 0, 0, 0, 0},\n    {\"watch_timeout\", 0, 0, 0, 0},\n    {\"hosts\", 0, 0, 0, 0},\n    {\"session_timeout\", 0, 0, 0, 0},\n    {\"session_id\", 0, 0, 0, 0},\n    {\"pending_watches\", 0, 0, 0, 0}\n};\n\nstatic zk_key_t zk_stat_keys[NUM_STAT_KEYS] = {\n    {\"czxid\", 0, offsetof(struct Stat, czxid),\n     sizeof(((struct Stat*) 0)->czxid), 0},\n    {\"mzxid\", 0, offsetof(struct Stat, mzxid),\n     sizeof(((struct Stat*) 0)->mzxid), 0},\n    {\"ctime\", 0, offsetof(struct Stat, ctime),\n     sizeof(((struct Stat*) 0)->ctime), 0},\n    {\"mtime\", 0, offsetof(struct Stat, mtime),\n     sizeof(((struct Stat*) 0)->mtime), 0},\n    {\"version\", 0, offsetof(struct Stat, version),\n     sizeof(((struct Stat*) 0)->version), 0},\n    {\"children_version\", 0, offsetof(struct Stat, cversion),\n     sizeof(((struct Stat*) 0)->cversion), 0},\n    {\"acl_version\", 0, offsetof(struct Stat, aversion),\n     sizeof(((struct Stat*) 0)->aversion), 0},\n    {\"ephemeral_owner\", 0, offsetof(struct Stat, ephemeralOwner),\n     sizeof(((struct Stat*) 0)->ephemeralOwner), 0},\n    {\"data_len\", 0, offsetof(struct Stat, dataLength),\n     sizeof(((struct Stat*) 0)->dataLength), 0},\n    {\"num_children\", 0, offsetof(struct Stat, numChildren),\n     sizeof(((struct Stat*) 0)->numChildren), 0},\n    {\"children_zxid\", 0, offsetof(struct Stat, pzxid),\n     sizeof(((struct Stat*) 0)->pzxid), 0}\n};\n\nstatic zk_key_t zk_watch_keys[NUM_WATCH_KEYS] = {\n    {\"timeout\", 0, 0, 0, 0},\n    {\"event\", 0, 0, 0, 0},\n    {\"state\", 0, 0, 0, 0}\n};\n\n\nstatic void _zk_watcher(zhandle_t *handle, int type, int state,\n                        const char *path, void *context)\n{\n    zk_watch_t *watch_ctx = context;\n\n    pthread_mutex_lock(&watch_ctx->mutex);\n\n    watch_ctx->event_type = type;\n    watch_ctx->event_state = state;\n\n    watch_ctx->done = 1;\n\n    pthread_cond_signal(&watch_ctx->cond);\n    pthread_mutex_unlock(&watch_ctx->mutex);\n\n    return;\n}\n\nstatic void _zk_auth_completion(int ret, const void *data)\n{\n    zk_watch_t *watch_ctx = (zk_watch_t*) data;\n\n    pthread_mutex_lock(&watch_ctx->mutex);\n\n    watch_ctx->ret = ret;\n\n    watch_ctx->done = 1;\n\n    pthread_cond_signal(&watch_ctx->cond);\n    pthread_mutex_unlock(&watch_ctx->mutex);\n\n    return;\n}\n\nstatic zk_watch_t *_zk_create_watch(pTHX)\n{\n    zk_watch_t *watch;\n\n    Newxz(watch, 1, zk_watch_t);\n\n    if (pthread_mutex_init(&watch->mutex, NULL)) {\n        int save_errno = errno;\n\n        Safefree(watch);\n\n        errno = save_errno;\n        return NULL;\n    }\n\n    if (pthread_cond_init(&watch->cond, NULL)) {\n        int save_errno = errno;\n\n        pthread_mutex_destroy(&watch->mutex);\n        Safefree(watch);\n\n        errno = save_errno;\n        return NULL;\n    }\n\n    return watch;\n}\n\nstatic void _zk_destroy_watch(pTHX_ zk_watch_t *watch)\n{\n    pthread_cond_destroy(&watch->cond);\n    pthread_mutex_destroy(&watch->mutex);\n\n    Safefree(watch);\n\n    return;\n}\n\nstatic zk_watch_t *_zk_acquire_watch(pTHX)\n{\n    zk_watch_t *watch = _zk_create_watch(aTHX);\n\n    if (watch) {\n        watch->ref_count = 1;\n    }\n\n    return watch;\n}\n\nstatic void _zk_release_watch(pTHX_ zk_watch_t *watch, int list)\n{\n    if (list) {\n        if (watch->prev) {\n            watch->prev->next = watch->next;\n        }\n        if (watch->next) {\n            watch->next->prev = watch->prev;\n        }\n        watch->prev = NULL;\n        watch->next = NULL;\n    }\n\n    if (--watch->ref_count == 0) {\n        _zk_destroy_watch(aTHX_ watch);\n    }\n\n    return;\n}\n\nstatic unsigned int _zk_release_watches(pTHX_ zk_watch_t *first_watch,\n                                        int final)\n{\n    zk_watch_t *watch = first_watch->next;\n    unsigned int pending_watches = 0;\n\n    while (watch) {\n        zk_watch_t *next_watch = watch->next;\n        int done = final;\n\n        if (!final) {\n            pthread_mutex_lock(&watch->mutex);\n            done = watch->done;\n            pthread_mutex_unlock(&watch->mutex);\n        }\n\n        if (done) {\n            _zk_release_watch(aTHX_ watch, 1);\n        }\n        else {\n            ++pending_watches;\n        }\n\n        watch = next_watch;\n    }\n\n    return pending_watches;\n}\n\nstatic void _zk_replace_watch(pTHX_ zk_handle_t *handle,\n                              zk_watch_t *first_watch,\n                              zk_watch_t *old_watch, zk_watch_t *new_watch)\n{\n    zk_watch_t *next_watch;\n\n    new_watch->timeout = old_watch->timeout;\n\n    _zk_release_watch(aTHX_ old_watch, 0);\n\n    /* cleanup any completed watches not tied to a handle */\n    _zk_release_watches(aTHX_ first_watch, 0);\n\n    next_watch = first_watch->next;\n\n    new_watch->prev = first_watch;\n    new_watch->next = next_watch;\n\n    if (next_watch) {\n        next_watch->prev = new_watch;\n    }\n\n    first_watch->next = new_watch;\n\n    ++new_watch->ref_count;\n\n    handle->handle.watch = new_watch;\n\n    return;\n}\n\nstatic void _zk_free_acl(pTHX_ struct ACL_vector *acl)\n{\n    if (acl->data) {\n        Safefree(acl->data);\n    }\n\n    return;\n}\n\nstatic const char *_zk_fill_acl(pTHX_ AV *acl_arr, struct ACL_vector *acl)\n{\n    I32 num_acl_entries = av_len(acl_arr) + 1;\n    int i;\n\n    Zero(acl, 1, struct ACL_vector);\n\n    if (num_acl_entries <= 0) {\n        return NULL;\n    }\n    else if (num_acl_entries > PERL_INT_MAX) {\n        num_acl_entries = PERL_INT_MAX;\n    }\n\n    Newx(acl->data, num_acl_entries, struct ACL);\n\n    for (i = 0; i < num_acl_entries; ++i) {\n        SV **acl_entry_ptr;\n        HV *acl_entry_hash;\n        zk_key_t *key;\n        SV **val_ptr;\n        struct ACL acl_entry;\n\n        acl_entry_ptr = av_fetch(acl_arr, i, 0);\n\n        if (!acl_entry_ptr) {\n            continue;\n        }\n\n        if (!SvROK(*acl_entry_ptr) ||\n            SvTYPE(SvRV(*acl_entry_ptr)) != SVt_PVHV) {\n            _zk_free_acl(aTHX_ acl);\n\n            return \"invalid ACL entry hash reference\";\n        }\n\n        acl_entry_hash = (HV*) SvRV(*acl_entry_ptr);\n\n        key = &zk_acl_entry_keys[0];\n        val_ptr = hv_fetch(acl_entry_hash, key->name, key->name_len, 0);\n\n        if (!val_ptr) {\n            _zk_free_acl(aTHX_ acl);\n\n            return \"no ACL entry perms element\";\n        }\n\n        acl_entry.perms = SvIV(*val_ptr);\n\n        if (!acl_entry.perms || (acl_entry.perms & ~ZOO_PERM_ALL)) {\n            _zk_free_acl(aTHX_ acl);\n\n            return \"invalid ACL entry perms\";\n        }\n\n        key = &zk_acl_entry_keys[1];\n        val_ptr = hv_fetch(acl_entry_hash, key->name, key->name_len, 0);\n\n        if (!val_ptr) {\n            _zk_free_acl(aTHX_ acl);\n\n            return \"no ACL entry scheme element\";\n        }\n\n        acl_entry.id.scheme = SvPV_nolen(*val_ptr);\n\n        key = &zk_acl_entry_keys[2];\n        val_ptr = hv_fetch(acl_entry_hash, key->name, key->name_len, 0);\n\n        if (!val_ptr) {\n            _zk_free_acl(aTHX_ acl);\n\n            return \"no ACL entry id element\";\n        }\n\n        acl_entry.id.id = SvPV_nolen(*val_ptr);\n\n        ++acl->count;\n        acl->data[i] = acl_entry;\n    }\n\n    return NULL;\n}\n\nstatic void _zk_fill_acl_entry_hash(pTHX_ struct ACL *acl_entry,\n                                    HV *acl_entry_hash)\n{\n    zk_key_t *key;\n    SV *val;\n\n    key = &zk_acl_entry_keys[0];\n    val = newSViv(acl_entry->perms);\n\n    if (!hv_store(acl_entry_hash, key->name, key->name_len, val, key->hash)) {\n        SvREFCNT_dec(val);\n    }\n\n    key = &zk_acl_entry_keys[1];\n    val = newSVpv(acl_entry->id.scheme, 0);\n\n    if (!hv_store(acl_entry_hash, key->name, key->name_len, val, key->hash)) {\n        SvREFCNT_dec(val);\n    }\n\n    key = &zk_acl_entry_keys[2];\n    val = newSVpv(acl_entry->id.id, 0);\n\n    if (!hv_store(acl_entry_hash, key->name, key->name_len, val, key->hash)) {\n        SvREFCNT_dec(val);\n    }\n\n    return;\n}\n\nstatic zk_handle_t *_zk_check_handle_inner(pTHX_ HV *attr_hash,\n                                           I32 package_signature)\n{\n    zk_handle_t *handle = NULL;\n\n    if (SvRMAGICAL(attr_hash)) {\n        MAGIC *magic = mg_find((SV*) attr_hash, PERL_MAGIC_ext);\n\n        if (magic) {\n            handle = (zk_handle_t*) magic->mg_ptr;\n\n            if (handle->signature != package_signature) {\n                handle = NULL;\n            }\n        }\n    }\n\n    return handle;\n}\n\nstatic zk_handle_t *_zk_check_handle_outer(pTHX_ HV *hash, HV **attr_hash_ptr,\n                                           const char *package_name,\n                                           I32 package_signature)\n{\n    zk_handle_t *handle = NULL;\n\n    if (attr_hash_ptr) {\n        *attr_hash_ptr = NULL;\n    }\n\n    if (SvRMAGICAL((SV*) hash)) {\n        MAGIC *magic = mg_find((SV*) hash, PERL_MAGIC_tied);\n\n        if (magic) {\n            SV *attr = magic->mg_obj;\n\n            if (SvROK(attr) && SvTYPE(SvRV(attr)) == SVt_PVHV &&\n                sv_derived_from(attr, package_name)) {\n                HV *attr_hash = (HV*) SvRV(attr);\n\n                handle = _zk_check_handle_inner(aTHX_ attr_hash,\n                                                package_signature);\n\n                if (handle && attr_hash_ptr) {\n                    *attr_hash_ptr = attr_hash;\n                }\n            }\n        }\n    }\n\n    return handle;\n}\n\nstatic zk_t *_zk_get_handle_inner(pTHX_ Net__ZooKeeper attr_hash)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_inner(aTHX_ attr_hash, PACKAGE_SIGNATURE);\n\n    return handle ? handle->handle.zk : NULL;\n}\n\nstatic zk_t *_zk_get_handle_outer(pTHX_ Net__ZooKeeper zkh)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_outer(aTHX_ zkh, NULL, PACKAGE_NAME,\n                                    PACKAGE_SIGNATURE);\n\n    return handle ? handle->handle.zk : NULL;\n}\n\nstatic zk_stat_t *_zks_get_handle_inner(pTHX_ Net__ZooKeeper__Stat attr_hash)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_inner(aTHX_ attr_hash, STAT_PACKAGE_SIGNATURE);\n\n    return handle ? handle->handle.stat : NULL;\n}\n\nstatic zk_stat_t *_zks_get_handle_outer(pTHX_ Net__ZooKeeper__Stat zksh)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_outer(aTHX_ zksh, NULL, STAT_PACKAGE_NAME,\n                                    STAT_PACKAGE_SIGNATURE);\n\n    return handle ? handle->handle.stat : NULL;\n}\n\nstatic zk_watch_t *_zkw_get_handle_inner(pTHX_ Net__ZooKeeper__Watch attr_hash)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_inner(aTHX_ attr_hash, WATCH_PACKAGE_SIGNATURE);\n\n    return handle ? handle->handle.watch : NULL;\n}\n\nstatic zk_watch_t *_zkw_get_handle_outer(pTHX_ Net__ZooKeeper__Watch zkwh,\n                                         zk_handle_t **handle_ptr)\n{\n    zk_handle_t *handle;\n\n    handle = _zk_check_handle_outer(aTHX_ zkwh, NULL, WATCH_PACKAGE_NAME,\n                                    WATCH_PACKAGE_SIGNATURE);\n\n    if (handle_ptr) {\n        *handle_ptr = handle;\n    }\n\n    return handle ? handle->handle.watch : NULL;\n}\n\n\nMODULE = Net::ZooKeeper  PACKAGE = Net::ZooKeeper  PREFIX = zk_\n\nREQUIRE: 1.9508\n\nPROTOTYPES: ENABLE\n\nBOOT:\n{\n    int i;\n\n    for (i = 0; i < NUM_ACL_ENTRY_KEYS; ++i) {\n        zk_key_t *key = &zk_acl_entry_keys[i];\n\n        key->name_len = strlen(key->name);\n        PERL_HASH(key->hash, key->name, key->name_len);\n    }\n\n    for (i = 0; i < NUM_KEYS; ++i) {\n        zk_keys[i].name_len = strlen(zk_keys[i].name);\n    }\n\n    for (i = 0; i < NUM_STAT_KEYS; ++i) {\n        zk_stat_keys[i].name_len = strlen(zk_stat_keys[i].name);\n    }\n\n    for (i = 0; i < NUM_WATCH_KEYS; ++i) {\n        zk_watch_keys[i].name_len = strlen(zk_watch_keys[i].name);\n    }\n\n    zoo_set_log_stream(NULL);\n    zoo_set_debug_level(0);\n}\n\n\nI32\nzk_constant(alias=Nullch)\n        char *alias\n    ALIAS:\n        ZOK = ZOK\n        ZSYSTEMERROR = ZSYSTEMERROR\n        ZRUNTIMEINCONSISTENCY = ZRUNTIMEINCONSISTENCY\n        ZDATAINCONSISTENCY = ZDATAINCONSISTENCY\n        ZCONNECTIONLOSS = ZCONNECTIONLOSS\n        ZMARSHALLINGERROR = ZMARSHALLINGERROR\n        ZUNIMPLEMENTED = ZUNIMPLEMENTED\n        ZOPERATIONTIMEOUT = ZOPERATIONTIMEOUT\n        ZBADARGUMENTS = ZBADARGUMENTS\n        ZINVALIDSTATE = ZINVALIDSTATE\n        ZAPIERROR = ZAPIERROR\n        ZNONODE = ZNONODE\n        ZNOAUTH = ZNOAUTH\n        ZBADVERSION = ZBADVERSION\n        ZNOCHILDRENFOREPHEMERALS = ZNOCHILDRENFOREPHEMERALS\n        ZNODEEXISTS = ZNODEEXISTS\n        ZNOTEMPTY = ZNOTEMPTY\n        ZSESSIONEXPIRED = ZSESSIONEXPIRED\n        ZINVALIDCALLBACK = ZINVALIDCALLBACK\n        ZINVALIDACL = ZINVALIDACL\n        ZAUTHFAILED = ZAUTHFAILED\n        ZCLOSING = ZCLOSING\n        ZNOTHING = ZNOTHING\n\n        ZOO_EPHEMERAL = ZOO_EPHEMERAL\n        ZOO_SEQUENCE = ZOO_SEQUENCE\n\n        ZOO_PERM_READ = ZOO_PERM_READ\n        ZOO_PERM_WRITE = ZOO_PERM_WRITE\n        ZOO_PERM_CREATE = ZOO_PERM_CREATE\n        ZOO_PERM_DELETE = ZOO_PERM_DELETE\n        ZOO_PERM_ADMIN = ZOO_PERM_ADMIN\n        ZOO_PERM_ALL = ZOO_PERM_ALL\n\n        ZOO_CREATED_EVENT = ZOO_CREATED_EVENT\n        ZOO_DELETED_EVENT = ZOO_DELETED_EVENT\n        ZOO_CHANGED_EVENT = ZOO_CHANGED_EVENT\n        ZOO_CHILD_EVENT = ZOO_CHILD_EVENT\n        ZOO_SESSION_EVENT = ZOO_SESSION_EVENT\n        ZOO_NOTWATCHING_EVENT = ZOO_NOTWATCHING_EVENT\n\n        ZOO_EXPIRED_SESSION_STATE = ZOO_EXPIRED_SESSION_STATE\n        ZOO_AUTH_FAILED_STATE = ZOO_AUTH_FAILED_STATE\n        ZOO_CONNECTING_STATE = ZOO_CONNECTING_STATE\n        ZOO_ASSOCIATING_STATE = ZOO_ASSOCIATING_STATE\n        ZOO_CONNECTED_STATE = ZOO_CONNECTED_STATE\n\n        ZOO_LOG_LEVEL_OFF = ZOO_LOG_LEVEL_OFF\n        ZOO_LOG_LEVEL_ERROR = ZOO_LOG_LEVEL_ERROR\n        ZOO_LOG_LEVEL_WARN = ZOO_LOG_LEVEL_WARN\n        ZOO_LOG_LEVEL_INFO = ZOO_LOG_LEVEL_INFO\n        ZOO_LOG_LEVEL_DEBUG = ZOO_LOG_LEVEL_DEBUG\n    CODE:\n         if (!ix) {\n             if (!alias) {\n                 alias = GvNAME(CvGV(cv));\n             }\n\n             if (strEQ(alias, \"ZOK\")) {\n                 RETVAL = ZOK;\n             }\n             else if (strEQ(alias, \"ZOO_LOG_LEVEL_OFF\")) {\n                 RETVAL = ZOO_LOG_LEVEL_OFF;\n             }\n             else {\n                 Perl_croak(aTHX_ \"unknown \" PACKAGE_NAME \" constant: %s\",\n                            alias);\n             }\n         }\n         else {\n             RETVAL = ix;\n         }\n    OUTPUT:\n        RETVAL\n\n\nAV *\nzk_acl_constant(alias=Nullch)\n        char *alias\n    ALIAS:\n        ZOO_OPEN_ACL_UNSAFE = 1\n        ZOO_READ_ACL_UNSAFE = 2\n        ZOO_CREATOR_ALL_ACL = 3\n    PREINIT:\n        struct ACL_vector acl;\n        AV *acl_arr;\n        int i;\n    PPCODE:\n        if (!ix && !alias) {\n            alias = GvNAME(CvGV(cv));\n        }\n\n        if (ix == 1 || (alias != NULL && strEQ(alias, \"ZOO_OPEN_ACL_UNSAFE\"))) {\n            acl = ZOO_OPEN_ACL_UNSAFE;\n        }\n        else if (ix == 2 || (alias != NULL && strEQ(alias, \"ZOO_READ_ACL_UNSAFE\"))) {\n            acl = ZOO_READ_ACL_UNSAFE;\n        }\n        else if (ix == 3 || (alias != NULL && strEQ(alias, \"ZOO_CREATOR_ALL_ACL\"))) {\n            acl = ZOO_CREATOR_ALL_ACL;\n        }\n        else {\n             Perl_croak(aTHX_ \"unknown \" PACKAGE_NAME \" constant: %s\", alias);\n        }\n\n        acl_arr = newAV();\n\n        av_extend(acl_arr, acl.count);\n\n        for (i = 0; i < acl.count; ++i) {\n            HV *acl_entry_hash = newHV();\n            SV *val;\n\n            _zk_fill_acl_entry_hash(aTHX_ &acl.data[i], acl_entry_hash);\n\n            val = newRV_noinc((SV*) acl_entry_hash);\n\n            if (!av_store(acl_arr, i, val)) {\n                SvREFCNT_dec(val);\n            }\n        }\n\n        ST(0) = sv_2mortal(newRV_noinc((SV*) acl_arr));\n\n        XSRETURN(1);\n\n\nvoid\nzk_set_log_level(level)\n        int level\n    PPCODE:\n        if (level < ZOO_LOG_LEVEL_OFF || level > ZOO_LOG_LEVEL_DEBUG) {\n            Perl_croak(aTHX_ \"invalid log level: %d\", level);\n        }\n\n        zoo_set_debug_level(level);\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzk_set_deterministic_conn_order(flag)\n        bool flag\n    PPCODE:\n        zoo_deterministic_conn_order(!!flag);\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzk_new(package, hosts, ...)\n        char *package\n        char *hosts\n    PREINIT:\n        int recv_timeout = DEFAULT_RECV_TIMEOUT_MSEC;\n        const clientid_t *client_id = NULL;\n        zk_t *zk;\n        zk_handle_t *handle;\n        HV *stash, *zk_hash, *attr_hash;\n        SV *attr;\n        int i;\n    PPCODE:\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"session_timeout\")) {\n                recv_timeout = SvIV(ST(i + 1));\n\n                /* NOTE: would be nice if requirement in zookeeper_interest()\n                 * that recv_timeout*2 be non-negative was documented\n                 */\n                if (recv_timeout < 0 || recv_timeout > (PERL_INT_MAX >> 1)) {\n                    Perl_croak(aTHX_ \"invalid session timeout: %d\",\n                               recv_timeout);\n                }\n            }\n            else if (strcaseEQ(key, \"session_id\")) {\n                STRLEN client_id_len;\n\n                client_id = (const clientid_t*) SvPV(ST(i + 1), client_id_len);\n\n                if (client_id_len != sizeof(clientid_t)) {\n                    Perl_croak(aTHX_ \"invalid session ID\");\n                }\n            }\n        }\n\n        Newxz(zk, 1, zk_t);\n\n        zk->handle = zookeeper_init(hosts, NULL, recv_timeout,\n                                    client_id, NULL, 0);\n\n        if (!zk->handle) {\n            Safefree(zk);\n\n            XSRETURN_UNDEF;\n        }\n\n        Newxz(zk->first_watch, 1, zk_watch_t);\n\n        zk->data_buf_len = DEFAULT_DATA_BUF_LEN;\n        zk->path_buf_len = DEFAULT_PATH_BUF_LEN;\n        zk->watch_timeout = DEFAULT_WATCH_TIMEOUT;\n\n        zk->hosts_len = strlen(hosts);\n        zk->hosts = savepvn(hosts, zk->hosts_len);\n\n        Newx(handle, 1, zk_handle_t);\n\n        handle->signature = PACKAGE_SIGNATURE;\n        handle->handle.zk = zk;\n\n        /* We use several tricks from DBI here.  The attr_hash is our\n         * empty inner hash; we attach extra magic to it in the form of\n         * our zk_handle_t structure.  Then we tie attr_hash to zk_hash,\n         * our outer hash.  This is what is passed around (by reference) by\n         * callers.\n         *\n         * Most methods use _zk_get_handle_outer() which finds our inner\n         * handle, then returns the zk_t structure from its extra magic\n         * pointer.\n         *\n         * However, the tied hash methods, FETCH(), STORE(), and so forth,\n         * receive an already-dereferenced inner handle hash.  This is\n         * because we bless both inner and outer handles into this class,\n         * so when a caller's code references a hash element in our\n         * outer handle, Perl detects its tied magic, looks up the\n         * tied object (our inner handle) and invokes the tied hash methods\n         * in its class on it.  Since we blessed it into the same class\n         * as the outer handle, these methods simply reside in our package.\n         */\n\n        stash = gv_stashpv(package, GV_ADDWARN);\n\n        attr_hash = newHV();\n\n        sv_magic((SV*) attr_hash, Nullsv, PERL_MAGIC_ext,\n                 (const char*) handle, 0);\n\n        attr = sv_bless(newRV_noinc((SV*) attr_hash), stash);\n\n        zk_hash = newHV();\n\n        sv_magic((SV*) zk_hash, attr, PERL_MAGIC_tied, Nullch, 0);\n        SvREFCNT_dec(attr);\n\n        ST(0) = sv_bless(sv_2mortal(newRV_noinc((SV*) zk_hash)), stash);\n\n        XSRETURN(1);\n\n\nvoid\nzk_DESTROY(zkh)\n        Net::ZooKeeper zkh\n    PREINIT:\n        zk_handle_t *handle;\n        HV *attr_hash;\n        int ret = ZBADARGUMENTS;\n    PPCODE:\n        handle = _zk_check_handle_outer(aTHX_ zkh, &attr_hash,\n                                        PACKAGE_NAME, PACKAGE_SIGNATURE);\n\n        if (!handle) {\n            handle = _zk_check_handle_inner(aTHX_ zkh, PACKAGE_SIGNATURE);\n\n            if (handle) {\n                attr_hash = zkh;\n                zkh = NULL;\n            }\n        }\n\n        if (handle) {\n            zk_t *zk = handle->handle.zk;\n\n            ret = zookeeper_close(zk->handle);\n\n            /* detach all now-inactive watches still tied to handles */\n            _zk_release_watches(aTHX_ zk->first_watch, 1);\n\n            Safefree(zk->first_watch);\n            Safefree(zk->hosts);\n            Safefree(zk);\n            Safefree(handle);\n\n            sv_unmagic((SV*) attr_hash, PERL_MAGIC_ext);\n        }\n\n        if (zkh && attr_hash) {\n            sv_unmagic((SV*) zkh, PERL_MAGIC_tied);\n        }\n\n        if (GIMME_V == G_VOID) {\n            XSRETURN_EMPTY;\n        }\n        else if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_CLONE(package)\n        char *package\n    PPCODE:\n        XSRETURN_EMPTY;\n\n\nvoid\nzk_CLONE_SKIP(package)\n        char *package\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzk_TIEHASH(package, ...)\n        char *package\n    PPCODE:\n        Perl_croak(aTHX_ \"tying hashes of class \"\n                         PACKAGE_NAME \" not supported\");\n\n\nvoid\nzk_UNTIE(attr_hash, ref_count)\n        Net::ZooKeeper attr_hash\n        IV ref_count\n    PPCODE:\n        Perl_croak(aTHX_ \"untying hashes of class \"\n                         PACKAGE_NAME \" not supported\");\n\n\nvoid\nzk_FIRSTKEY(attr_hash)\n        Net::ZooKeeper attr_hash\n    PREINIT:\n        zk_t *zk;\n    PPCODE:\n        zk = _zk_get_handle_inner(aTHX_ attr_hash);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        ST(0) = sv_2mortal(newSVpvn(zk_keys[0].name, zk_keys[0].name_len));\n\n        XSRETURN(1);\n\n\nvoid\nzk_NEXTKEY(attr_hash, attr_key)\n        Net::ZooKeeper attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_t *zk;\n        char *key;\n        int i;\n    PPCODE:\n        zk = _zk_get_handle_inner(aTHX_ attr_hash);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_KEYS; ++i) {\n            if (strcaseEQ(key, zk_keys[i].name)) {\n                ++i;\n\n                break;\n            }\n        }\n\n        if (i < NUM_KEYS) {\n            ST(0) = sv_2mortal(newSVpvn(zk_keys[i].name, zk_keys[i].name_len));\n\n            XSRETURN(1);\n        }\n        else {\n            XSRETURN_EMPTY;\n        }\n\n\nvoid\nzk_SCALAR(attr_hash)\n        Net::ZooKeeper attr_hash\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzk_FETCH(attr_hash, attr_key)\n        Net::ZooKeeper attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_t *zk;\n        char *key;\n        SV *val = NULL;\n    PPCODE:\n        zk = _zk_get_handle_inner(aTHX_ attr_hash);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        if (strcaseEQ(key, \"data_read_len\")) {\n            val = newSViv(zk->data_buf_len);\n        }\n        else if (strcaseEQ(key, \"path_read_len\")) {\n            val = newSViv(zk->path_buf_len);\n        }\n        else if (strcaseEQ(key, \"watch_timeout\")) {\n            val = newSVuv(zk->watch_timeout);\n        }\n        else if (strcaseEQ(key, \"hosts\")) {\n            val = newSVpvn(zk->hosts, zk->hosts_len);\n        }\n        else if (strcaseEQ(key, \"session_timeout\")) {\n            val = newSViv(zoo_recv_timeout(zk->handle));\n        }\n        else if (strcaseEQ(key, \"session_id\")) {\n            const clientid_t *client_id;\n            clientid_t null_client_id;\n\n            client_id = zoo_client_id(zk->handle);\n\n            memset(&null_client_id, 0, sizeof(clientid_t));\n\n            if (!memcmp(client_id, &null_client_id, sizeof(clientid_t))) {\n                val = newSVpv(\"\", 0);\n            }\n            else {\n                val = newSVpvn((const char*) client_id, sizeof(clientid_t));\n            }\n        }\n        else if (strcaseEQ(key, \"pending_watches\")) {\n            /* cleanup any completed watches not tied to a handle */\n            val = newSVuv(_zk_release_watches(aTHX_ zk->first_watch, 0));\n        }\n\n        if (val) {\n            ST(0) = sv_2mortal(val);\n\n            XSRETURN(1);\n        }\n\n        Perl_warn(aTHX_ \"invalid element: %s\", key);\n\n        XSRETURN_UNDEF;\n\n\nvoid\nzk_STORE(attr_hash, attr_key, attr_val)\n        Net::ZooKeeper attr_hash\n        SV *attr_key\n        SV *attr_val\n    PREINIT:\n        zk_t *zk;\n        char *key;\n    PPCODE:\n        zk = _zk_get_handle_inner(aTHX_ attr_hash);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        if (strcaseEQ(key, \"data_read_len\")) {\n            int val = SvIV(attr_val);\n\n            if (val < 0) {\n                Perl_croak(aTHX_ \"invalid data read length: %d\", val);\n            }\n\n            zk->data_buf_len = val;\n        }\n        else if (strcaseEQ(key, \"path_read_len\")) {\n            int val = SvIV(attr_val);\n\n            if (val < 0) {\n                Perl_croak(aTHX_ \"invalid path read length: %d\", val);\n            }\n\n            zk->path_buf_len = val;\n        }\n        else if (strcaseEQ(key, \"watch_timeout\")) {\n            zk->watch_timeout = SvUV(attr_val);\n        }\n        else {\n            int i;\n\n            for (i = 0; i < NUM_KEYS; ++i) {\n                if (strcaseEQ(key, zk_keys[i].name)) {\n                    Perl_warn(aTHX_ \"read-only element: %s\", key);\n\n                    XSRETURN_EMPTY;\n                }\n            }\n\n            Perl_warn(aTHX_ \"invalid element: %s\", key);\n        }\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzk_EXISTS(attr_hash, attr_key)\n        Net::ZooKeeper attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_t *zk;\n        char *key;\n        int i;\n    PPCODE:\n        zk = _zk_get_handle_inner(aTHX_ attr_hash);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_KEYS; ++i) {\n            if (strcaseEQ(key, zk_keys[i].name)) {\n                XSRETURN_YES;\n            }\n        }\n\n        XSRETURN_NO;\n\n\nvoid\nzk_DELETE(attr_hash, attr_key)\n        Net::ZooKeeper attr_hash\n        SV *attr_key\n    PPCODE:\n        Perl_warn(aTHX_ \"deleting elements from hashes of class \"\n                        PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzk_CLEAR(attr_hash)\n        Net::ZooKeeper attr_hash\n    PPCODE:\n        Perl_warn(aTHX_ \"clearing hashes of class \"\n                        PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nSV *\nzk_get_error(zkh)\n        Net::ZooKeeper zkh\n    PREINIT:\n        zk_t *zk;\n    CODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        RETVAL = newSViv(zk->last_ret);\n        errno = zk->last_errno;\n    OUTPUT:\n        RETVAL\n\n\nvoid\nzk_add_auth(zkh, scheme, cert)\n        Net::ZooKeeper zkh\n        char *scheme\n        char *cert; cert = (char *) SvPV($arg, cert_len);\n    PREINIT:\n        zk_t *zk;\n        STRLEN cert_len;\n        zk_watch_t *watch;\n        int ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (cert_len > PERL_INT_MAX) {\n            Perl_croak(aTHX_ \"invalid certificate length: %u\", cert_len);\n        }\n\n        watch = _zk_create_watch(aTHX);\n\n        if (!watch) {\n            /* errno will be set */\n            zk->last_ret = ZSYSTEMERROR;\n            zk->last_errno = errno;\n\n            XSRETURN_NO;\n        }\n\n        errno = 0;\n        ret = zoo_add_auth(zk->handle, scheme, cert, cert_len,\n                           _zk_auth_completion, watch);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (ret == ZOK) {\n            pthread_mutex_lock(&watch->mutex);\n\n            while (!watch->done) {\n                pthread_cond_wait(&watch->cond, &watch->mutex);\n            }\n\n            pthread_mutex_unlock(&watch->mutex);\n\n            if (watch->done) {\n                ret = watch->ret;\n            }\n            else {\n                ret = ZINVALIDSTATE;\n            }\n\n            /* errno may be set while we waited */\n            zk->last_ret = ret;\n            zk->last_errno = errno;\n        }\n\n        _zk_destroy_watch(aTHX_ watch);\n\n        if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_create(zkh, path, buf, ...)\n        Net::ZooKeeper zkh\n        char *path\n        char *buf; buf = (char *) SvPV($arg, buf_len);\n    PREINIT:\n        zk_t *zk;\n        STRLEN buf_len;\n        int flags = 0;\n        char *path_buf;\n        int path_buf_len;\n        AV *acl_arr = NULL;\n        struct ACL_vector acl;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 3 && !(items % 2)) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        if (buf_len > PERL_INT_MAX) {\n            Perl_croak(aTHX_ \"invalid data length: %u\", buf_len);\n        }\n\n        path_buf_len = zk->path_buf_len;\n\n        for (i = 3; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"path_read_len\")) {\n                path_buf_len = SvIV(ST(i + 1));\n\n                if (path_buf_len < 2) {\n                    Perl_croak(aTHX_ \"invalid path read length: %d\",\n                               path_buf_len);\n                }\n            }\n            else if (strcaseEQ(key, \"flags\")) {\n                flags = SvIV(ST(i + 1));\n\n                if (flags & ~(ZOO_SEQUENCE | ZOO_EPHEMERAL)) {\n                    Perl_croak(aTHX_ \"invalid create flags: %d\", flags);\n                }\n            }\n            else if (strcaseEQ(key, \"acl\")) {\n                const char *err;\n\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVAV) {\n                    Perl_croak(aTHX_ \"invalid ACL array reference\");\n                }\n\n                acl_arr = (AV*) SvRV(ST(i + 1));\n\n                err = _zk_fill_acl(aTHX_ acl_arr, &acl);\n\n                if (err) {\n                    Perl_croak(aTHX_ err);\n                }\n            }\n        }\n\n        /* NOTE: would be nice to be able to rely on null-terminated string */\n        ++path_buf_len;\n        Newxz(path_buf, path_buf_len, char);\n\n        errno = 0;\n        ret = zoo_create(zk->handle, path, buf, buf_len,\n                         (acl_arr ? &acl : NULL), flags,\n                         path_buf, path_buf_len);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (acl_arr) {\n            _zk_free_acl(aTHX_ &acl);\n        }\n\n        if (ret == ZOK) {\n            ST(0) = sv_newmortal();\n#ifdef SV_HAS_TRAILING_NUL\n            sv_usepvn_flags(ST(0), path_buf, strlen(path_buf),\n                            SV_HAS_TRAILING_NUL);\n#else\n            sv_usepvn(ST(0), path_buf, strlen(path_buf));\n#endif\n            SvCUR_set(ST(0), strlen(path_buf));\n\n            XSRETURN(1);\n        }\n\n        Safefree(path_buf);\n\n        XSRETURN_UNDEF;\n\n\nvoid\nzk_delete(zkh, path, ...)\n        Net::ZooKeeper zkh\n        char *path\n    PREINIT:\n        zk_t *zk;\n        int version = -1;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"version\")) {\n                version = SvIV(ST(i + 1));\n\n                if (version < 0) {\n                    Perl_croak(aTHX_ \"invalid version requirement: %d\",\n                               version);\n                }\n            }\n        }\n\n        errno = 0;\n        ret = zoo_delete(zk->handle, path, version);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_exists(zkh, path, ...)\n        Net::ZooKeeper zkh\n        char *path\n    PREINIT:\n        zk_t *zk;\n        zk_stat_t *stat = NULL;\n        zk_watch_t *old_watch = NULL;\n        zk_handle_t *watch_handle = NULL;\n        watcher_fn watcher = NULL;\n        zk_watch_t *new_watch = NULL;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"stat\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), STAT_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"stat is not a hash reference of \"\n                                     \"type \" STAT_PACKAGE_NAME);\n                }\n\n                stat = _zks_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)));\n\n                if (!stat) {\n                    Perl_croak(aTHX_ \"invalid stat handle\");\n                }\n            }\n            else if (strcaseEQ(key, \"watch\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), WATCH_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"watch is not a hash reference of \"\n                                     \"type \" WATCH_PACKAGE_NAME);\n                }\n\n                old_watch = _zkw_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)),\n                                                  &watch_handle);\n\n                if (!old_watch) {\n                    Perl_croak(aTHX_ \"invalid watch handle\");\n                }\n            }\n        }\n\n        if (watch_handle) {\n            new_watch = _zk_acquire_watch(aTHX);\n\n            if (!new_watch) {\n                /* errno will be set */\n                zk->last_ret = ZSYSTEMERROR;\n                zk->last_errno = errno;\n\n                XSRETURN_NO;\n            }\n\n            watcher = _zk_watcher;\n        }\n\n        errno = 0;\n        ret = zoo_wexists(zk->handle, path, watcher, new_watch, stat);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (watch_handle) {\n            _zk_replace_watch(aTHX_ watch_handle, zk->first_watch,\n                              old_watch, new_watch);\n        }\n\n        if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_get_children(zkh, path, ...)\n        Net::ZooKeeper zkh\n        char *path\n    PREINIT:\n        zk_t *zk;\n        zk_watch_t *old_watch = NULL;\n        zk_handle_t *watch_handle = NULL;\n        watcher_fn watcher = NULL;\n        zk_watch_t *new_watch = NULL;\n        struct String_vector strings;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"watch\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), WATCH_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"watch is not a hash reference of \"\n                                     \"type \" WATCH_PACKAGE_NAME);\n                }\n\n                old_watch = _zkw_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)),\n                                                  &watch_handle);\n\n                if (!old_watch) {\n                    Perl_croak(aTHX_ \"invalid watch handle\");\n                }\n            }\n        }\n\n        if (watch_handle) {\n            new_watch = _zk_acquire_watch(aTHX);\n\n            if (!new_watch) {\n                /* errno will be set */\n                zk->last_ret = ZSYSTEMERROR;\n                zk->last_errno = errno;\n\n                if (GIMME_V == G_ARRAY) {\n                    XSRETURN_EMPTY;\n                }\n                else {\n                    XSRETURN_UNDEF;\n                }\n            }\n\n            watcher = _zk_watcher;\n        }\n\n        Zero(&strings, 1, struct String_vector);\n\n        errno = 0;\n        ret = zoo_wget_children(zk->handle, path, watcher, new_watch,\n                                &strings);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (watch_handle) {\n            _zk_replace_watch(aTHX_ watch_handle, zk->first_watch,\n                              old_watch, new_watch);\n        }\n\n        if (ret == ZOK) {\n            int num_children;\n\n            num_children =\n                (strings.count > PERL_INT_MAX) ? PERL_INT_MAX : strings.count;\n\n            if (GIMME_V == G_ARRAY && num_children > 0) {\n                EXTEND(SP, num_children);\n\n                for (i = 0; i < num_children; ++i) {\n                    ST(i) = sv_2mortal(newSVpv(strings.data[i], 0));\n                }\n            }\n\n            /* NOTE: would be nice if this were documented as required */\n            deallocate_String_vector(&strings);\n\n            if (GIMME_V == G_ARRAY) {\n                if (num_children == 0) {\n                    XSRETURN_EMPTY;\n                }\n\n                XSRETURN(num_children);\n            }\n            else {\n                ST(0) = sv_2mortal(newSViv(num_children));\n\n                XSRETURN(1);\n            }\n        }\n        else {\n            if (GIMME_V == G_ARRAY) {\n                XSRETURN_EMPTY;\n            }\n            else {\n                XSRETURN_UNDEF;\n            }\n        }\n\n\nvoid\nzk_get(zkh, path, ...)\n        Net::ZooKeeper zkh\n        char *path\n    PREINIT:\n        zk_t *zk;\n        int buf_len;\n        zk_stat_t *stat = NULL;\n        zk_watch_t *old_watch = NULL;\n        zk_handle_t *watch_handle = NULL;\n        char *buf;\n        watcher_fn watcher = NULL;\n        zk_watch_t *new_watch = NULL;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        buf_len = zk->data_buf_len;\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"data_read_len\")) {\n                buf_len = SvIV(ST(i + 1));\n\n                if (buf_len < 0) {\n                    Perl_croak(aTHX_ \"invalid data read length: %d\",\n                               buf_len);\n                }\n            }\n            else if (strcaseEQ(key, \"stat\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), STAT_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"stat is not a hash reference of \"\n                                     \"type \" STAT_PACKAGE_NAME);\n                }\n\n                stat = _zks_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)));\n\n                if (!stat) {\n                    Perl_croak(aTHX_ \"invalid stat handle\");\n                }\n            }\n            else if (strcaseEQ(key, \"watch\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), WATCH_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"watch is not a hash reference of \"\n                                     \"type \" WATCH_PACKAGE_NAME);\n                }\n\n                old_watch = _zkw_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)),\n                                                  &watch_handle);\n\n                if (!old_watch) {\n                    Perl_croak(aTHX_ \"invalid watch handle\");\n                }\n            }\n        }\n\n        if (watch_handle) {\n            new_watch = _zk_acquire_watch(aTHX);\n\n            if (!new_watch) {\n                /* errno will be set */\n                zk->last_ret = ZSYSTEMERROR;\n                zk->last_errno = errno;\n\n                XSRETURN_UNDEF;\n            }\n\n            watcher = _zk_watcher;\n        }\n\n        Newx(buf, buf_len + 1, char);\n\n        errno = 0;\n        ret = zoo_wget(zk->handle, path, watcher, new_watch,\n                       buf, &buf_len, stat);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (watch_handle) {\n            _zk_replace_watch(aTHX_ watch_handle, zk->first_watch,\n                              old_watch, new_watch);\n        }\n\n        if (ret == ZOK && buf_len != -1) {\n            ST(0) = sv_newmortal();\n#ifdef SV_HAS_TRAILING_NUL\n            buf[buf_len] = '\\0';\n            sv_usepvn_flags(ST(0), buf, buf_len, SV_HAS_TRAILING_NUL);\n#else\n            sv_usepvn(ST(0), buf, buf_len);\n#endif\n\n            XSRETURN(1);\n        }\n        else {\n            Safefree(buf);\n\n            XSRETURN_UNDEF;\n        }\n\n\nvoid\nzk_set(zkh, path, buf, ...)\n        Net::ZooKeeper zkh\n        char *path\n        char *buf; buf = (char *) SvPV($arg, buf_len);\n    PREINIT:\n        zk_t *zk;\n        int version = -1;\n        zk_stat_t *stat = NULL;\n        STRLEN buf_len;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 3 && !(items % 2)) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        if (buf_len > PERL_INT_MAX) {\n            Perl_croak(aTHX_ \"invalid data length: %u\", buf_len);\n        }\n\n        for (i = 3; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"version\")) {\n                version = SvIV(ST(i + 1));\n\n                if (version < 0) {\n                    Perl_croak(aTHX_ \"invalid version requirement: %d\",\n                               version);\n                }\n            }\n            else if (strcaseEQ(key, \"stat\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), STAT_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"stat is not a hash reference of \"\n                                     \"type \" STAT_PACKAGE_NAME);\n                }\n\n                stat = _zks_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)));\n\n                if (!stat) {\n                    Perl_croak(aTHX_ \"invalid stat handle\");\n                }\n            }\n        }\n\n        errno = 0;\n        ret = zoo_set2(zk->handle, path, buf, buf_len, version, stat);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_get_acl(zkh, path, ...)\n        Net::ZooKeeper zkh\n        char *path\n    PREINIT:\n        zk_t *zk;\n        zk_stat_t *stat = NULL;\n        struct ACL_vector acl;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 2 && items % 2) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        for (i = 2; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"stat\")) {\n                if (!SvROK(ST(i + 1)) || SvTYPE(SvRV(ST(i + 1))) != SVt_PVHV ||\n                    !sv_derived_from(ST(i + 1), STAT_PACKAGE_NAME)) {\n                    Perl_croak(aTHX_ \"stat is not a hash reference of \"\n                                     \"type \" STAT_PACKAGE_NAME);\n                }\n\n                stat = _zks_get_handle_outer(aTHX_ (HV*) SvRV(ST(i + 1)));\n\n                if (!stat) {\n                    Perl_croak(aTHX_ \"invalid stat handle\");\n                }\n            }\n        }\n\n        errno = 0;\n        ret = zoo_get_acl(zk->handle, path, &acl, stat);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        if (ret == ZOK) {\n            int num_acl_entries;\n\n            num_acl_entries =\n                (acl.count > PERL_INT_MAX) ? PERL_INT_MAX : acl.count;\n\n            if (GIMME_V == G_ARRAY && num_acl_entries > 0) {\n                EXTEND(SP, num_acl_entries);\n\n                for (i = 0; i < num_acl_entries; ++i) {\n                    HV *acl_entry_hash = newHV();\n\n                    _zk_fill_acl_entry_hash(aTHX_ &acl.data[i],\n                                            acl_entry_hash);\n\n                    ST(i) = sv_2mortal(newRV_noinc((SV*) acl_entry_hash));\n                }\n            }\n\n            /* NOTE: would be nice if this were documented as required */\n            deallocate_ACL_vector(&acl);\n\n            if (GIMME_V == G_ARRAY) {\n                if (num_acl_entries == 0) {\n                    XSRETURN_EMPTY;\n                }\n\n                XSRETURN(num_acl_entries);\n            }\n            else {\n                ST(0) = sv_2mortal(newSViv(num_acl_entries));\n\n                XSRETURN(1);\n            }\n        }\n        else {\n            if (GIMME_V == G_ARRAY) {\n                XSRETURN_EMPTY;\n            }\n            else {\n                XSRETURN_UNDEF;\n            }\n        }\n\n\nvoid\nzk_set_acl(zkh, path, acl_arr, ...)\n        Net::ZooKeeper zkh\n        char *path\n        AV *acl_arr\n    PREINIT:\n        zk_t *zk;\n        const char *err;\n        int version = -1;\n        struct ACL_vector acl;\n        int i, ret;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 3 && !(items % 2)) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        err = _zk_fill_acl(aTHX_ acl_arr, &acl);\n\n        if (err) {\n            Perl_croak(aTHX_ err);\n        }\n\n        for (i = 3; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"version\")) {\n                version = SvIV(ST(i + 1));\n\n                if (version < 0) {\n                    Perl_croak(aTHX_ \"invalid version requirement: %d\",\n                               version);\n                }\n            }\n        }\n\n        errno = 0;\n        ret = zoo_set_acl(zk->handle, path, version, &acl);\n\n        zk->last_ret = ret;\n        zk->last_errno = errno;\n\n        _zk_free_acl(aTHX_ &acl);\n\n        if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzk_stat(zkh)\n        Net::ZooKeeper zkh\n    PREINIT:\n        zk_t *zk;\n        zk_handle_t *handle;\n        HV *stash, *stat_hash, *attr_hash;\n        SV *attr;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        Newx(handle, 1, zk_handle_t);\n\n        handle->signature = STAT_PACKAGE_SIGNATURE;\n\n        Newxz(handle->handle.stat, 1, zk_stat_t);\n\n        /* As in zk_new(), we use two levels of magic here. */\n\n        stash = gv_stashpv(STAT_PACKAGE_NAME, GV_ADDWARN);\n\n        attr_hash = newHV();\n\n        sv_magic((SV*) attr_hash, Nullsv, PERL_MAGIC_ext,\n                 (const char*) handle, 0);\n\n        attr = sv_bless(newRV_noinc((SV*) attr_hash), stash);\n\n        stat_hash = newHV();\n\n        sv_magic((SV*) stat_hash, attr, PERL_MAGIC_tied, Nullch, 0);\n        SvREFCNT_dec(attr);\n\n        ST(0) = sv_bless(sv_2mortal(newRV_noinc((SV*) stat_hash)), stash);\n\n        XSRETURN(1);\n\n\nvoid\nzk_watch(zkh, ...)\n        Net::ZooKeeper zkh\n    PREINIT:\n        zk_t *zk;\n        unsigned int timeout;\n        zk_watch_t *watch;\n        zk_handle_t *handle;\n        HV *stash, *watch_hash, *attr_hash;\n        SV *attr;\n        int i;\n    PPCODE:\n        zk = _zk_get_handle_outer(aTHX_ zkh);\n\n        if (!zk) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        zk->last_ret = ZOK;\n        zk->last_errno = 0;\n\n        if (items > 1 && !(items % 2)) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        timeout = zk->watch_timeout;\n\n        for (i = 1; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"timeout\")) {\n                timeout = SvUV(ST(i + 1));\n            }\n        }\n\n        watch = _zk_acquire_watch(aTHX);\n\n        if (!watch) {\n            /* errno will be set */\n            zk->last_ret = ZSYSTEMERROR;\n            zk->last_errno = errno;\n\n            XSRETURN_UNDEF;\n        }\n\n        Newx(handle, 1, zk_handle_t);\n\n        handle->signature = WATCH_PACKAGE_SIGNATURE;\n        handle->handle.watch = watch;\n\n        /* As in zk_new(), we use two levels of magic here. */\n\n        stash = gv_stashpv(WATCH_PACKAGE_NAME, GV_ADDWARN);\n\n        attr_hash = newHV();\n\n        watch->timeout = timeout;\n\n        sv_magic((SV*) attr_hash, Nullsv, PERL_MAGIC_ext,\n                 (const char*) handle, 0);\n\n        attr = sv_bless(newRV_noinc((SV*) attr_hash), stash);\n\n        watch_hash = newHV();\n\n        sv_magic((SV*) watch_hash, attr, PERL_MAGIC_tied, Nullch, 0);\n        SvREFCNT_dec(attr);\n\n        ST(0) = sv_bless(sv_2mortal(newRV_noinc((SV*) watch_hash)), stash);\n\n        XSRETURN(1);\n\n\nMODULE = Net::ZooKeeper  PACKAGE = Net::ZooKeeper::Stat  PREFIX = zks_\n\nvoid\nzks_DESTROY(zksh)\n        Net::ZooKeeper::Stat zksh\n    PREINIT:\n        zk_handle_t *handle;\n        HV *attr_hash;\n        int ret = ZBADARGUMENTS;\n    PPCODE:\n        handle = _zk_check_handle_outer(aTHX_ zksh, &attr_hash,\n                                        STAT_PACKAGE_NAME,\n                                        STAT_PACKAGE_SIGNATURE);\n\n        if (!handle) {\n            handle = _zk_check_handle_inner(aTHX_ zksh,\n                                            STAT_PACKAGE_SIGNATURE);\n\n            if (handle) {\n                attr_hash = zksh;\n                zksh = NULL;\n            }\n        }\n\n        if (handle) {\n            ret = ZOK;\n\n            Safefree(handle->handle.stat);\n            Safefree(handle);\n\n            sv_unmagic((SV*) attr_hash, PERL_MAGIC_ext);\n        }\n\n        if (zksh && attr_hash) {\n            sv_unmagic((SV*) zksh, PERL_MAGIC_tied);\n        }\n\n        if (GIMME_V == G_VOID) {\n            XSRETURN_EMPTY;\n        }\n        else if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzks_CLONE(package)\n        char *package\n    PPCODE:\n        XSRETURN_EMPTY;\n\n\nvoid\nzks_CLONE_SKIP(package)\n        char *package\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzks_TIEHASH(package, ...)\n        char *package\n    PPCODE:\n        Perl_croak(aTHX_ \"tying hashes of class \"\n                         STAT_PACKAGE_NAME \" not supported\");\n\n\nvoid\nzks_UNTIE(attr_hash, ref_count)\n        Net::ZooKeeper::Stat attr_hash\n        IV ref_count\n    PPCODE:\n        Perl_croak(aTHX_ \"untying hashes of class \"\n                         STAT_PACKAGE_NAME \" not supported\");\n\n\nvoid\nzks_FIRSTKEY(attr_hash)\n        Net::ZooKeeper::Stat attr_hash\n    PREINIT:\n        zk_stat_t *stat;\n    PPCODE:\n        stat = _zks_get_handle_inner(aTHX_ attr_hash);\n\n        if (!stat) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        ST(0) = sv_2mortal(newSVpvn(zk_stat_keys[0].name,\n                                    zk_stat_keys[0].name_len));\n\n        XSRETURN(1);\n\n\nvoid\nzks_NEXTKEY(attr_hash, attr_key)\n        Net::ZooKeeper::Stat attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_stat_t *stat;\n        char *key;\n        int i;\n    PPCODE:\n        stat = _zks_get_handle_inner(aTHX_ attr_hash);\n\n        if (!stat) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_STAT_KEYS; ++i) {\n            if (strcaseEQ(key, zk_stat_keys[i].name)) {\n                ++i;\n\n                break;\n            }\n        }\n\n        if (i < NUM_STAT_KEYS) {\n            ST(0) = sv_2mortal(newSVpvn(zk_stat_keys[i].name,\n                                        zk_stat_keys[i].name_len));\n\n            XSRETURN(1);\n        }\n        else {\n            XSRETURN_EMPTY;\n        }\n\n\nvoid\nzks_SCALAR(attr_hash)\n        Net::ZooKeeper::Stat attr_hash\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzks_FETCH(attr_hash, attr_key)\n        Net::ZooKeeper::Stat attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_stat_t *stat;\n        char *key;\n        SV *val = NULL;\n        int i;\n    PPCODE:\n        stat = _zks_get_handle_inner(aTHX_ attr_hash);\n\n        if (!stat) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_STAT_KEYS; ++i) {\n            if (strcaseEQ(key, zk_stat_keys[i].name)) {\n                if (zk_stat_keys[i].size * CHAR_BIT == 32) {\n                    val = newSViv(*((int32_t*) (((char*) stat) +\n                                                zk_stat_keys[i].offset)));\n                }\n                else {\n                    /* NOTE: %lld is inconsistent, so cast to a double */\n                    val = newSVpvf(\"%.0f\", (double)\n                                   *((int64_t*) (((char*) stat) +\n                                                 zk_stat_keys[i].offset)));\n                }\n\n                break;\n            }\n        }\n\n        if (val) {\n            ST(0) = sv_2mortal(val);\n\n            XSRETURN(1);\n        }\n\n        Perl_warn(aTHX_ \"invalid element: %s\", key);\n\n        XSRETURN_UNDEF;\n\n\nvoid\nzks_STORE(attr_hash, attr_key, attr_val)\n        Net::ZooKeeper::Stat attr_hash\n        SV *attr_key\n        SV *attr_val\n    PREINIT:\n        zk_stat_t *stat;\n        char *key;\n        int i;\n    PPCODE:\n        stat = _zks_get_handle_inner(aTHX_ attr_hash);\n\n        if (!stat) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_STAT_KEYS; ++i) {\n            if (strcaseEQ(key, zk_stat_keys[i].name)) {\n                Perl_warn(aTHX_ \"read-only element: %s\", key);\n\n                XSRETURN_EMPTY;\n            }\n        }\n\n        Perl_warn(aTHX_ \"invalid element: %s\", key);\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzks_EXISTS(attr_hash, attr_key)\n        Net::ZooKeeper::Stat attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_stat_t *stat;\n        char *key;\n        int i;\n    PPCODE:\n        stat = _zks_get_handle_inner(aTHX_ attr_hash);\n\n        if (!stat) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_STAT_KEYS; ++i) {\n            if (strcaseEQ(key, zk_stat_keys[i].name)) {\n                XSRETURN_YES;\n            }\n        }\n\n        XSRETURN_NO;\n\n\nvoid\nzks_DELETE(attr_hash, attr_key)\n        Net::ZooKeeper::Stat attr_hash\n        SV *attr_key\n    PPCODE:\n        Perl_warn(aTHX_ \"deleting elements from hashes of class \"\n                        STAT_PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzks_CLEAR(attr_hash)\n        Net::ZooKeeper::Stat attr_hash\n    PPCODE:\n        Perl_warn(aTHX_ \"clearing hashes of class \"\n                        STAT_PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nMODULE = Net::ZooKeeper  PACKAGE = Net::ZooKeeper::Watch  PREFIX = zkw_\n\nvoid\nzkw_DESTROY(zkwh)\n        Net::ZooKeeper::Watch zkwh\n    PREINIT:\n        zk_handle_t *handle;\n        HV *attr_hash;\n        int ret = ZBADARGUMENTS;\n    PPCODE:\n        handle = _zk_check_handle_outer(aTHX_ zkwh, &attr_hash,\n                                        WATCH_PACKAGE_NAME,\n                                        WATCH_PACKAGE_SIGNATURE);\n\n        if (!handle) {\n            handle = _zk_check_handle_inner(aTHX_ zkwh,\n                                            WATCH_PACKAGE_SIGNATURE);\n\n            if (handle) {\n                attr_hash = zkwh;\n                zkwh = NULL;\n            }\n        }\n\n        if (handle) {\n            ret = ZOK;\n\n            _zk_release_watch(aTHX_ handle->handle.watch, 0);\n            Safefree(handle);\n\n            sv_unmagic((SV*) attr_hash, PERL_MAGIC_ext);\n        }\n\n        if (zkwh && attr_hash) {\n            sv_unmagic((SV*) zkwh, PERL_MAGIC_tied);\n        }\n\n        if (GIMME_V == G_VOID) {\n            XSRETURN_EMPTY;\n        }\n        else if (ret == ZOK) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n\nvoid\nzkw_CLONE(package)\n        char *package\n    PPCODE:\n        XSRETURN_EMPTY;\n\n\nvoid\nzkw_CLONE_SKIP(package)\n        char *package\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzkw_TIEHASH(package, ...)\n        char *package\n    PPCODE:\n        Perl_croak(aTHX_ \"tying hashes of class \"\n                         WATCH_PACKAGE_NAME \" not supported\");\n\n\nvoid\nzkw_UNTIE(attr_hash, ref_count)\n        Net::ZooKeeper::Watch attr_hash\n        IV ref_count\n    PPCODE:\n        Perl_croak(aTHX_ \"untying hashes of class \"\n                         WATCH_PACKAGE_NAME \" not supported\");\n\n\nvoid\nzkw_FIRSTKEY(attr_hash)\n        Net::ZooKeeper::Watch attr_hash\n    PREINIT:\n        zk_watch_t *watch;\n    PPCODE:\n        watch = _zkw_get_handle_inner(aTHX_ attr_hash);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        ST(0) = sv_2mortal(newSVpvn(zk_watch_keys[0].name,\n                                    zk_watch_keys[0].name_len));\n\n        XSRETURN(1);\n\n\nvoid\nzkw_NEXTKEY(attr_hash, attr_key)\n        Net::ZooKeeper::Watch attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_watch_t *watch;\n        char *key;\n        int i;\n    PPCODE:\n        watch = _zkw_get_handle_inner(aTHX_ attr_hash);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_WATCH_KEYS; ++i) {\n            if (strcaseEQ(key, zk_watch_keys[i].name)) {\n                ++i;\n\n                break;\n            }\n        }\n\n        if (i < NUM_WATCH_KEYS) {\n            ST(0) = sv_2mortal(newSVpvn(zk_watch_keys[i].name,\n                                        zk_watch_keys[i].name_len));\n\n            XSRETURN(1);\n        }\n        else {\n            XSRETURN_EMPTY;\n        }\n\n\nvoid\nzkw_SCALAR(attr_hash)\n        Net::ZooKeeper::Watch attr_hash\n    PPCODE:\n        XSRETURN_YES;\n\n\nvoid\nzkw_FETCH(attr_hash, attr_key)\n        Net::ZooKeeper::Watch attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_watch_t *watch;\n        char *key;\n        SV *val = NULL;\n    PPCODE:\n        watch = _zkw_get_handle_inner(aTHX_ attr_hash);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        if (strcaseEQ(key, \"timeout\")) {\n            val = newSVuv(watch->timeout);\n        }\n        else if (strcaseEQ(key, \"event\")) {\n            val = newSViv(watch->event_type);\n        }\n        else if (strcaseEQ(key, \"state\")) {\n            val = newSViv(watch->event_state);\n        }\n\n        if (val) {\n            ST(0) = sv_2mortal(val);\n\n            XSRETURN(1);\n        }\n\n        Perl_warn(aTHX_ \"invalid element: %s\", key);\n\n        XSRETURN_UNDEF;\n\n\nvoid\nzkw_STORE(attr_hash, attr_key, attr_val)\n        Net::ZooKeeper::Watch attr_hash\n        SV *attr_key\n        SV *attr_val\n    PREINIT:\n        zk_watch_t *watch;\n        char *key;\n    PPCODE:\n        watch = _zkw_get_handle_inner(aTHX_ attr_hash);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        if (strcaseEQ(key, \"timeout\")) {\n            watch->timeout = SvUV(attr_val);\n        }\n        else {\n            int i;\n\n            for (i = 0; i < NUM_WATCH_KEYS; ++i) {\n                if (strcaseEQ(key, zk_watch_keys[i].name)) {\n                    Perl_warn(aTHX_ \"read-only element: %s\", key);\n\n                    XSRETURN_EMPTY;\n                }\n            }\n\n            Perl_warn(aTHX_ \"invalid element: %s\", key);\n        }\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzkw_EXISTS(attr_hash, attr_key)\n        Net::ZooKeeper::Watch attr_hash\n        SV *attr_key\n    PREINIT:\n        zk_watch_t *watch;\n        char *key;\n        int i;\n    PPCODE:\n        watch = _zkw_get_handle_inner(aTHX_ attr_hash);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        key = SvPV_nolen(attr_key);\n\n        for (i = 0; i < NUM_WATCH_KEYS; ++i) {\n            if (strcaseEQ(key, zk_watch_keys[i].name)) {\n                XSRETURN_YES;\n            }\n        }\n\n        XSRETURN_NO;\n\n\nvoid\nzkw_DELETE(attr_hash, attr_key)\n        Net::ZooKeeper::Watch attr_hash\n        SV *attr_key\n    PPCODE:\n        Perl_warn(aTHX_ \"deleting elements from hashes of class \"\n                        WATCH_PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzkw_CLEAR(attr_hash)\n        Net::ZooKeeper::Watch attr_hash\n    PPCODE:\n        Perl_warn(aTHX_ \"clearing hashes of class \"\n                        WATCH_PACKAGE_NAME \" not supported\");\n\n        XSRETURN_EMPTY;\n\n\nvoid\nzkw_wait(zkwh, ...)\n        Net::ZooKeeper::Watch zkwh\n    PREINIT:\n        zk_watch_t *watch;\n        unsigned int timeout;\n        struct timeval end_timeval;\n        int i, done;\n        struct timespec wait_timespec;\n    PPCODE:\n        watch = _zkw_get_handle_outer(aTHX_ zkwh, NULL);\n\n        if (!watch) {\n            Perl_croak(aTHX_ \"invalid handle\");\n        }\n\n        if (items > 1 && !(items % 2)) {\n            Perl_croak(aTHX_ \"invalid number of arguments\");\n        }\n\n        timeout = watch->timeout;\n\n        for (i = 1; i < items; i += 2) {\n            char *key = SvPV_nolen(ST(i));\n\n            if (strcaseEQ(key, \"timeout\")) {\n                timeout = SvUV(ST(i + 1));\n            }\n        }\n\n        gettimeofday(&end_timeval, NULL);\n\n        end_timeval.tv_sec += timeout / 1000;\n        end_timeval.tv_usec += (timeout % 1000) * 1000;\n\n        wait_timespec.tv_sec = end_timeval.tv_sec;\n        wait_timespec.tv_nsec = end_timeval.tv_usec * 1000;\n\n        pthread_mutex_lock(&watch->mutex);\n\n        while (!watch->done) {\n            struct timeval curr_timeval;\n\n            gettimeofday(&curr_timeval, NULL);\n\n            if (end_timeval.tv_sec < curr_timeval.tv_sec ||\n                (end_timeval.tv_sec == curr_timeval.tv_sec &&\n                 end_timeval.tv_usec <= curr_timeval.tv_usec)) {\n                break;\n            }\n\n            pthread_cond_timedwait(&watch->cond, &watch->mutex,\n                                   &wait_timespec);\n        }\n\n        done = watch->done;\n\n        pthread_mutex_unlock(&watch->mutex);\n\n        if (done) {\n            XSRETURN_YES;\n        }\n        else {\n            XSRETURN_NO;\n        }\n\n"
  },
  {
    "path": "src/contrib/zkperl/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zkperl\" default=\"compile\">\n  <import file=\"../build-contrib.xml\"/>\n\n  <target name=\"init\" depends=\"check-contrib\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <antcall target=\"init-contrib\"/>\n  </target>\n\n  <target name=\"compile\" depends=\"init\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${build.dir}\"/>\n    <copy todir=\"${build.dir}\">\n      <fileset dir=\"${basedir}\">\n        <exclude name=\"**/VERSION\"/>\n      </fileset>\n    </copy>\n    <exec executable=\"echo\" output=\"${build.dir}/VERSION\">\n      <arg line=\"${version}\" />\n    </exec>\n  </target>\n\n\t<target name=\"jar\" depends=\"compile\" >\n\t\t<echo message=\"No jar target defined for this package\"/>\n\t</target>\n\n \t<target name=\"test\">\n        <echo message=\"No test target defined for this package\" />\n    </target>\n\n\n  <target name=\"package\" depends=\"compile\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}\">\n      <fileset dir=\"${build.dir}\"/>\n    </copy>\n  </target>\n\n</project>\n"
  },
  {
    "path": "src/contrib/zkperl/t/10_invalid.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 107;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(1);\n\n\n## new()\n\neval {\n    Net::ZooKeeper->new();\n};\nlike($@, qr/Usage: Net::ZooKeeper::new\\(package, hosts, \\.\\.\\.\\)/,\n     'new(): no hostname specified');\n\neval {\n    Net::ZooKeeper->new($hosts, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'new(): invalid number of arguments');\n\neval {\n    Net::ZooKeeper->new($hosts, 'session_timeout' => -3);\n};\nlike($@, qr/invalid session timeout/,\n     'new(): invalid session timeout');\n\neval {\n    Net::ZooKeeper->new($hosts, 'session_timeout' => 0x4000_0000);\n};\nlike($@, qr/invalid session timeout/,\n     'new(): invalid session timeout');\n\neval {\n    Net::ZooKeeper->new($hosts, 'session_id' => 'abcdef');\n};\nlike($@, qr/invalid session ID/,\n     'new(): invalid session ID');\n\nmy $zkh = Net::ZooKeeper->new($hosts);\nisa_ok($zkh, 'Net::ZooKeeper',\n       'new(): created handle');\n\n\n## DESTROY()\n\neval {\n    $zkh->DESTROY('foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::DESTROY\\(zkh\\)/,\n     'DESTROY(): too many arguments');\n\nmy $bad_zkh = {};\n$bad_zkh = bless($bad_zkh, 'Net::ZooKeeper');\n\nmy $ret = $bad_zkh->DESTROY();\nok(!$ret,\n   'DESTROY(): no action on invalid handle');\n\n\n## add_auth()\n\neval {\n    $zkh->add_auth();\n};\nlike($@, qr/Usage: Net::ZooKeeper::add_auth\\(zkh, scheme, cert\\)/,\n     'add_auth(): no scheme specified');\n\neval {\n    $zkh->add_auth('foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::add_auth\\(zkh, scheme, cert\\)/,\n     'add_auth(): no certificate specified');\n\neval {\n    $zkh->add_auth('foo', 'foo', 'bar');\n};\nlike($@, qr/Usage: Net::ZooKeeper::add_auth\\(zkh, scheme, cert\\)/,\n     'add_auth(): too many arguments');\n\neval {\n    $bad_zkh->add_auth('foo', 'foo');\n};\nlike($@, qr/invalid handle/,\n     'add_auth(): invalid handle');\n\neval {\n    Net::ZooKeeper::add_auth(1, 'foo', 'foo');\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'add_auth(): invalid hash reference');\n\n\n## create()\n\neval {\n    $zkh->create();\n};\nlike($@, qr/Usage: Net::ZooKeeper::create\\(zkh, path, buf, \\.\\.\\.\\)/,\n     'create(): no path specified');\n\neval {\n    $zkh->create($node_path);\n};\nlike($@, qr/Usage: Net::ZooKeeper::create\\(zkh, path, buf, \\.\\.\\.\\)/,\n     'create(): no data buffer specified');\n\neval {\n    $zkh->create($node_path, 'foo', 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'create(): invalid number of arguments');\n\neval {\n    $zkh->create($node_path, 'foo', 'path_read_len' => -3);\n};\nlike($@, qr/invalid path read length/,\n     'create(): invalid path read length');\n\neval {\n    $zkh->create($node_path, 'foo', 'path_read_len' => 1);\n};\nlike($@, qr/invalid path read length/,\n     'create(): invalid path read length');\n\neval {\n    $zkh->create($node_path, 'foo', 'flags' => 15);\n};\nlike($@, qr/invalid create flags/,\n     'create(): invalid create flags');\n\neval {\n    $zkh->create($node_path, 'foo', 'flags' => ZOO_EPHEMERAL, 'acl', 'foo');\n};\nlike($@, qr/invalid ACL array reference/,\n     'create(): invalid ACL array reference');\n\neval {\n    $zkh->create($node_path, 'foo', 'acl', {});\n};\nlike($@, qr/invalid ACL array reference/,\n     'create(): invalid ACL array reference to hash');\n\neval {\n    my @acl = ('foo', 'bar');\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/invalid ACL entry hash reference/,\n     'create(): invalid ACL entry hash reference');\n\neval {\n    my @acl = ({ 'foo' => 'bar' });\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/no ACL entry perms element/,\n     'create(): no ACL entry perms element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => -1\n        }\n    );\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/invalid ACL entry perms/,\n     'create(): invalid ACL entry perms');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL\n        }\n    );\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/no ACL entry scheme element/,\n     'create(): no ACL entry scheme element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL,\n            'scheme' => 'foo'\n        }\n    );\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/no ACL entry id element/,\n     'create(): no ACL entry id element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL,\n            'scheme' => 'foo',\n            'id'     => 'bar'\n        },\n        'bar'\n    );\n    $zkh->create($node_path, 'foo', 'acl', \\@acl);\n};\nlike($@, qr/invalid ACL entry hash reference/,\n     'create(): invalid second ACL entry hash reference');\n\neval {\n    $bad_zkh->create($node_path, 'foo');\n};\nlike($@, qr/invalid handle/,\n     'create(): invalid handle');\n\neval {\n    Net::ZooKeeper::create(1, $node_path, 'foo');\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'create(): invalid hash reference');\n\n\n## delete()\n\neval {\n    $zkh->delete();\n};\nlike($@, qr/Usage: Net::ZooKeeper::delete\\(zkh, path, \\.\\.\\.\\)/,\n     'delete(): no path specified');\n\neval {\n    $zkh->delete($node_path, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'delete(): invalid number of arguments');\n\neval {\n    $zkh->delete($node_path, 'version' => -3);\n};\nlike($@, qr/invalid version requirement/,\n     'delete(): invalid version requirement');\n\neval {\n    $bad_zkh->delete($node_path);\n};\nlike($@, qr/invalid handle/,\n     'delete(): invalid handle');\n\neval {\n    Net::ZooKeeper::delete(1, $node_path);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'delete(): invalid hash reference');\n\n\n## exists()\n\neval {\n    $zkh->exists();\n};\nlike($@, qr/Usage: Net::ZooKeeper::exists\\(zkh, path, \\.\\.\\.\\)/,\n     'exists(): no path specified');\n\neval {\n    $zkh->exists($node_path, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'exists(): invalid number of arguments');\n\neval {\n    $zkh->exists($node_path, 'watch', 'bar');\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'exists(): invalid watch hash reference');\n\neval {\n    $zkh->exists($node_path, 'watch', []);\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'exists(): invalid watch hash reference to array');\n\neval {\n    $zkh->exists($node_path, 'stat', 'bar');\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'exists(): invalid stat hash reference');\n\neval {\n    $zkh->exists($node_path, 'stat', []);\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'exists(): invalid stat hash reference');\n\neval {\n    $bad_zkh->exists($node_path);\n};\nlike($@, qr/invalid handle/,\n     'exists(): invalid handle');\n\neval {\n    Net::ZooKeeper::exists(1, $node_path);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'exists(): invalid hash reference');\n\n\n## get_children()\n\neval {\n    $zkh->get_children();\n};\nlike($@, qr/Usage: Net::ZooKeeper::get_children\\(zkh, path, \\.\\.\\.\\)/,\n     'get_children(): no path specified');\n\neval {\n    $zkh->get_children($node_path, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'get_children(): invalid number of arguments');\n\neval {\n    $zkh->get_children($node_path, 'watch', 'bar');\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'get_children(): invalid watch hash reference');\n\neval {\n    $zkh->get_children($node_path, 'watch', []);\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'get_children(): invalid watch ash reference to array');\n\neval {\n    $bad_zkh->get_children($node_path);\n};\nlike($@, qr/invalid handle/,\n     'get_children(): invalid handle');\n\neval {\n    Net::ZooKeeper::get_children(1, $node_path);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'get_children(): invalid hash reference');\n\n\n## get()\n\neval {\n    $zkh->get();\n};\nlike($@, qr/Usage: Net::ZooKeeper::get\\(zkh, path, \\.\\.\\.\\)/,\n     'get(): no path specified');\n\neval {\n    $zkh->get($node_path, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'get(): invalid number of arguments');\n\neval {\n    $zkh->get($node_path, 'data_read_len' => -3);\n};\nlike($@, qr/invalid data read length/,\n     'get(): invalid data read length');\n\neval {\n    $zkh->get($node_path, 'data_read_len' => 10, 'watch', 'bar');\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'get(): invalid watch hash reference');\n\neval {\n    $zkh->get($node_path, 'watch', []);\n};\nlike($@, qr/watch is not a hash reference of type Net::ZooKeeper::Watch/,\n     'get(): invalid watch hash reference to array');\n\neval {\n    $zkh->get($node_path, 'stat', 'bar');\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'get(): invalid stat hash reference');\n\neval {\n    $zkh->get($node_path, 'stat', []);\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'get(): invalid stat hash reference');\n\neval {\n    $bad_zkh->get($node_path);\n};\nlike($@, qr/invalid handle/,\n     'get(): invalid handle');\n\neval {\n    Net::ZooKeeper::get(1, $node_path);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'get(): invalid hash reference');\n\n\n## set()\n\neval {\n    $zkh->set();\n};\nlike($@, qr/Usage: Net::ZooKeeper::set\\(zkh, path, buf, \\.\\.\\.\\)/,\n     'set(): no path specified');\n\neval {\n    $zkh->set($node_path);\n};\nlike($@, qr/Usage: Net::ZooKeeper::set\\(zkh, path, buf, \\.\\.\\.\\)/,\n     'set(): no data buffer specified');\n\neval {\n    $zkh->set($node_path, 'foo', 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'set(): invalid number of arguments');\n\neval {\n    $zkh->set($node_path, 'foo', 'version' => -3);\n};\nlike($@, qr/invalid version requirement/,\n     'set(): invalid version requirement');\n\neval {\n    $zkh->set($node_path, 'foo', 'version', 0, 'stat', 'bar');\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'set(): invalid stat hash reference');\n\neval {\n    $zkh->set($node_path, 'foo', 'stat', []);\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'set(): invalid stat hash reference');\n\neval {\n    $bad_zkh->set($node_path, 'foo');\n};\nlike($@, qr/invalid handle/,\n     'set(): invalid handle');\n\neval {\n    Net::ZooKeeper::set(1, $node_path, 'foo');\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'set(): invalid hash reference');\n\n\n## get_acl()\n\neval {\n    $zkh->get_acl();\n};\nlike($@, qr/Usage: Net::ZooKeeper::get_acl\\(zkh, path, \\.\\.\\.\\)/,\n     'get_acl(): no path specified');\n\neval {\n    $zkh->get_acl($node_path, 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'get_acl(): invalid number of arguments');\n\neval {\n    $zkh->get_acl($node_path, 'stat', 'bar');\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'get_acl(): invalid stat hash reference');\n\neval {\n    $zkh->get_acl($node_path, 'stat', []);\n};\nlike($@, qr/stat is not a hash reference of type Net::ZooKeeper::Stat/,\n     'get_acl(): invalid stat hash reference');\n\neval {\n    $bad_zkh->get_acl($node_path);\n};\nlike($@, qr/invalid handle/,\n     'get_acl(): invalid handle');\n\neval {\n    Net::ZooKeeper::get_acl(1, $node_path);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'get_acl(): invalid hash reference');\n\n\n## set_acl()\n\neval {\n    $zkh->set_acl();\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_acl\\(zkh, path, acl_arr, \\.\\.\\.\\)/,\n     'set_acl(): no path specified');\n\neval {\n    $zkh->set_acl($node_path);\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_acl\\(zkh, path, acl_arr, \\.\\.\\.\\)/,\n     'set_acl(): no data buffer specified');\n\neval {\n    $zkh->set_acl($node_path, 'foo');\n};\nlike($@, qr/acl_arr is not an array reference/,\n     'set_acl(): invalid ACL array reference');\n\neval {\n    $zkh->set_acl($node_path, {});\n};\nlike($@, qr/acl_arr is not an array reference/,\n     'set_acl(): invalid ACL array reference to hash');\n\neval {\n    my @acl = ('foo', 'bar');\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/invalid ACL entry hash reference/,\n     'set_acl(): invalid ACL entry hash reference');\n\neval {\n    my @acl = ({ 'foo' => 'bar' });\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/no ACL entry perms element/,\n     'set_acl(): no ACL entry perms element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => -1\n        }\n    );\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/invalid ACL entry perms/,\n     'set_acl(): invalid ACL entry perms');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL\n        }\n    );\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/no ACL entry scheme element/,\n     'set_acl(): no ACL entry scheme element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL,\n            'scheme' => 'foo'\n        }\n    );\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/no ACL entry id element/,\n     'set_acl(): no ACL entry id element');\n\neval {\n    my @acl = (\n        {\n            'perms'  => ZOO_PERM_ALL,\n            'scheme' => 'foo',\n            'id'     => 'bar'\n        },\n        'bar'\n    );\n    $zkh->set_acl($node_path, \\@acl);\n};\nlike($@, qr/invalid ACL entry hash reference/,\n     'set_acl(): invalid second ACL entry hash reference');\n\neval {\n    $zkh->set_acl($node_path, [], 'bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'set_acl(): invalid number of arguments');\n\neval {\n    $zkh->set_acl($node_path, [], 'version' => -3);\n};\nlike($@, qr/invalid version requirement/,\n     'set_acl(): invalid version requirement');\n\neval {\n    $bad_zkh->set_acl($node_path, []);\n};\nlike($@, qr/invalid handle/,\n     'set_acl(): invalid handle');\n\neval {\n    Net::ZooKeeper::set_acl(1, $node_path, []);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'set_acl(): invalid hash reference');\n\n\n## stat()\n\neval {\n    $zkh->stat('bar');\n};\nlike($@, qr/Usage: Net::ZooKeeper::stat\\(zkh\\)/,\n     'stat(): too many arguments');\n\neval {\n    $bad_zkh->stat();\n};\nlike($@, qr/invalid handle/,\n     'stat(): invalid handle');\n\neval {\n    Net::ZooKeeper::stat(1);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'stat(): invalid hash reference');\n\nmy $stat = $zkh->stat();\nisa_ok($stat, 'Net::ZooKeeper::Stat',\n       'stat(): created stat handle');\n\n\n## stat DESTROY()\n\neval {\n    $stat->DESTROY('foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::Stat::DESTROY\\(zksh\\)/,\n     'stat DESTROY(): too many arguments');\n\nmy $bad_stat = {};\n$bad_stat = bless($bad_stat, 'Net::ZooKeeper::Stat');\n\n$ret = $bad_stat->DESTROY();\nok(!$ret,\n   'stat DESTROY(): no action on invalid handle');\n\n\n## watch()\n\neval {\n    $zkh->watch('bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'watch(): invalid number of arguments');\n\neval {\n    $bad_zkh->watch();\n};\nlike($@, qr/invalid handle/,\n     'watch(): invalid handle');\n\neval {\n    Net::ZooKeeper::watch(1);\n};\nlike($@, qr/zkh is not a hash reference of type Net::ZooKeeper/,\n     'watch(): invalid hash reference');\n\nmy $watch = $zkh->watch();\nisa_ok($watch, 'Net::ZooKeeper::Watch',\n       'watch(): created watch handle');\n\n\n## watch DESTROY()\n\neval {\n    $watch->DESTROY('foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::Watch::DESTROY\\(zkwh\\)/,\n     'watch DESTROY(): too many arguments');\n\nmy $bad_watch = {};\n$bad_watch = bless($bad_watch, 'Net::ZooKeeper::Watch');\n\n$ret = $bad_watch->DESTROY();\nok(!$ret,\n   'watch DESTROY(): no action on invalid handle');\n\n\n## wait()\n\neval {\n    $watch->wait('bar');\n};\nlike($@, qr/invalid number of arguments/,\n     'wait(): invalid number of arguments');\n\neval {\n    $bad_watch->wait();\n};\nlike($@, qr/invalid handle/,\n     'wait(): invalid watch handle');\n\neval {\n    Net::ZooKeeper::Watch::wait(1);\n};\nlike($@, qr/zkwh is not a hash reference of type Net::ZooKeeper::Watch/,\n     'wait(): invalid watch hash reference');\n\n\n## set_log_level()\n\neval {\n    my $f = \\&Net::ZooKeeper::set_log_level;\n    &$f();\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_log_level\\(level\\)/,\n     'set_log_level(): no level specified');\n\neval {\n    my $f = \\&Net::ZooKeeper::set_log_level;\n    &$f(ZOO_LOG_LEVEL_OFF, 'foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_log_level\\(level\\)/,\n     'set_log_level(): too many arguments');\n\neval {\n    Net::ZooKeeper::set_log_level((ZOO_LOG_LEVEL_OFF) - 1);\n};\nlike($@, qr/invalid log level/,\n     'set_log_level(): invalid low log level');\n\neval {\n    Net::ZooKeeper::set_log_level((ZOO_LOG_LEVEL_DEBUG) + 1);\n};\nlike($@, qr/invalid log level/,\n     'set_log_level(): invalid high log level');\n\n\n## set_deterministic_conn_order()\n\neval {\n    my $f = \\&Net::ZooKeeper::set_deterministic_conn_order;\n    &$f();\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_deterministic_conn_order\\(flag\\)/,\n     'set_deterministic_conn_order(): no flag specified');\n\neval {\n    my $f = \\&Net::ZooKeeper::set_deterministic_conn_order;\n    &$f(1, 'foo');\n};\nlike($@, qr/Usage: Net::ZooKeeper::set_deterministic_conn_order\\(flag\\)/,\n     'set_deterministic_conn_order(): too many arguments');\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/15_thread.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse Config;\nuse File::Spec;\nuse Test::More;\n\nBEGIN {\n    if ($Config{'useithreads'}) {\n        plan tests => 10;\n    }\n    else {\n        plan skip_all => 'no thread support';\n    }\n}\n\nuse threads;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nmy $zkh = Net::ZooKeeper->new($hosts);\n\nSKIP: {\n    skip 'no valid handle', 9 unless (defined($zkh));\n\n    my($thread) = threads->new(\\&thread_test, $zkh);\n\n    SKIP: {\n        skip 'no valid thread', 3 unless (defined($thread));\n\n        my(@ret) = $thread->join;\n\n        ok((@ret == 3 and $ret[0]),\n           'CLONE_SKIP(): handle reference after spawning thread');\n\n        ok((@ret == 3 and $ret[1]),\n           'CLONE_SKIP(): scalar handle reference after spawning thread');\n\n        ok((@ret == 3 and $ret[2]),\n           'CLONE_SKIP(): undef handle reference after spawning thread');\n    }\n\n    my $stat = $zkh->stat();\n\n    ($thread) = threads->new(\\&thread_test, $stat);\n\n    SKIP: {\n        skip 'no valid thread', 3 unless (defined($thread));\n\n        my(@ret) = $thread->join;\n\n        ok((@ret == 3 and $ret[0]),\n           'stat CLONE_SKIP(): stat handle reference after spawning thread');\n\n        ok((@ret == 3 and $ret[1]),\n           'stat CLONE_SKIP(): scalar stat handle reference after ' .\n           'spawning thread');\n\n        ok((@ret == 3 and $ret[2]),\n           'stat CLONE_SKIP(): undef stat handle reference after ' .\n           'spawning thread');\n    }\n\n    my $watch = $zkh->watch();\n\n    ($thread) = threads->new(\\&thread_test, $watch);\n\n    SKIP: {\n        skip 'no valid thread', 3 unless (defined($thread));\n\n        my(@ret) = $thread->join;\n\n        ok((@ret == 3 and $ret[0]),\n           'watch CLONE_SKIP(): watch handle reference after spawning thread');\n\n        ok((@ret == 3 and $ret[1]),\n           'watch CLONE_SKIP(): scalar watch handle reference after ' .\n           'spawning thread');\n\n        ok((@ret == 3 and $ret[2]),\n           'watch CLONE_SKIP(): undef watch handle reference after ' .\n           'spawning thread');\n    }\n}\n\nsub thread_test\n{\n    my $zkh = shift;\n\n    my @ret;\n\n    $ret[0] = ref($zkh) ? 1 : 0;\n    $ret[1] = ($ret[0] and ref($zkh) eq 'SCALAR') ? 1 : 0;\n    $ret[2] = ($ret[1] and !defined(${$zkh})) ? 1 : 0;\n\n    return @ret;\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/20_tie.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 54;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 4 unless (defined($zkh));\n\n\n    ## DESTROY()\n\n    my $attr = tied(%{$zkh});\n\n    my $ret = $attr->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed inner hash');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on destroyed inner hash');\n\n    $ret = $zkh->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on handle with destroyed inner hash');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released handle with destroyed inner hash');\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 49 unless (defined($zkh));\n\n\n    ## TIEHASH(), UNTIE()\n\n    eval {\n        tie(%{$zkh}, 'Net::ZooKeeper');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper not supported/,\n         'tie(): tying hashes not supported');\n\n    eval {\n        Net::ZooKeeper::TIEHASH('Net::ZooKeeper');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper not supported/,\n         'TIEHASH(): tying hashes not supported');\n\n    eval {\n        untie(%{$zkh});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper not supported/,\n         'untie(): untying hashes not supported');\n\n    my $attr = tied(%{$zkh});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper not supported/,\n         'UNTIE(): untying hashes not supported');\n\n\n    ## FIRSTKEY(), NEXTKEY(), SCALAR()\n\n    my $copy_zkh;\n    {\n        my %copy_zkh = %{$zkh};\n        $copy_zkh = \\%copy_zkh;\n    }\n    bless($copy_zkh, 'Net::ZooKeeper');\n    is(ref($copy_zkh), 'Net::ZooKeeper',\n       'FIRSTKEY(), NEXTKEY(): copied dereferenced handle');\n\n    eval {\n        my $val = $copy_zkh->FIRSTKEY();\n    };\n    like($@, qr/invalid handle/,\n         'FETCHKEY(): invalid handle');\n\n    eval {\n        my $val = $copy_zkh->NEXTKEY('data_read_len');\n    };\n    like($@, qr/invalid handle/,\n         'NEXTKEY(): invalid handle');\n\n    my @keys = keys(%{$zkh});\n    is(scalar(@keys), 7,\n       'keys(): count of keys from handle');\n\n    @keys = keys(%{$copy_zkh});\n    is(scalar(@keys), 7,\n       'keys(): count of keys from copied dereferenced handle');\n\n    is($attr->FIRSTKEY(), 'data_read_len',\n       'FIRSTKEY(): retrieved first key using inner hash');\n\n    is($attr->NEXTKEY('session_id'), 'pending_watches',\n       'NEXTKEY(): retrieved last key using inner hash');\n\n    is($attr->NEXTKEY('pending_watches'), undef,\n       'NEXTKEY(): undef returned after last key using inner hash');\n\n    ok(scalar(%{$zkh}),\n       'scalar(): true value returned for dereferenced handle');\n\n    ok($zkh->SCALAR(),\n       'SCALAR(): true value returned');\n\n\n    ## FETCH()\n\n    eval {\n        my $val = $copy_zkh->FETCH('data_read_len');\n    };\n    like($@, qr/invalid handle/,\n         'FETCH(): invalid handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        my $val = $zkh->{'foo'};\n        ok(!defined($val),\n           'FETCH(): undef returned for invalid element');\n\n        like($msg, qr/invalid element/,\n             'FETCH(): invalid element');\n    }\n\n    is($zkh->{'data_read_len'}, 1023,\n       'FETCH(): default data read length');\n\n    is($zkh->{'path_read_len'}, 1023,\n       'FETCH(): default path read length');\n\n    is($zkh->{'hosts'}, $hosts,\n       'FETCH(): server hosts');\n\n    is($zkh->{'session_timeout'}, 10000,\n       'FETCH(): default session timeout');\n\n    ok(defined($zkh->{'session_id'}),\n       'FETCH(): session ID');\n\n    SKIP: {\n        my $zkh = Net::ZooKeeper->new('0.0.0.0:0');\n\n        skip 'no valid handle with invalid host', 1 unless (defined($zkh));\n\n        is($zkh->{'session_id'}, '',\n           'FETCH(): empty session ID with invalid host');\n    }\n\n    is($zkh->{'pending_watches'}, 0,\n       'FETCH(): default pending watch list length');\n\n    is($attr->FETCH('data_read_len'), 1023,\n       'FETCH(): default data read length using inner hash');\n\n\n    ## STORE()\n\n    eval {\n        my $val = $copy_zkh->STORE('data_read_len', 'foo');\n    };\n    like($@, qr/invalid handle/,\n         'STORE(): invalid handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->{'foo'} = 'foo';\n        like($msg, qr/invalid element/,\n             'STORE(): invalid element');\n    }\n\n    eval {\n        $zkh->{'data_read_len'} = -3;\n    };\n    like($@, qr/invalid data read length/,\n         'STORE(): invalid data read length');\n\n    eval {\n        $zkh->{'path_read_len'} = -3;\n    };\n    like($@, qr/invalid path read length/,\n         'STORE(): invalid path read length');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->{'hosts'} = 'foo';\n        like($msg, qr/read-only element: hosts/,\n             'STORE(): read-only server hosts element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->{'session_timeout'} = 0;\n        like($msg, qr/read-only element: session_timeout/,\n             'STORE(): read-only session timeout element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->{'session_id'} = 'foo';\n        like($msg, qr/read-only element: session_id/,\n             'STORE(): read-only session ID element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->{'pending_watches'} = 0;\n        like($msg, qr/read-only element: pending_watches/,\n             'STORE(): read-only pending watch list length element');\n    }\n\n    $zkh->{'data_read_len'} = 200;\n    is($zkh->{'data_read_len'}, 200,\n       'STORE(): updated data read length');\n\n    $zkh->{'path_read_len'} = 100;\n    is($zkh->{'path_read_len'}, 100,\n       'STORE(): updated path read length');\n\n    $attr->STORE('data_read_len', 100);\n    is($zkh->{'data_read_len'}, 100,\n       'STORE(): updated data read length using inner hash');\n\n\n    ## EXISTS()\n\n    eval {\n        my $val = $copy_zkh->EXISTS('data_read_len');\n    };\n    like($@, qr/invalid handle/,\n         'EXISTS(): invalid handle');\n\n    ok(!exists($zkh->{'foo'}),\n       'exists(): invalid element of handle');\n\n    ok(exists($zkh->{'data_read_len'}),\n       'exists(): data read length');\n\n    ok(exists($zkh->{'path_read_len'}),\n       'exists(): path read length');\n\n    ok(exists($zkh->{'hosts'}),\n       'exists(): server hosts');\n\n    ok(exists($zkh->{'session_timeout'}),\n       'exists(): session timeout');\n\n    ok(exists($zkh->{'session_id'}),\n       'exists(): session ID');\n\n    ok(exists($zkh->{'pending_watches'}),\n       'exists(): pending watch list length');\n\n    ok($attr->EXISTS('data_read_len'),\n       'EXISTS(): data read length using inner hash');\n\n\n    ## DELETE(), CLEAR()\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        delete($zkh->{'data_read_len'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper not supported/,\n             'delete(): deleting hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->DELETE({'data_read_len'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper not supported/,\n             'DELETE(): deleting hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        %{$zkh} = ();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper not supported/,\n             'assign: clearing hashes not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $zkh->CLEAR();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper not supported/,\n             'CLEAR(): clearing hashes not supported');\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/22_stat_tie.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 66;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n    my $stat = $zkh->stat() if (defined($zkh));\n\n    skip 'no valid stat handle', 4 unless (defined($stat));\n\n\n    ## DESTROY()\n\n    my $attr = tied(%{$stat});\n\n    my $ret = $attr->DESTROY();\n    ok($ret,\n       'stat DESTROY(): destroyed inner stat hash');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'stat DESTROY(): no action on destroyed inner stat hash');\n\n    $ret = $stat->DESTROY();\n    ok(!$ret,\n       'stat DESTROY(): no action on stat handle with destroyed inner hash');\n\n    undef $stat;\n    ok(!defined($stat),\n       'undef: released stat handle with destroyed inner hash');\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n    my $stat = $zkh->stat() if (defined($zkh));\n\n    skip 'no valid stat handle', 61 unless (defined($stat));\n\n\n    ## TIEHASH(), UNTIE()\n\n    eval {\n        tie(%{$stat}, 'Net::ZooKeeper::Stat');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper::Stat not supported/,\n         'tie(): tying stat hashes not supported');\n\n    eval {\n        Net::ZooKeeper::Stat::TIEHASH('Net::ZooKeeper::Stat');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper::Stat not supported/,\n         'stat TIEHASH(): tying stat hashes not supported');\n\n    eval {\n        untie(%{$stat});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,\n         'untie(): untying stat hashes not supported');\n\n    my $attr = tied(%{$stat});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,\n         'stat UNTIE(): untying stat hashes not supported');\n\n\n    ## FIRSTKEY(), NEXTKEY(), SCALAR()\n\n    my $copy_stat;\n    {\n        my %copy_stat = %{$stat};\n        $copy_stat = \\%copy_stat;\n    }\n    bless($copy_stat, 'Net::ZooKeeper::Stat');\n    is(ref($copy_stat), 'Net::ZooKeeper::Stat',\n       'stat FIRSTKEY(), NEXTKEY(): copied dereferenced stat handle');\n\n    eval {\n        my $val = $copy_stat->FIRSTKEY();\n    };\n    like($@, qr/invalid handle/,\n         'stat FETCHKEY(): invalid stat handle');\n\n    eval {\n        my $val = $copy_stat->NEXTKEY('czxid');\n    };\n    like($@, qr/invalid handle/,\n         'stat NEXTKEY(): invalid stat handle');\n\n    my @keys = keys(%{$stat});\n    is(scalar(@keys), 11,\n       'keys(): count of keys from stat handle');\n\n    @keys = keys(%{$copy_stat});\n    is(scalar(@keys), 11,\n       'keys(): count of keys from copied dereferenced stat handle');\n\n    is($attr->FIRSTKEY(), 'czxid',\n       'stat FIRSTKEY(): retrieved first key using inner stat hash');\n\n    is($attr->NEXTKEY('num_children'), 'children_zxid',\n       'stat NEXTKEY(): retrieved last key using inner stat hash');\n\n    is($attr->NEXTKEY('children_zxid'), undef,\n       'NEXTKEY(): undef returned after last key using inner stat hash');\n\n    ok(scalar(%{$stat}),\n       'scalar(): true value returned for dereferenced stat handle');\n\n    ok($stat->SCALAR(),\n       'stat SCALAR(): true value returned');\n\n\n    ## FETCH()\n\n    eval {\n        my $val = $copy_stat->FETCH('version');\n    };\n    like($@, qr/invalid handle/,\n         'stat FETCH(): invalid stat handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        my $val = $stat->{'foo'};\n        ok(!defined($val),\n           'stat FETCH(): undef returned for invalid element');\n\n        like($msg, qr/invalid element/,\n             'stat FETCH(): invalid element');\n    }\n\n    is($stat->{'czxid'}, 0,\n       'stat FETCH(): default node creation ZooKeeper transaction ID');\n\n    is($stat->{'mzxid'}, 0,\n       'stat FETCH(): default data last-modified ZooKeeper transaction ID');\n\n    is($stat->{'ctime'}, 0,\n       'stat FETCH(): default node creation time');\n\n    is($stat->{'mtime'}, 0,\n       'stat FETCH(): default data last-modified time');\n\n    is($stat->{'version'}, 0,\n       'stat FETCH(): default data version');\n\n    is($stat->{'children_version'}, 0,\n       'stat FETCH(): default child node list version');\n\n    is($stat->{'acl_version'}, 0,\n       'stat FETCH(): default ACL version');\n\n    is($stat->{'ephemeral_owner'}, 0,\n       'stat FETCH(): ephemeral node owner session ID');\n\n    is($stat->{'data_len'}, 0,\n       'stat FETCH(): default data length');\n\n    is($stat->{'num_children'}, 0,\n       'stat FETCH(): default child node list length');\n\n    is($stat->{'children_zxid'}, 0,\n       'stat FETCH(): default child node list last-modified ' .\n       'ZooKeeper transaction ID');\n\n    is($attr->FETCH('version'), 0,\n       'stat FETCH(): default data version using inner stat hash');\n\n\n    ## STORE()\n\n    eval {\n        my $val = $copy_stat->STORE('version', 'foo');\n    };\n    like($@, qr/invalid handle/,\n         'stat STORE(): invalid stat handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'foo'} = 'foo';\n        like($msg, qr/invalid element/,\n             'stat STORE(): invalid element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'czxid'} = 'foo';\n        like($msg, qr/read-only element: czxid/,\n             'stat STORE(): read-only node creation ' .\n             'ZooKeeper transaction ID element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'mzxid'} = 'foo';\n        like($msg, qr/read-only element: mzxid/,\n             'stat STORE(): read-only data last-modified ' .\n             'ZooKeeper transaction ID element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'ctime'} = 'foo';\n        like($msg, qr/read-only element: ctime/,\n             'stat STORE(): read-only node creation time element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'mtime'} = 'foo';\n        like($msg, qr/read-only element: mtime/,\n             'stat STORE(): read-only data last-modified time element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'version'} = 'foo';\n        like($msg, qr/read-only element: version/,\n             'stat STORE(): read-only data version element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'children_version'} = 'foo';\n        like($msg, qr/read-only element: children_version/,\n             'stat STORE(): read-only child node list version element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'acl_version'} = 'foo';\n        like($msg, qr/read-only element: acl_version/,\n             'stat STORE(): read-only ACL version element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'ephemeral_owner'} = 'foo';\n        like($msg, qr/read-only element: ephemeral_owner/,\n             'stat STORE(): read-only ephemeral node owner ' .\n             'session ID element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'data_len'} = 'foo';\n        like($msg, qr/read-only element: data_len/,\n             'stat STORE(): read-only data length element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'num_children'} = 'foo';\n        like($msg, qr/read-only element: num_children/,\n             'stat STORE(): read-only child node list length element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->{'children_zxid'} = 'foo';\n        like($msg, qr/read-only element: children_zxid/,\n             'stat STORE(): read-only child node list last-modified ' .\n             'ZooKeeper transaction ID element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $attr->STORE('version', 'foo');\n        like($msg, qr/read-only element: version/,\n             'stat STORE(): read-only data version element using ' .\n             'inner stat hash');\n    }\n\n\n    ## EXISTS()\n\n    eval {\n        my $val = $copy_stat->EXISTS('version');\n    };\n    like($@, qr/invalid handle/,\n         'stat EXISTS(): invalid stat handle');\n\n    ok(!exists($stat->{'foo'}),\n       'exists(): invalid element of stat handle');\n\n    ok(exists($stat->{'czxid'}),\n       'exists(): node creation ZooKeeper transaction ID');\n\n    ok(exists($stat->{'mzxid'}),\n       'exists(): data last-modified ZooKeeper transaction ID');\n\n    ok(exists($stat->{'ctime'}),\n       'exists(): node creation time');\n\n    ok(exists($stat->{'mtime'}),\n       'exists(): data last-modified time');\n\n    ok(exists($stat->{'version'}),\n       'exists(): data version');\n\n    ok(exists($stat->{'children_version'}),\n       'exists(): child node list version');\n\n    ok(exists($stat->{'acl_version'}),\n       'exists(): ACL version');\n\n    ok(exists($stat->{'ephemeral_owner'}),\n       'exists(): ephemeral node owner session ID');\n\n    ok(exists($stat->{'data_len'}),\n       'exists(): data length');\n\n    ok(exists($stat->{'num_children'}),\n       'exists(): child node list length');\n\n    ok(exists($stat->{'children_zxid'}),\n       'exists(): child node list last-modified ZooKeeper transaction ID');\n\n    ok($attr->EXISTS('version'),\n       'stat EXISTS(): data version using inner stat hash');\n\n\n    ## DELETE(), CLEAR()\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        delete($stat->{'version'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper::Stat not supported/,\n             'delete(): deleting stat hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->DELETE({'version'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper::Stat not supported/,\n             'stat DELETE(): deleting stat hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        %{$stat} = ();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper::Stat not supported/,\n             'assign: clearing stat hashes not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $stat->CLEAR();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper::Stat not supported/,\n             'stat CLEAR(): clearing stat hashes not supported');\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/24_watch_tie.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 42;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n    my $watch = $zkh->watch() if (defined($zkh));\n\n    skip 'no valid watch handle', 4 unless (defined($watch));\n\n\n    ## DESTROY()\n\n    my $attr = tied(%{$watch});\n\n    my $ret = $attr->DESTROY();\n    ok($ret,\n       'watch DESTROY(): destroyed inner watch hash');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'watch DESTROY(): no action on destroyed inner watch hash');\n\n    $ret = $watch->DESTROY();\n    ok(!$ret,\n       'watch DESTROY(): no action on watch handle with destroyed inner hash');\n\n    undef $watch;\n    ok(!defined($watch),\n       'undef: released watch handle with destroyed inner hash');\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n    my $watch = $zkh->watch() if (defined($zkh));\n\n    skip 'no valid watch handle', 37 unless (defined($watch));\n\n\n    ## TIEHASH(), UNTIE()\n\n    eval {\n        tie(%{$watch}, 'Net::ZooKeeper::Watch');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper::Watch not supported/,\n         'tie(): tying watch hashes not supported');\n\n    eval {\n        Net::ZooKeeper::Watch::TIEHASH('Net::ZooKeeper::Watch');\n    };\n    like($@, qr/tying hashes of class Net::ZooKeeper::Watch not supported/,\n         'watch TIEHASH(): tying watch hashes not supported');\n\n    eval {\n        untie(%{$watch});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,\n         'untie(): untying watch hashes not supported');\n\n    my $attr = tied(%{$watch});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,\n         'watch UNTIE(): untying watch hashes not supported');\n\n\n    ## FIRSTKEY(), NEXTKEY(), SCALAR()\n\n    my $copy_watch;\n    {\n        my %copy_watch = %{$watch};\n        $copy_watch = \\%copy_watch;\n    }\n    bless($copy_watch, 'Net::ZooKeeper::Watch');\n    is(ref($copy_watch), 'Net::ZooKeeper::Watch',\n       'watch FIRSTKEY(), NEXTKEY(): copied dereferenced watch handle');\n\n    eval {\n        my $val = $copy_watch->FIRSTKEY();\n    };\n    like($@, qr/invalid handle/,\n         'watch FETCHKEY(): invalid watch handle');\n\n    eval {\n        my $val = $copy_watch->NEXTKEY('czxid');\n    };\n    like($@, qr/invalid handle/,\n         'watch NEXTKEY(): invalid watch handle');\n\n    my @keys = keys(%{$watch});\n    is(scalar(@keys), 3,\n       'keys(): count of keys from watch handle');\n\n    @keys = keys(%{$copy_watch});\n    is(scalar(@keys), 3,\n       'keys(): count of keys from copied dereferenced watch handle');\n\n    is($attr->FIRSTKEY(), 'timeout',\n       'watch FIRSTKEY(): retrieved first key using inner watch hash');\n\n    is($attr->NEXTKEY('event'), 'state',\n       'watch NEXTKEY(): retrieved last key using inner watch hash');\n\n    is($attr->NEXTKEY('state'), undef,\n       'NEXTKEY(): undef returned after last key using inner watch hash');\n\n    ok(scalar(%{$watch}),\n       'scalar(): true value returned for dereferenced watch handle');\n\n    ok($watch->SCALAR(),\n       'watch SCALAR(): true value returned');\n\n\n    ## FETCH()\n\n    eval {\n        my $val = $copy_watch->FETCH('version');\n    };\n    like($@, qr/invalid handle/,\n         'watch FETCH(): invalid watch handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        my $val = $watch->{'foo'};\n        ok(!defined($val),\n           'watch FETCH(): undef returned for invalid element');\n\n        like($msg, qr/invalid element/,\n             'watch FETCH(): invalid element');\n    }\n\n    is($watch->{'timeout'}, 60000,\n       'watch FETCH(): default timeout');\n\n    is($watch->{'event'}, 0,\n       'watch FETCH(): default event');\n\n    is($watch->{'state'}, 0,\n       'watch FETCH(): default state');\n\n    is($attr->FETCH('timeout'), 60000,\n       'watch FETCH(): default timeout using inner watch hash');\n\n\n    ## STORE()\n\n    eval {\n        my $val = $copy_watch->STORE('version', 'foo');\n    };\n    like($@, qr/invalid handle/,\n         'watch STORE(): invalid watch handle');\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $watch->{'foo'} = 'foo';\n        like($msg, qr/invalid element/,\n             'watch STORE(): invalid element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $watch->{'event'} = 'foo';\n        like($msg, qr/read-only element: event/,\n             'watch STORE(): read-only event element');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $watch->{'state'} = 'foo';\n        like($msg, qr/read-only element: state/,\n             'watch STORE(): read-only state element');\n    }\n\n    $watch->{'timeout'} = 100;\n    is($watch->{'timeout'}, 100,\n       'watch STORE(): updated timeout');\n\n    $attr->STORE('timeout', 200);\n    is($watch->{'timeout'}, 200,\n       'watch STORE(): updated timeout using inner hash');\n\n\n    ## EXISTS()\n\n    eval {\n        my $val = $copy_watch->EXISTS('version');\n    };\n    like($@, qr/invalid handle/,\n         'watch EXISTS(): invalid watch handle');\n\n    ok(!exists($watch->{'foo'}),\n       'exists(): invalid element of watch handle');\n\n    ok(exists($watch->{'timeout'}),\n       'exists(): timeout');\n\n    ok(exists($watch->{'event'}),\n       'exists(): event');\n\n    ok(exists($watch->{'state'}),\n       'exists(): state');\n\n    ok($attr->EXISTS('timeout'),\n       'watch EXISTS(): timeout using inner watch hash');\n\n\n    ## DELETE(), CLEAR()\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        delete($watch->{'version'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper::Watch not supported/,\n             'delete(): deleting watch hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $watch->DELETE({'version'});\n        like($msg,\n             qr/deleting elements from hashes of class Net::ZooKeeper::Watch not supported/,\n             'watch DELETE(): deleting watch hash elements not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        %{$watch} = ();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper::Watch not supported/,\n             'assign: clearing watch hashes not supported');\n    }\n\n    {\n        my $msg;\n\n        $SIG{'__WARN__'} = sub { $msg = $_[0]; };\n\n        $watch->CLEAR();\n        like($msg, qr/clearing hashes of class Net::ZooKeeper::Watch not supported/,\n             'watch CLEAR(): clearing watch hashes not supported');\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/30_connect.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 29;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\n## new(), DESTROY()\n\nNet::ZooKeeper::set_deterministic_conn_order(1);\n\nmy $zkh = Net::ZooKeeper->new($hosts);\nisa_ok($zkh, 'Net::ZooKeeper',\n       'new(): created handle');\n\nSKIP: {\n    skip 'no valid handle', 3 unless (defined($zkh));\n\n    my $ret = $zkh->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed handle');\n\n    $ret = $zkh->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on destroyed handle');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released handle');\n}\n\nNet::ZooKeeper::set_deterministic_conn_order(0);\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 10 unless (defined($zkh));\n\n    my $copy_zkh = $zkh;\n    isa_ok($copy_zkh, 'Net::ZooKeeper',\n           'assign: copied handle');\n\n    my $ret = $zkh->exists($root_path);\n    ok(defined($ret),\n       'exists(): no error from original handle');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released original handle');\n\n    $ret = $copy_zkh->exists($root_path);\n    ok(defined($ret),\n       'exists(): no error from first copy of handle');\n\n    $zkh = $copy_zkh;\n    isa_ok($zkh, 'Net::ZooKeeper',\n           'assign: re-copied handle');\n\n    $ret = $copy_zkh->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed first copy of handle');\n\n    eval {\n        $zkh->exists($root_path);\n    };\n    like($@, qr/invalid handle/,\n         'exists(): invalid second copy of handle');\n\n    undef $copy_zkh;\n    ok(!defined($copy_zkh),\n       'undef: released first copy of handle');\n\n    $ret = $zkh->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on second copy of destroyed handle');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released second copy of handle');\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 6 unless (defined($zkh));\n\n    my $copy_zkh;\n    {\n        my %copy_zkh = %{$zkh};\n        $copy_zkh = \\%copy_zkh;\n    }\n    bless($copy_zkh, 'Net::ZooKeeper');\n    isa_ok($copy_zkh, 'Net::ZooKeeper',\n           'FIRSTKEY(), NEXTKEY(): copied dereferenced handle');\n\n    eval {\n        $copy_zkh->exists($root_path);\n    };\n    like($@, qr/invalid handle/,\n         'exists(): invalid copy of dereferenced handle');\n\n    $ret = $copy_zkh->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on copy of dereferenced handle');\n\n    undef $copy_zkh;\n    ok(!defined($copy_zkh),\n       'undef: released copy of dereferenced handle');\n\n    my $ret = $zkh->exists($root_path);\n    ok(defined($ret),\n       'exists(): no error from original handle');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released original handle');\n}\n\nNet::ZooKeeper::set_deterministic_conn_order(1);\n\nmy $zkh1 = Net::ZooKeeper->new($hosts, 'session_timeout' => 0x3FFF_FFFF);\nisa_ok($zkh1, 'Net::ZooKeeper',\n       'new(): created handle with maximum session timeout');\n\nSKIP: {\n    my $ret = $zkh1->exists($root_path) if (defined($zkh1));\n\n    skip 'no connection to ZooKeeper', 7 unless\n        (defined($ret) and $ret);\n\n\n    ## FETCH() of read-only attributes\n\n    ok(($zkh1->{'session_timeout'} > 0 and\n        $zkh1->{'session_timeout'} <= 0x3FFF_FFFF),\n       'FETCH(): session timeout reset after connection');\n\n    my $session_id1 = $zkh1->{'session_id'};\n    ok((length($session_id1) > 0),\n       'FETCH(): non-empty session ID after connection');\n\n    SKIP: {\n        skip 'no session ID after connection', 1 unless\n            (length($session_id1) > 0);\n\n        my @nonzero_bytes = grep($_ != 0, unpack('c' x length($session_id1),\n                                                 $session_id1));\n        ok((@nonzero_bytes > 0),\n           'FETCH(): non-zero session ID after connection');\n    }\n\n    ## NOTE: to test re-connections with saved session IDs we create a second\n    ## connection with the same ID while the first is still active;\n    ## this is bad practice in normal usage\n\n    my $zkh2 = Net::ZooKeeper->new($hosts,\n                                  'session_id' => $session_id1,\n                                  'session_timeout' => 20000);\n    isa_ok($zkh2, 'Net::ZooKeeper',\n           'new(): created handle with session ID and valid session timeout');\n\n    $ret = $zkh2->exists($root_path);\n    ok($ret,\n       'new(): reconnection with session ID');\n\n    SKIP: {\n        skip 'no connection to ZooKeeper', 2 unless ($ret);\n\n        is($zkh2->{'session_timeout'}, 20000,\n           'FETCH(): session timeout unchanged after connection');\n\n        my $session_id2 = $zkh2->{'session_id'};\n        ok((length($session_id2) == length($session_id1)\n            and $session_id2 eq $session_id1),\n           'FETCH(): reconnect with session ID');\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/35_log.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 3;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nmy $zkh = Net::ZooKeeper->new($hosts);\n\nNet::ZooKeeper::set_log_level(ZOO_LOG_LEVEL_INFO);\n\nSKIP: {\n    skip 'no valid handle', 2 unless (defined($zkh));\n\n    SKIP: {\n        my $dup = 0;\n\n        if (open(OLDERR, '>&', fileno(STDERR))) {\n            if (close(STDERR) and open(STDERR, '+>', undef)) {\n                $dup = 1;\n\n                my $old_select = select(STDERR);\n                $| = 1;\n                select($old_select);\n            }\n            else {\n                open(STDERR, '>&', fileno(OLDERR));\n                close(OLDERR);\n            }\n        }\n\n        skip 'no duplicated stderr', 2 unless ($dup);\n\n        SKIP: {\n            $zkh->exists($root_path);\n\n            sleep(1);\n\n            skip 'no seek on stderr', 1 unless (seek(STDERR, 0, 0));\n\n            my $log = <STDERR>;\n            like($log, qr/ZOO_/,\n                 'exists(): generated log message');\n        }\n\n        SKIP: {\n            $zkh->DESTROY();\n\n            sleep(1);\n\n            skip 'no seek on stderr', 1 unless (seek(STDERR, 0, 0));\n\n            my $log = <STDERR>;\n            like($log, qr/ZOO_/,\n                 'DESTROY(): generated log message');\n        }\n\n        open(STDERR, '>&', fileno(OLDERR));\n        close(OLDERR);\n    }\n}\n\nNet::ZooKeeper::set_log_level(ZOO_LOG_LEVEL_OFF);\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/40_basic.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 35;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nmy $zkh = Net::ZooKeeper->new($hosts);\nmy $path;\n\nSKIP: {\n    my $ret = $zkh->exists($root_path) if (defined($zkh));\n\n    skip 'no connection to ZooKeeper', 1 unless\n        (defined($ret) and $ret);\n\n    $path = $zkh->create($node_path, 'foo', 'acl' => ZOO_OPEN_ACL_UNSAFE);\n    is($path, $node_path,\n       'create(): created node');\n}\n\nSKIP: {\n    skip 'no connection to ZooKeeper', 21 unless\n        (defined($path) and $path eq $node_path);\n\n\n    ## exists()\n\n    my $ret = $zkh->exists($node_path);\n    ok($ret,\n       'exists(): checked node existence');\n\n    $ret = $zkh->exists($node_path . '/NONE');\n    ok((!$ret and $zkh->get_error() == ZNONODE and $! eq ''),\n       'exists(): checked node non-existence');\n\n    my $stat = $zkh->stat();\n\n    $ret = $zkh->exists($node_path, 'stat' => $stat);\n    ok(($ret and $stat->{'data_len'} == 3),\n       'exists(): checked node existence with stat handle');\n\n\n    ## get()\n\n    my $node = $zkh->get($node_path);\n    is($node, 'foo',\n       'get(): retrieved node value');\n\n    $node = $zkh->get($node_path . '/NONE');\n    ok((!defined($node) and $zkh->get_error() == ZNONODE and $! eq ''),\n       'get(): undef returned for non-extant node');\n\n    $node = $zkh->get($node_path, 'data_read_len', 2);\n    is($node, 'fo',\n       'get(): retrieved truncated node value');\n\n    $node = $zkh->get($node_path, 'data_read_len' => 0);\n    is($node, '',\n       'get(): retrieved zero-length node value');\n\n    $node = $zkh->get($node_path, 'stat' => $stat);\n    ok(($node eq 'foo' and $stat->{'data_len'} == 3),\n       'get(): retrieved node value with stat handle');\n\n\n    ## set()\n\n    $ret = $zkh->set($node_path, 'foo');\n    ok($ret,\n       'set(): set node value');\n\n    SKIP: {\n        my $ret = $zkh->exists($node_path, 'stat' => $stat);\n\n        skip 'invalid node data', 2 unless\n            ($ret and $stat->{'version'} == 1);\n\n        $ret = $zkh->set($node_path, 'foo', 'version' => $stat->{'version'});\n        ok($ret,\n           'set(): set node value with matching version');\n\n        $ret = $zkh->set($node_path, 'foo', 'version' => $stat->{'version'});\n        ok((!$ret and $zkh->get_error() == ZBADVERSION and $! eq ''),\n           'set(): node value unchanged if non-matching version');\n    }\n\n    $ret = $zkh->set($node_path, 'foobaz', 'stat' => $stat);\n    ok(($ret and $stat->{'data_len'} == 6),\n       'set(): retrieved node value with stat handle');\n\n\n    ## create(), delete()\n\n    $path = $zkh->create($node_path, 'foo', 'acl' => ZOO_OPEN_ACL_UNSAFE);\n    ok((!defined($path) and $zkh->get_error() == ZNODEEXISTS and $! eq ''),\n       'create(): undef when attempting to create extant node');\n\n    $ret = $zkh->delete($node_path . '/NONE');\n    ok((!$ret and $zkh->get_error() == ZNONODE and $! eq ''),\n       'delete(): no deletion of non-extant node');\n\n    $ret = $zkh->delete($node_path);\n    ok($ret,\n       'delete(): deleted node');\n\n    my $path_read_len = length($node_path) - 2;\n\n    $path = $zkh->create($node_path, 'foo',\n                         'path_read_len' => $path_read_len,\n                         'acl' => ZOO_OPEN_ACL_UNSAFE);\n    is($path, substr($node_path, 0, -2),\n       'create(): created node with small return path buffer');\n\n    $path = $zkh->create(\"$node_path/s\", 'foo',\n                         'flags' => ZOO_SEQUENCE,\n                         'acl' => ZOO_OPEN_ACL_UNSAFE);\n    like($path, qr/^$node_path\\/s[0-9]+$/,\n       'create(): created sequential node');\n\n    SKIP: {\n        my $ret = $zkh->exists($path, 'stat' => $stat);\n\n        unless ($ret and $stat->{'version'} == 0) {\n            my $ret = $zkh->delete($path);\n            diag(sprintf('unable to delete node %s: %d, %s',\n                         $path, $zkh->get_error(), $!)) unless ($ret);\n\n            skip 'invalid node data', 2;\n        }\n\n        $ret = $zkh->delete($path, 'version' => ($stat->{'version'} + 1));\n        ok((!$ret and $zkh->get_error() == ZBADVERSION and $! eq ''),\n           'delete(): node not deleted if non-matching version');\n\n        $ret = $zkh->delete($path, 'version' => $stat->{'version'});\n        ok($ret,\n           'delete(): deleted sequential node with matching version');\n    }\n\n    $path = $zkh->create(\"$node_path/e\", 'foo',\n                         'flags' => ZOO_EPHEMERAL,\n                         'acl' => ZOO_OPEN_ACL_UNSAFE);\n    is($path, \"$node_path/e\",\n       'create(): created ephemeral node');\n\n    $path = $zkh->create(\"$node_path/es\", 'foo',\n                         'flags' => (ZOO_SEQUENCE | ZOO_EPHEMERAL),\n                         'acl' => ZOO_OPEN_ACL_UNSAFE);\n    like($path, qr/^$node_path\\/es[0-9]+$/,\n       'create(): created ephemeral sequential node');\n\n    undef $zkh;\n}\n\n$zkh = Net::ZooKeeper->new($hosts);\n\nSKIP: {\n    my $ret = $zkh->exists($node_path) if (defined($zkh));\n\n    skip 'no connection to ZooKeeper', 12 unless\n        (defined($ret) and $ret);\n\n    $ret = $zkh->exists(\"$node_path/e\");\n    ok((!$ret and $zkh->get_error() == ZNONODE and $! eq ''),\n       'exists(): checked ephemeral node non-extant after reconnection');\n\n    $ret = $zkh->exists($path);\n    ok((!$ret and $zkh->get_error() == ZNONODE and $! eq ''),\n       'exists(): checked ephemeral sequential node non-extant ' .\n       'after reconnection');\n\n\n    ## get_children()\n\n    my @child_paths = ('abc');\n    @child_paths = $zkh->get_children($node_path);\n    ok((@child_paths == 0 and $zkh->get_error() == ZOK),\n       'get_children(): retrieved empty list of child nodes');\n\n    my $num_children = $zkh->get_children($node_path);\n    ok((defined($num_children) and $num_children == 0),\n       'get_children(): retrieved zero count of child nodes');\n\n    @child_paths = $zkh->get_children($node_path . '/NONE');\n    ok((@child_paths == 0 and $zkh->get_error() == ZNONODE and $! eq ''),\n       'get_children(): empty list returned for non-extant node');\n\n    $num_children = $zkh->get_children($node_path . '/NONE');\n    ok((!defined($num_children) and $zkh->get_error() == ZNONODE and $! eq ''),\n       'get_children(): undef returned for non-extant node');\n\n    SKIP: {\n        my $path = $zkh->create(\"$node_path/c1\", 'foo',\n                                'acl' => ZOO_OPEN_ACL_UNSAFE);\n\n        skip 'no connection to ZooKeeper', 6 unless\n            (defined($path) and $path eq \"$node_path/c1\");\n\n        my @child_paths = ('abc');\n        @child_paths = $zkh->get_children($node_path);\n        ok((@child_paths == 1 and $child_paths[0] eq 'c1'),\n           'get_children(): retrieved list of single child node');\n\n        my $num_children = $zkh->get_children($node_path);\n        ok((defined($num_children) and $num_children == 1),\n           'get_children(): retrieved count of single child node');\n\n        SKIP: {\n            my $path = $zkh->create(\"$node_path/c2\", 'foo',\n                                    'acl' => ZOO_OPEN_ACL_UNSAFE);\n\n            skip 'no connection to ZooKeeper', 2 unless\n                (defined($path) and $path eq \"$node_path/c2\");\n\n            my @child_paths = ('abc');\n            @child_paths = $zkh->get_children($node_path);\n            ok((@child_paths == 2 and $child_paths[0] eq 'c1' and\n                $child_paths[1] eq 'c2'),\n               'get_children(): retrieved list of two child nodes');\n\n            my $num_children = $zkh->get_children($node_path);\n            ok((defined($num_children) and $num_children == 2),\n               'get_children(): retrieved count of two child nodes');\n\n            my $ret = $zkh->delete(\"$node_path/c2\");\n            diag(sprintf('unable to delete node %s: %d, %s',\n                         \"$node_path/c2\", $zkh->get_error(), $!)) unless\n                ($ret);\n        }\n\n        @child_paths = ('abc');\n        @child_paths = $zkh->get_children($node_path);\n        ok((@child_paths == 1 and $child_paths[0] eq 'c1'),\n           'get_children(): retrieved list of single child node');\n\n        $num_children = $zkh->get_children($node_path);\n        ok((defined($num_children) and $num_children == 1),\n           'get_children(): retrieved count of single child node');\n\n        my $ret = $zkh->delete(\"$node_path/c1\");\n        diag(sprintf('unable to delete node %s: %d, %s',\n                     \"$node_path/c1\", $zkh->get_error(), $!)) unless ($ret);\n    }\n\n\n    ## cleanup\n\n    $ret = $zkh->delete($node_path);\n    diag(sprintf('unable to delete node %s: %d, %s',\n                 $node_path, $zkh->get_error(), $!)) unless ($ret);\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/45_class.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 47;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 15 unless (defined($zkh));\n\n    my $stat = $zkh->stat();\n    my $watch = $zkh->watch();\n\n\n    ## DESTROY() on reblessed handle\n\n    bless($zkh, 'My::ZooKeeper');\n    is(ref($zkh), 'My::ZooKeeper',\n       'bless(): reblessed handle');\n\n    eval {\n        $zkh->EXISTS();\n    };\n    like($@, qr/Can't locate object method \"EXISTS\" via package \"My::ZooKeeper\"/,\n         'EXISTS(): not defined on reblessed handle');\n\n    my $attr = tied(%{$zkh});\n\n    my $ret = $attr->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed inner hash of reblessed handle');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on destroyed inner hash of reblessed handle');\n\n    undef $zkh;\n    ok(!defined($zkh),\n       'undef: released reblessed handle');\n\n\n    ## DESTROY() on reblessed stat handle\n\n    bless($stat, 'My::ZooKeeper::Stat');\n    is(ref($stat), 'My::ZooKeeper::Stat',\n       'bless(): reblessed stat handle');\n\n    eval {\n        $stat->EXISTS(1);\n    };\n    like($@, qr/Can't locate object method \"EXISTS\" via package \"My::ZooKeeper::Stat\"/,\n         'stat EXISTS(): not defined on reblessed stat handle');\n\n    $attr = tied(%{$stat});\n\n    $ret = $attr->DESTROY();\n    ok($ret,\n       'stat DESTROY(): destroyed inner hash of reblessed stat handle');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'stat DESTROY(): no action on destroyed inner hash of ' .\n       'reblessed stat handle');\n\n    undef $stat;\n    ok(!defined($stat),\n       'undef: released reblessed stat handle');\n\n\n    ## DESTROY() on reblessed watch handle\n\n    bless($watch, 'My::ZooKeeper::Watch');\n    is(ref($watch), 'My::ZooKeeper::Watch',\n       'bless(): reblessed watch handle');\n\n    eval {\n        $watch->EXISTS(1);\n    };\n    like($@, qr/Can't locate object method \"EXISTS\" via package \"My::ZooKeeper::Watch\"/,\n         'watch EXISTS(): not defined on reblessed watch handle');\n\n    $attr = tied(%{$watch});\n\n    $ret = $attr->DESTROY();\n    ok($ret,\n       'watch DESTROY(): destroyed inner hash of reblessed watch handle');\n\n    $ret = $attr->DESTROY();\n    ok(!$ret,\n       'watch DESTROY(): no action on destroyed inner hash of ' .\n       'reblessed watch handle');\n\n    undef $watch;\n    ok(!defined($watch),\n       'undef: released reblessed watch handle');\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    skip 'no valid handle', 9 unless (defined($zkh));\n\n    my $stat = $zkh->stat();\n    my $watch = $zkh->watch();\n\n\n    ## UNTIE() on reblessed handle\n\n    bless($zkh, 'My::ZooKeeper');\n    is(ref($zkh), 'My::ZooKeeper',\n       'bless(): reblessed handle');\n\n    eval {\n        untie(%{$zkh});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper not supported/,\n         'untie(): untying hashes from reblessed handle not supported');\n\n    my $attr = tied(%{$zkh});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper not supported/,\n         'UNTIE(): untying hashes from reblessed handle not supported');\n\n\n    ## UNTIE() on reblessed stat handle\n\n    bless($stat, 'My::ZooKeeper::Stat');\n    is(ref($stat), 'My::ZooKeeper::Stat',\n       'bless(): reblessed stat handle');\n\n    eval {\n        untie(%{$stat});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,\n         'untie(): untying hashes from reblessed stat handle not supported');\n\n    $attr = tied(%{$stat});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,\n         'stat UNTIE(): untying hashes from reblessed stat handle ' .\n         'not supported');\n\n\n    ## UNTIE() on reblessed watch handle\n\n    bless($watch, 'My::ZooKeeper::Watch');\n    is(ref($watch), 'My::ZooKeeper::Watch',\n       'bless(): reblessed watch handle');\n\n    eval {\n        untie(%{$watch});\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,\n         'untie(): untying hashes from reblessed watch handle not supported');\n\n    $attr = tied(%{$watch});\n\n    eval {\n        $attr->UNTIE(0);\n    };\n    like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,\n         'watch UNTIE(): untying hashes from reblessed watch handle ' .\n         'not supported');\n}\n\n\npackage Net::ZooKeeper::Test;\n\nuse Net::ZooKeeper qw(:acls);\n\nour @ISA = qw(Net::ZooKeeper);\n\nsub create\n{\n    my($self, $path, $buf) = @_;\n\n    return $self->SUPER::create($path, $buf,\n                                'path_read_len' => length($path),\n                                'acl' => ZOO_OPEN_ACL_UNSAFE);\n}\n\nsub get_first_child\n{\n    my($self, $path) = @_;\n\n    my @child_paths = $self->get_children($path);\n\n    if (@child_paths > 0) {\n        return $path . (($path =~ /\\/$/) ? '' : '/') . $child_paths[0];\n    }\n\n    return undef;\n}\n\nsub stat\n{\n    my $self = shift;\n\n    my $stat = $self->SUPER::stat();\n\n    return bless($stat, 'Net::ZooKeeper::Test::Stat');\n}\n\n\nsub watch\n{\n    my $self = shift;\n\n    my $watch = $self->SUPER::watch();\n\n    return bless($watch, 'Net::ZooKeeper::Test::Watch');\n}\n\n\npackage Net::ZooKeeper::Test::Stat;\n\nour @ISA = qw(Net::ZooKeeper::Stat);\n\nsub get_ctime\n{\n    my $self = shift;\n\n    return $self->{'ctime'};\n}\n\n\npackage Net::ZooKeeper::Test::Watch;\n\nour @ISA = qw(Net::ZooKeeper::Watch);\n\nsub get_timeout\n{\n    my $self = shift;\n\n    return $self->{'timeout'};\n}\n\n\npackage main;\n\nmy $sub_zkh = Net::ZooKeeper::Test->new($hosts);\nisa_ok($sub_zkh, 'Net::ZooKeeper::Test',\n       'new(): created subclassed handle');\n\nSKIP: {\n    skip 'no valid subclassed handle', 21 unless (defined($sub_zkh));\n\n    is($sub_zkh->{'data_read_len'}, 1023,\n       'FETCH(): default data read length using subclassed handle');\n\n    my $path;\n\n    SKIP: {\n        my $ret = $sub_zkh->exists($root_path);\n\n        skip 'no connection to ZooKeeper', 1 unless\n            (defined($ret) and $ret);\n\n        $path = $sub_zkh->create($node_path, 'foo',\n                                 'acl' => ZOO_OPEN_ACL_UNSAFE);\n        is($path, $node_path,\n           'create(): created node with subclassed handle');\n    }\n\n    SKIP: {\n        skip 'no connection to ZooKeeper', 1 unless\n            (defined($path) and $path eq $node_path);\n\n        my $child_path = $sub_zkh->get_first_child($root_path);\n        is($child_path, $node_path,\n           'get_first_child(): retrieved first child with subclassed handle');\n    }\n\n    my $sub_stat = $sub_zkh->stat();\n    isa_ok($sub_stat, 'Net::ZooKeeper::Test::Stat',\n           'stat(): created subclassed stat handle');\n\n    SKIP: {\n        skip 'no valid subclassed stat handle', 6 unless\n            (defined($sub_stat));\n\n        is($sub_stat->{'ctime'}, 0,\n           'stat FETCH(): default ctime using subclassed stat handle');\n\n        SKIP: {\n            my $ret = $sub_zkh->exists($node_path, 'stat' => $sub_stat) if\n                (defined($path) and $path eq $node_path);\n\n            skip 'no connection to ZooKeeper', 2 unless\n                (defined($ret) and $ret);\n\n            my $ctime = $sub_stat->get_ctime();\n            ok($ctime > 0,\n               'get_ctime(): retrieved ctime with subclassed stat handle');\n\n            is($sub_stat->{'ctime'}, $ctime,\n               'stat FETCH(): ctime using subclassed stat handle');\n        }\n\n        my $ret = $sub_stat->DESTROY();\n        ok($ret,\n           'stat DESTROY(): destroyed subclassed stat handle');\n\n        $ret = $sub_stat->DESTROY();\n        ok(!$ret,\n           'stat DESTROY(): no action on destroyed subclassed stat handle');\n\n        undef $sub_stat;\n        ok(!defined($sub_stat),\n           'undef: released subclassed stat handle');\n    }\n\n    my $sub_watch = $sub_zkh->watch();\n    isa_ok($sub_watch, 'Net::ZooKeeper::Test::Watch',\n           'watch(): created subclassed watch handle');\n\n    SKIP: {\n        skip 'no valid subclassed watch handle', 6 unless\n            (defined($sub_watch));\n\n        SKIP: {\n            my $ret = $sub_zkh->exists($root_path, 'watch' => $sub_watch);\n\n            skip 'no connection to ZooKeeper', 3 unless\n                (defined($ret) and $ret);\n\n            $sub_watch->{'timeout'} = 50;\n\n            is($sub_watch->get_timeout(), 50,\n               'get_timeout(): retrieved timeout with subclassed ' .\n               'watch handle');\n\n            is($sub_watch->{'timeout'}, 50,\n               'watch FETCH(): timeout using subclassed stat handle');\n\n            $ret = $sub_watch->wait();\n            ok(!$ret,\n               'wait(): watch after checking node existence timed out with ' .\n               'subclassed watch handle');\n        }\n\n        my $ret = $sub_watch->DESTROY();\n        ok($ret,\n           'watch DESTROY(): destroyed subclassed watch handle');\n\n        $ret = $sub_watch->DESTROY();\n        ok(!$ret,\n           'watch DESTROY(): no action on destroyed subclassed watch handle');\n\n        undef $sub_watch;\n        ok(!defined($sub_watch),\n           'undef: released subclassed watch handle');\n    }\n\n    SKIP: {\n        skip 'no connection to ZooKeeper', 1 unless\n            (defined($path) and $path eq $node_path);\n\n        my $ret = $sub_zkh->delete($node_path);\n        ok($ret,\n           'delete(): deleted node with subclassed handle');\n    }\n\n    my $ret = $sub_zkh->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed subclassed handle');\n\n    $ret = $sub_zkh->DESTROY();\n    ok(!$ret,\n       'DESTROY(): no action on destroyed subclassed handle');\n\n    undef $sub_zkh;\n    ok(!defined($sub_zkh),\n       'undef: released subclassed handle');\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/50_access.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 40;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\nmy($username, $password, $digest) = zk_acl_test_setup();\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    my $path = $zkh->create($node_path, 'foo',\n                            'acl' => ZOO_OPEN_ACL_UNSAFE) if (defined($zkh));\n\n    skip 'no connection to ZooKeeper', 36 unless\n        (defined($path) and $path eq $node_path);\n\n\n    ## _zk_acl_constant()\n\n    my $no_read_acl = ZOO_OPEN_ACL_UNSAFE;\n    ok((ref($no_read_acl) eq 'ARRAY' and\n        @{$no_read_acl} == 1 and\n        ref($no_read_acl->[0]) eq 'HASH' and\n        keys(%{$no_read_acl->[0]}) == 3 and\n        $no_read_acl->[0]->{'perms'} == ZOO_PERM_ALL),\n       '_zk_acl_constant(): returned default ACL');\n\n    my $zoo_read_acl_unsafe = ZOO_READ_ACL_UNSAFE;\n    ok((ref($zoo_read_acl_unsafe) eq 'ARRAY' and\n        @{$zoo_read_acl_unsafe} == 1 and\n        ref($zoo_read_acl_unsafe->[0]) eq 'HASH' and\n        keys(%{$zoo_read_acl_unsafe->[0]}) == 3 and\n        $zoo_read_acl_unsafe->[0]->{'perms'} == ZOO_PERM_READ),\n       '_zk_acl_constant(): returned good ACL');\n\n    my $zoo_creator_all_acl = ZOO_CREATOR_ALL_ACL;\n    ok((ref($zoo_creator_all_acl) eq 'ARRAY' and\n        @{$zoo_creator_all_acl} == 1 and\n        ref($zoo_creator_all_acl->[0]) eq 'HASH' and\n        keys(%{$zoo_creator_all_acl->[0]}) == 3 and\n        $zoo_creator_all_acl->[0]->{'perms'} == ZOO_PERM_ALL),\n       '_zk_acl_constant(): returned good ACL');\n\n    $no_read_acl->[0]->{'perms'} &= ~ZOO_PERM_READ;\n    is($no_read_acl->[0]->{'perms'}, ((ZOO_PERM_ALL) & ~ZOO_PERM_READ),\n       'assign: altered default ACL');\n\n    is(ZOO_OPEN_ACL_UNSAFE->[0]->{'perms'}, ZOO_PERM_ALL,\n       '_zk_acl_constant(): returned unaltered default ACL');\n\n    my $copy_no_read_acl = $no_read_acl;\n    is_deeply($copy_no_read_acl, $no_read_acl,\n              'assign: copied default ACL');\n\n    undef $no_read_acl;\n    ok(!defined($no_read_acl),\n       'undef: released original default ACL');\n\n    is($copy_no_read_acl->[0]->{'perms'}, ((ZOO_PERM_ALL) & ~ZOO_PERM_READ),\n       'undef: no change to copied default ACL');\n\n    $no_read_acl = $copy_no_read_acl;\n    is_deeply($no_read_acl, $copy_no_read_acl,\n              'assign: re-copied default ACL');\n\n\n    ## create()\n\n    my $acl_node_path = \"$node_path/a1\";\n\n    $path = $zkh->create($acl_node_path, 'foo', 'acl' => $no_read_acl);\n    is($path, $acl_node_path,\n       'create(): created node with no-read ACL');\n\n    my $node = $zkh->get($acl_node_path);\n\n    my $skip_acl;\n    if (defined($node) and $node eq 'foo') {\n        $skip_acl = 1;\n    }\n    elsif(!defined($node) and $zkh->get_error() == ZNOAUTH) {\n        $skip_acl = 0;\n    }\n    else {\n        $skip_acl = -1;\n        diag(sprintf('unable to get node with no-read ACL %s: %d, %s',\n                     $acl_node_path, $zkh->get_error(), $!));\n    }\n\n    my $ret = $zkh->delete($acl_node_path);\n    diag(sprintf('unable to delete node with no-read ACL %s: %d, %s',\n                 $acl_node_path, $zkh->get_error(), $!)) unless ($ret);\n\n    my $digest_acl = [\n        {\n            'perms'  => ZOO_PERM_READ,\n            'scheme' => 'world',\n            'id'     => 'anyone'\n        },\n        {\n            'perms'  => (ZOO_PERM_WRITE | ZOO_PERM_ADMIN),\n            'scheme' => 'digest',\n            'id'     => \"$username:$digest\"\n        }\n    ];\n\n    $path = $zkh->create($acl_node_path, 'foo', 'acl' => $digest_acl);\n    is($path, $acl_node_path,\n       'create(): created node with digest auth ACL');\n\n    SKIP: {\n        skip 'ZooKeeper skipping ACLs', 1 unless (!$skip_acl);\n\n        my $acl_node_path = \"$node_path/a2\";\n\n        my $path = $zkh->create($acl_node_path, 'foo', 'acl' => [\n            {\n                'perms'  => ZOO_PERM_WRITE,\n                'scheme' => 'foo',\n                'id'     => 'bar'\n            }\n        ]);\n        ok((!defined($path) and $zkh->get_error() == ZINVALIDACL and $! eq ''),\n           'create(): undef when attempting to create node with invalid ACL');\n    }\n\n\n    ## get_acl()\n\n    my @acl = ('abc');\n    @acl = $zkh->get_acl($node_path . '/NONE');\n    ok((@acl == 0 and $zkh->get_error() == ZNONODE and $! eq ''),\n       'get_acl(): empty list returned for non-extant node');\n\n    $num_acl_entries = $zkh->get_acl($node_path . '/NONE');\n    ok((!defined($num_acl_entries) and $zkh->get_error() == ZNONODE and\n        $! eq ''),\n       'get_acl(): undef returned for non-extant node');\n\n    @acl = ('abc');\n    @acl = $zkh->get_acl($acl_node_path);\n    is_deeply(\\@acl, $digest_acl,\n              'get_acl(): retrieved digest ACL');\n\n    my $stat = $zkh->stat();\n\n    @acl = ('abc');\n    @acl = $zkh->get_acl($node_path, 'stat' => $stat);\n    is_deeply(\\@acl, ZOO_OPEN_ACL_UNSAFE,\n              'get_acl(): retrieved ACL');\n\n    is($stat->{'data_len'}, 3,\n       'get_acl(): retrieved ACL with stat handle');\n\n    SKIP: {\n        skip 'ZooKeeper not skipping ACLs', 3 unless ($skip_acl > 0);\n\n        my $acl_node_path = \"$node_path/a2\";\n\n        my $path = $zkh->create($acl_node_path, 'foo', 'acl' => []);\n        is($path, $acl_node_path,\n           'create(): created node with empty ACL');\n\n        my @acl = ('abc');\n        @acl = $zkh->get_acl($acl_node_path);\n        ok((@acl == 0 and $zkh->get_error() == ZOK),\n           'get_acl(): retrieved empty ACL');\n\n        my $num_acl_entries = $zkh->get_acl($acl_node_path);\n        ok((defined($num_acl_entries) and $num_acl_entries == 0),\n           'get_acl(): retrieved zero count of ACL entries');\n\n        my $ret = $zkh->delete($acl_node_path);\n        diag(sprintf('unable to delete node with empty ACL %s: %d, %s',\n                     $acl_node_path, $zkh->get_error(), $!)) unless ($ret);\n    }\n\n\n    ## set_acl()\n\n    SKIP: {\n        skip 'ZooKeeper skipping ACLs', 2 unless (!$skip_acl);\n\n        my $ret = $zkh->set_acl($acl_node_path, [\n            {\n                'perms'  => ZOO_PERM_CREATE,\n                'scheme' => 'foo',\n                'id'     => 'bar'\n            }\n        ]);\n        ok((!$ret and $zkh->get_error() == ZINVALIDACL and $! eq ''),\n           'set_acl(): invalid ACL');\n\n        push @{$digest_acl}, {\n            'perms'  => (ZOO_PERM_CREATE | ZOO_PERM_DELETE),\n            'scheme' => 'ip',\n            'id'     => '0.0.0.0'\n        };\n\n        $ret = $zkh->set_acl($acl_node_path, $digest_acl);\n        ok((!$ret and $zkh->get_error() == ZNOAUTH and $! eq ''),\n           'set_acl(): ACL unchanged if no auth');\n    }\n\n\n    ## add_auth(), set_acl()\n\n    $ret = $zkh->add_auth('digest', '');\n    ok($ret,\n       'add_auth(): empty digest cert');\n\n    SKIP: {\n        skip 'ZooKeeper skipping ACLs', 1 unless (!$skip_acl);\n\n        my $ret = $zkh->set($acl_node_path, 'foo');\n        ok((!$ret and $zkh->get_error() == ZNOAUTH and $! eq ''),\n           'set(): node value unchanged if no auth');\n    }\n\n    $ret = $zkh->add_auth('digest', \"$username:$password\");\n    ok($ret,\n       'add_auth(): valid digest cert');\n\n    SKIP: {\n        skip 'ZooKeeper skipping ACLs', 13 unless (!$skip_acl);\n\n        my $ret = $zkh->set($acl_node_path, 'baz');\n        ok($ret,\n           'set(): set node value with auth');\n\n        my $node = $zkh->get($acl_node_path);\n        is($node, 'baz',\n           'get(): retrieved node value with auth');\n\n        $ret = $zkh->set_acl($acl_node_path, $digest_acl);\n        ok($ret,\n           'set_acl(): set digest ACL with auth');\n\n        my $stat = $zkh->stat();\n\n        my @acl = ('abc');\n        @acl = $zkh->get_acl($acl_node_path, 'stat' => $stat);\n        is_deeply(\\@acl, $digest_acl,\n                  'get_acl(): retrieved digest ACL with auth');\n\n        is($stat->{'data_len'}, 3,\n           'get_acl(): retrieved digest ACL with stat handle and auth');\n\n        SKIP: {\n            skip 'invalid node data', 2 unless ($stat->{'version'} == 1);\n\n            my $ret = $zkh->set_acl($acl_node_path, $digest_acl,\n                                    'version' => $stat->{'version'});\n            ok($ret,\n               'set_acl(): set digest ACL with matching version with auth');\n\n            $ret = $zkh->set_acl($acl_node_path, $digest_acl,\n                                 'version' => $stat->{'version'});\n            ok((!$ret and $zkh->get_error() == ZBADVERSION and $! eq ''),\n               'set_acl(): ACL unchanged if non-matching version');\n        }\n\n        my $child_node_path = \"$acl_node_path/c1\";\n\n        my $path = $zkh->create($child_node_path, 'foo',\n                                'acl' => ZOO_OPEN_ACL_UNSAFE);\n        ok((!defined($path) and $zkh->get_error() == ZNOAUTH and $! eq ''),\n           'create(): undef when attempting to create node if no auth');\n\n        $digest_acl->[1]->{'perms'} |= ZOO_PERM_CREATE;\n        $digest_acl->[2]->{'perms'} &= ~ZOO_PERM_CREATE;\n\n        $ret = $zkh->set_acl($acl_node_path, $digest_acl);\n        ok($ret,\n           'set_acl(): set changed digest ACL with auth');\n\n        $path = $zkh->create($child_node_path, 'foo',\n                             'acl' => ZOO_OPEN_ACL_UNSAFE);\n        is($path, $child_node_path,\n           'create(): created node with auth');\n\n        $ret = $zkh->delete($child_node_path);\n        ok((!$ret and $zkh->get_error() == ZNOAUTH and $! eq ''),\n           'delete(): no deletion of node if no auth');\n\n        $digest_acl->[1]->{'perms'} |= ZOO_PERM_DELETE;\n        pop @{$digest_acl};\n\n        $ret = $zkh->set_acl($acl_node_path, $digest_acl);\n        ok($ret,\n           'set_acl(): set reduced digest ACL with auth');\n\n        $ret = $zkh->delete($child_node_path);\n        ok($ret,\n           'delete(): deleted node with auth');\n    }\n\n\n    ## cleanup\n\n    $ret = $zkh->delete($acl_node_path);\n    diag(sprintf('unable to delete node with digest auth ACL %s: %d, %s',\n                 $acl_node_path, $zkh->get_error(), $!)) unless ($ret);\n\n    $ret = $zkh->delete($node_path);\n    diag(sprintf('unable to delete node %s: %d, %s',\n                 $node_path, $zkh->get_error(), $!)) unless ($ret);\n}\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    my $ret = $zkh->exists($root_path) if (defined($zkh));\n\n    skip 'no connection to ZooKeeper', 1 unless\n        (defined($ret) and $ret);\n\n\n    ## add_auth()\n\n    $ret = $zkh->add_auth('foo', 'bar');\n    my $err = $zkh->get_error();\n    ok((!$ret and\n        ($err == ZAUTHFAILED or\n         $err == ZCONNECTIONLOSS or\n         $err == ZSESSIONEXPIRED)\n        and $! eq ''),\n       'set_acl(): invalid scheme');\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/60_watch.t",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nuse File::Spec;\nuse Test::More tests => 30;\n\nBEGIN { use_ok('Net::ZooKeeper', qw(:all)) };\n\n\nmy $test_dir;\n(undef, $test_dir, undef) = File::Spec->splitpath($0);\nrequire File::Spec->catfile($test_dir, 'util.pl');\n\nmy($hosts, $root_path, $node_path) = zk_test_setup(0);\n\n\nSKIP: {\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    my $path = $zkh->create($node_path, 'foo',\n                            'acl' => ZOO_OPEN_ACL_UNSAFE) if (defined($zkh));\n\n    skip 'no connection to ZooKeeper', 20 unless\n        (defined($path) and $path eq $node_path);\n\n\n    ## exists()\n\n    $zkh->{'watch_timeout'} = 100;\n\n    my $watch = $zkh->watch();\n\n    my $ret = $zkh->exists($node_path, 'watch' => $watch);\n    ok($ret,\n       'exists(): checked node existence with watch handle');\n\n    $ret = $watch->wait();\n    ok(!$ret,\n       'wait(): watch after checking node existence timed out');\n\n    $ret = $zkh->exists($node_path, 'watch' => $watch);\n    ok($ret,\n       'exists(): checked node existence with renewed watch handle');\n\n    $ret = $watch->wait();\n    ok(!$ret,\n       'wait(): watch after checking node existence timed out with ' .\n       'renewed watch handle');\n\n    undef $watch;\n    ok(!defined($watch),\n       'undef: released watch handle');\n\n    my $pending_watches = $zkh->{'pending_watches'};\n    is($pending_watches, 2,\n       '_zk_release_watches(): report pending watches');\n\n\n    ## get_children()\n\n    $watch = $zkh->watch('timeout' => 50);\n\n    my $num_children = $zkh->get_children($node_path, 'watch' => $watch);\n    ok((defined($num_children) and $num_children == 0),\n       'get_children(): retrieved zero count of child nodes with ' .\n       'watch handle');\n\n    $ret = $watch->wait();\n    ok(!$ret,\n       'wait(): watch after retrieving child nodes timed out with ' .\n       'watch handle');\n\n    $watch->{'timeout'} = 100;\n\n    my @child_paths = $zkh->get_children($node_path, 'watch' => $watch);\n    ok((@child_paths == 0),\n       'get_children(): retrieved empty list of child nodes with ' .\n       'renewed watch handle');\n\n    $ret = $watch->wait();\n    ok(!$ret,\n       'wait(): watch after retrieving child nodes timed out with ' .\n       'renewed watch handle');\n\n    $pending_watches = $zkh->{'pending_watches'};\n    is($pending_watches, 4,\n       '_zk_release_watches(): report pending watches');\n\n\n    ## get()\n\n    $watch = $zkh->watch();\n\n    my $node = $zkh->get($node_path, 'watch' => $watch);\n    is($node, 'foo',\n       'get(): retrieved node value with watch handle');\n\n    $ret = $watch->wait('timeout' => 0);\n    ok(!$ret,\n       'wait(): watch after retrieving node value timed out with ' .\n       'watch handle');\n\n    $node = $zkh->get($node_path, 'watch' => $watch);\n    is($node, 'foo',\n       'get(): retrieved node value with renewed watch handle');\n\n    $ret = $watch->wait();\n    ok(!$ret,\n       'wait(): watch after retrieving node value timed out with ' .\n       'renewed watch handle');\n\n    $pending_watches = $zkh->{'pending_watches'};\n    is($pending_watches, 6,\n       '_zk_release_watches(): all watches pending');\n\n\n    ## _zk_release_watches()\n\n    $ret = $zkh->DESTROY();\n    ok($ret,\n       'DESTROY(): destroyed handle with pending watches');\n\n    my $event = $watch->{'event'};\n    is($event, 0,\n       '_zk_release_watches(): watch not destroyed when tied to watch handle');\n\n    $zkh = Net::ZooKeeper->new($hosts);\n\n    SKIP: {\n        my $ret = $zkh->exists($node_path, 'watch' => $watch);\n\n        skip 'no connection to ZooKeeper', 2 unless\n            (defined($ret) and $ret);\n\n        ok($ret,\n           'exists(): checked node existence with renewed watch handle ' .\n           'from prior connection');\n\n        $ret = $watch->wait();\n        ok(!$ret,\n           'wait(): watch after checking node existence timed out with ' .\n           'renewed watch handle from prior connection');\n\n\n    }\n}\n\nmy $pid = fork();\n\nSKIP: {\n    skip 'unable to fork', 4 unless (defined($pid));\n\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    my $ret = $zkh->exists($node_path) if (defined($zkh));\n\n    if ($pid == 0) {\n        ## child process\n\n        my $code = 0;\n\n        if (defined($ret) and $ret) {\n            sleep(1);\n\n            my $ret = $zkh->set($node_path, 'foo');\n\n            diag(sprintf('set(): failed in child process: %d, %s',\n                         $zkh->get_error(), $!)) unless ($ret);\n\n            $code = !$ret;\n\n            sleep(1);\n\n            my $path = $zkh->create(\"$node_path/c\", 'foo',\n                                    'acl' => ZOO_OPEN_ACL_UNSAFE);\n\n            diag(sprintf('create(): failed in child process: %d, %s',\n                         $zkh->get_error(), $!)) unless\n                (defined($path) and $path eq \"$node_path/c\");\n\n            $code &= !$ret;\n\n            sleep(1);\n\n            $ret = $zkh->delete(\"$node_path/c\");\n\n            diag(sprintf('delete(): failed in child process: %d, %s',\n                         $zkh->get_error(), $!)) unless ($ret);\n\n            $code &= !$ret;\n\n            sleep(1);\n\n            $ret = $zkh->set($node_path, 'foo');\n\n            diag(sprintf('set(): failed in child process: %d, %s',\n                         $zkh->get_error(), $!)) unless ($ret);\n\n            $code &= !$ret;\n        }\n\n        exit($code);\n    }\n    else {\n        ## parent process\n\n        SKIP: {\n            skip 'no connection to ZooKeeper', 9 unless\n                (defined($ret) and $ret);\n\n            my $watch = $zkh->watch('timeout' => 5000);\n\n\n            ## wait()\n\n            my $ret = $zkh->exists($node_path, 'watch' => $watch);\n            ok($ret,\n               'exists(): checked node existence with watch handle ' .\n               'in parent');\n\n            $ret = $watch->wait();\n            ok(($ret and $watch->{'event'} == ZOO_CHANGED_EVENT and\n                $watch->{'state'} == ZOO_CONNECTED_STATE),\n               'wait(): waited for event after checking node existence');\n\n            my $num_children = $zkh->get_children($node_path,\n                                                 'watch' => $watch);\n            ok((defined($num_children) and $num_children == 0),\n               'get_children(): retrieved zero count of child nodes with ' .\n               'watch handle in parent');\n\n            $ret = $watch->wait();\n            ok(($ret and $watch->{'event'} == ZOO_CHILD_EVENT and\n                $watch->{'state'} == ZOO_CONNECTED_STATE),\n               'wait(): waited for create child event after ' .\n               'retrieving child nodes');\n\n            my @child_paths = $zkh->get_children($node_path,\n                                                'watch' => $watch);\n            ok((@child_paths == 1 and $child_paths[0] eq 'c'),\n               'get_children(): retrieved list of child nodes with ' .\n               'watch handle in parent');\n\n            $ret = $watch->wait();\n            ok(($ret and $watch->{'event'} == ZOO_CHILD_EVENT and\n                $watch->{'state'} == ZOO_CONNECTED_STATE),\n               'wait(): waited for delete child event after ' .\n               'retrieving child nodes');\n\n            my $node = $zkh->get($node_path, 'watch' => $watch);\n            is($node, 'foo',\n               'get(): retrieved node value with watch handle in parent');\n\n            $ret = $watch->wait();\n            ok(($ret and $watch->{'event'} == ZOO_CHANGED_EVENT and\n                $watch->{'state'} == ZOO_CONNECTED_STATE),\n               'wait(): waited for event after retrieving node value');\n\n            undef $watch;\n\n            my $pending_watches = $zkh->{'pending_watches'};\n            is($pending_watches, 0,\n               '_zk_release_watches(): no watches pending');\n        }\n\n        my $reap = waitpid($pid, 0);\n\n        diag(sprintf('child process failed: exit %d, signal %d%s',\n                     ($? >> 8), ($? & 127),\n                     (($? & 128) ? ', core dump' : ''))) if\n            ($reap == $pid and $? != 0);\n    }\n}\n\n\n## cleanup\n\n{\n    my $zkh = Net::ZooKeeper->new($hosts);\n\n    my $ret = $zkh->exists($node_path) if (defined($zkh));\n\n    if (defined($ret) and $ret) {\n        $ret = $zkh->delete($node_path);\n        diag(sprintf('unable to delete node %s: %d, %s',\n                     $node_path, $zkh->get_error(), $!)) unless ($ret);\n    }\n}\n\n"
  },
  {
    "path": "src/contrib/zkperl/t/util.pl",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nsub zk_test_setup\n{\n    my $verbose = shift;\n\n    $SIG{'PIPE'} = 'IGNORE';\n\n    my $hosts = $ENV{'ZK_TEST_HOSTS'};\n    unless (defined($hosts) and $hosts =~ /\\S/) {\n        $hosts = 'localhost:0';\n        diag('no ZooKeeper hostnames specified in ZK_TEST_HOSTS env var, ' .\n             \"using $hosts\") if ($verbose);\n    }\n\n    my $root_path = $ENV{'ZK_TEST_PATH'};\n    if (defined($root_path) and $root_path =~ /^\\//) {\n        $root_path =~ s/\\/+/\\//g;\n        $root_path =~ s/\\/$//;\n    }\n    else {\n        $root_path = '/';\n        diag('no ZooKeeper path specified in ZK_TEST_PATH env var, ' .\n             'using root path') if ($verbose);\n    }\n\n    my $node_path = $root_path . (($root_path =~ /\\/$/) ? '' : '/') .\n        '_net_zookeeper_test';\n\n    return ($hosts, $root_path, $node_path);\n}\n\nsub zk_acl_test_setup\n{\n    my $username = '_net_zookeeper_test';\n\n    my $password = 'test';\n\n    ## digest is Base64-encoded SHA1 digest of username:password\n    my $digest = '2qi7Erp2cXYLGcQbXADiwUFaOGo=';\n\n    return ($username, $password, $digest);\n}\n\n1;\n    \n"
  },
  {
    "path": "src/contrib/zkperl/typemap",
    "content": "# Net::ZooKeeper - Perl extension for Apache ZooKeeper\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nTYPEMAP\nNet::ZooKeeper\tT_ZK_HANDLE\nNet::ZooKeeper::Stat\tT_ZK_HANDLE\nNet::ZooKeeper::Watch\tT_ZK_HANDLE\n\nINPUT\nT_ZK_HANDLE\n\tif (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV &&\n\t    sv_derived_from($arg, \\\"${ntype}\\\")) {\n\t    $var = (HV*) SvRV($arg);\n\t}\n\telse {\n\t    Perl_croak(aTHX_\n                       \\\"$var is not a hash reference of type ${ntype}\\\");\n\t}\n\nOUTPUT\nT_ZK_HANDLE\n\tNOT_IMPLEMENTED\n\n"
  },
  {
    "path": "src/contrib/zkpython/README",
    "content": "Early version of ZooKeeper bindings for Python. All functions are imported as methods into the zookeeper module.\n\nPlease do not rely on APIs staying constant in the short term. The handling of exceptions and failure modes is one area that is subject to change. \n\nDEPENDENCIES:\n-------------\n\nThis has only been tested against SVN (i.e. 3.2.0 in development) but should work against 3.1.1. \n\nYou will need the Python development headers installed to build the module - on many package-management systems, these can be found in python-devel.\n\nPython >= 2.6 is required. We have tested against 2.6. We have not tested against 3.x. \n\nBUILD AND INSTALL:\n-------------------\n\nTo install, make sure that the C client has been built and that the libraries are installed in /usr/local/lib (or change this directory in setup.py). Then run:\n\nant install\n\nfrom zookeeper/src/contrib/zkpython/.\n\nTo test, run ant test from the same directory. \n\nYou can compile the module without installing by running\n\nant compile\n\nIn order to use the module, zookeeper.so must be in your PYTHONPATH or in one of the directories referenced by sys.path. Running ant install should make sure that this is the case, but if you only run ant compile you probably need to add build/contrib/zkpython/* to PYTHONPATH to find the module. The C client libraries must be in a system library path, or LD_LIBRARY_PATH or DYLD_LIBRARY_PATH (Mac OS) for the module to work correctly, otherwise you will see a library not found error when trying to import the module. \n\nNAMING CONVENTIONS:\n--------------------\n\nAll methods that in the C library are zoo_fn_name have been implemented as zookeeper.fn_name. The exception is any function that has a watch function argument is named without the 'w' prefix (for example, zoo_wexists becomes zookeeper.exists). The variants of these functions without the watch argument (i.e. zoo_exists) have not been implemented on the understanding that they are superseded by the zoo_w* API. \n\nEnums and integer constants that begin ZOO_int_name are named as zookeeper.int_name.\n\nPARAMETER CHANGES:\n------------------\n\nZookeeper handles are represented as integers to avoid marshalling the entire structure for every call. Therefore they are opaque from Python. \n\nAny parameter that is used to provide arguments to callback methods is not exposed in the API. Python provides better mechanisms for providing a closure to be called in the future.\n\nEvery callback gets passed the handle of the ZooKeeper instance used to register the callback.\n\nDATA TYPES:\n-----------\n\nACL_vectors are lists of dictionaries. Stat structures are dictionaries. String_vectors are lists of strings.\n\nEXCEPTIONS AND ERROR HANDLING:\n------------------------------\n\nCurrently synchronous calls indicate failure by throwing an exception (note that this includes the synchronous calls to set up asynchronous completion callbacks!). Success is returned as an integer. \n\nCallbacks signify failure by having the integer response code passed in. \n\nWHAT'S NEW IN 0.4:\n------------------\n\nMore test coverage. \n\nBetter reference counting, fixing at least two serious bugs.\n\nOut-of-range zhandles are now checked, fixing a potential security hole.\n\nDocstrings! Editing and cleanup required, but most of the text is there.\n\nzookeeper.set_watcher is now implemented correctly.\n\nzookeeper.client_id is now implemented correctly. zookeeper.init now respects the client_id parameter.\n\nget_context and set_context have been removed from the API. The context mechanism is used by PyZK to store the callables that are dispatched by C-side watchers. Messing with this from Python-side causes bugs very quickly. You should wrap all desired context up in a callable and then use zookeeper.set_watcher to attach it to the global watcher. \n\nMany methods now have optional parameters (usually if you can specify a watch, it's optional). The only time where genuinely optional parameters are still mandatory is when a required parameters comes after it. Currently we still respect the ZK C client parameter ordering. For example, you can simply connect with zookeeper.init(\"host:port\") and ignore the other three parameters.\n\n\nWHAT'S NEW IN 0.3:\n------------------\n\nSome tests in zkpython/test. More to follow!\n\nA variety of bugfixes.\n\nChanged the way methods return results - all responses are integers now, for the client to convert to a string if it needs.\n\nWHAT'S NEW IN 0.2:\n------------------\n\nThe asynchronous API is now implemented (see zookeeper.a*).\n\nMost enums defined in zookeeper.h are now added as constants to the module.\n\n_set2 and a few other edge API calls have been implemented. The module is now nearly 100% feature complete!\n\nA reference count error was tracked down and killed. More probably lurk in there!\n\nWHAT'S NOT DONE / KNOWN ISSUES / FUTURE WORK:\n---------------------------------------------\n\n1. There may well be more memory leaks / reference count issues; however I am more confident that common paths are relatively safe. \n2. There probably needs to be a more Pythonic Python-side wrapper for these functions (e.g. a zookeeper object, the ability to iterate through a tree of zk nodes)\n3. Docstrings need a cleanup.\n4. The way exceptions and error codes are returned needs looking at. Currently synchronous calls throw exceptions on everything but ZOK return, but asynchronous completions are simply passed the error code. Async. functions should never throw an exception on the C-side as they are practically impossible to catch. For the sync. functions, exceptions seem more reasonable, but some cases are certainly not exceptional. \n\nBug reports / comments very welcome!\n\nHenry Robinson henry@cloudera.com\n"
  },
  {
    "path": "src/contrib/zkpython/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zkpython\" default=\"install\">\n  <import file=\"../build-contrib.xml\"/>\n  <property name=\"python.src.dir\" value=\"src/python\"/>\n  <property name=\"test.build.dir\" value=\"build/test/\" />\n  <property name=\"test.src.dir\" value=\"src/test\"/>\n  <property name=\"test.log.dir\" value=\"${build.test}/logs\" />\n  <property name=\"test.output\" value=\"no\" />\n  <property name=\"test.timeout\" value=\"900000\" />\n  <property name=\"package.buildroot\" value=\"/tmp/zkpython_build_${user.name}\"/>\n  <property name=\"package.build.dir\" value=\"/tmp/zkpython_build_${user.name}/BUILD\"/>\n  <property name=\"package.release\" value=\"1\"/>\n  <property name=\"package.prefix\" value=\"/usr\"/>\n\n  <target name=\"test\"\n          depends=\"compile,test-init,test-category,test-start,python-test,test-stop\" />\n\t\n    <target name=\"test-init\" depends=\"checkMainCompiled\">\n        <delete dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n    </target>\n\n    <target name=\"test-start\">\n      <exec executable=\"${test.src.dir}/zkServer.sh\" failonerror=\"true\">\n        <arg value=\"startClean\"/>\n      </exec>\n    </target>\n\n    <target name=\"test-stop\">\n      <exec executable=\"${test.src.dir}/zkServer.sh\" failonerror=\"true\">\n        <arg value=\"stop\"/>\n      </exec>\n    </target>\n\n    <target name=\"test-category\">\n         <property name=\"test.category\" value=\"\"/>\n    </target>\n\n    <target name=\"python-test\">\n      <exec executable=\"${test.src.dir}/run_tests.sh\" failonerror=\"true\">\n        <arg value=\"${test.src.dir}\"/>\n        <arg value=\"${test.log.dir}\"/>\n      </exec>\n    </target>\n\n    <target name=\"compile\" depends=\"ivy-retrieve\">\n      <exec executable=\"python\" failonerror=\"true\">\n        <arg value=\"${python.src.dir}/setup.py\"/>\n        <arg value=\"build\"/>\n        <arg value=\"--build-base=${build.dir}\"/>\n      </exec>\n    </target>\n\n    <target name=\"install\" depends=\"compile\">\n      <exec executable=\"python\" failonerror=\"true\">\n        <arg value=\"${python.src.dir}/setup.py\"/>\n        <arg value=\"build\"/>\n        <arg value=\"--build-base=${build.dir}\"/>\n        <arg value=\"install\"/>\n      </exec>\n    </target>\n\n    <target name=\"package\" unless=\"skip.contrib\">\n      <echo message=\"contrib: ${name}\"/>\n\n      <mkdir dir=\"${build.dir}\"/>\n      <copy todir=\"${build.dir}\">\n        <fileset dir=\"${basedir}\">\n          <exclude name=\"**/VERSION\"/>\n        </fileset>\n      </copy>\n      <exec executable=\"echo\" output=\"${build.dir}/VERSION\">\n        <arg line=\"${version}\" />\n      </exec>\n\n      <mkdir dir=\"${dist.dir}/contrib/${name}\"/>\n      <copy todir=\"${dist.dir}/contrib/${name}\">\n        <fileset dir=\"${build.dir}\">\n          <exclude name=\"**/temp*\"/>\n        </fileset>\n      </copy>\n    </target>\n\n    <target name=\"bin-package\" depends=\"compile, package\" unless=\"skip.contrib\">\n    </target>\n\n    <target name=\"tar-bin\" depends=\"init, compile, bin-package\" unless=\"skip.contrib\">\n      <exec executable=\"python\" failonerror=\"true\" dir=\"${build.dir}\">\n        <arg value=\"${python.src.dir}/setup.py\"/>\n        <arg value=\"build\"/>\n        <arg value=\"--build-base=${build.dir}\"/>\n        <arg value=\"bdist_dumb\"/>\n      </exec>\n    </target>\n\n    <target name=\"rpm\" depends=\"tar-bin\" unless=\"skip.contrib\">\n      <mkdir dir=\"${package.buildroot}/BUILD\" />\n      <mkdir dir=\"${package.buildroot}/RPMS\" />\n      <mkdir dir=\"${package.buildroot}/SRPMS\" />\n      <mkdir dir=\"${package.buildroot}/SOURCES\" />\n      <mkdir dir=\"${package.buildroot}/SPECS\" />\n      <copy todir=\"${package.buildroot}/SOURCES\">\n        <fileset dir=\"${build.dir}/dist\">\n          <include name=\"*.tar.gz\" />\n        </fileset>\n      </copy>\n      <path id=\"python.lib\">\n        <fileset dir=\"${package.buildroot}/SOURCES\">\n          <include name=\"*.tar.gz\" />\n        </fileset>\n      </path>\n      <property name=\"python.lib\" refid=\"python.lib\" />\n      <copy file=\"${src.dir}/../packages/rpm/spec/${name}.spec\" todir=\"${package.buildroot}/SPECS\">\n        <filterchain>\n          <replacetokens>\n            <token key=\"final.name\" value=\"${name}\" />\n            <token key=\"version\" value=\"${rpm.version}\" />\n            <token key=\"package.release\" value=\"${package.release}\" />\n            <token key=\"package.build.dir\" value=\"${package.build.dir}\" />\n            <token key=\"package.prefix\" value=\"${package.prefix}\" />\n            <token key=\"python.lib\" value=\"${python.lib}\" />\n          </replacetokens>\n        </filterchain>\n      </copy>\n\n      <rpm specFile=\"${name}.spec\" command=\"-ba --buildroot=${package.buildroot}/BUILD\" topDir=\"${package.buildroot}\" cleanBuildDir=\"true\" failOnError=\"true\" />\n      <copy todir=\"${build.dir}/\" flatten=\"true\">\n        <fileset dir=\"${package.buildroot}/RPMS\">\n          <include name=\"**/*.rpm\" />\n        </fileset>\n      </copy>\n      <delete dir=\"${package.buildroot}\" quiet=\"true\" verbose=\"false\" />\n    </target>\n\n    <target name=\"deb\" depends=\"tar-bin\" unless=\"skip.contrib\">\n      <mkdir dir=\"${package.buildroot}\" />\n      <mkdir dir=\"${package.buildroot}/BUILD\" />\n      <mkdir dir=\"${package.buildroot}/SPECS\" />\n      <copy todir=\"${package.buildroot}/SOURCES\">\n        <fileset dir=\"${build.dir}/dist\">\n          <include name=\"*.tar.gz\" />\n        </fileset>\n      </copy>\n      <path id=\"python.lib\">\n        <fileset dir=\"${package.buildroot}/SOURCES\">\n          <include name=\"*.tar.gz\" />\n        </fileset>\n      </path>\n      <property name=\"python.lib\" refid=\"python.lib\" />\n      <copy todir=\"${package.build.dir}/zkpython.control\">\n        <fileset dir=\"${src.dir}/../packages/deb/zkpython.control\">\n          <exclude name=\"control\" />\n        </fileset>\n      </copy>\n      <copy file=\"${src.dir}/../packages/deb/zkpython.control/control\" todir=\"${package.build.dir}/zkpython.control\">\n        <filterchain>\n          <replacetokens>\n            <token key=\"final.name\" value=\"${name}\" />\n            <token key=\"version\" value=\"${version}\" />\n            <token key=\"package.release\" value=\"${package.release}\" />\n            <token key=\"package.build.dir\" value=\"${package.build.dir}\" />\n            <token key=\"package.prefix\" value=\"${package.prefix}\" />\n          </replacetokens>\n        </filterchain>\n      </copy>\n      <taskdef name=\"deb\" classname=\"org.vafer.jdeb.ant.DebAntTask\">\n        <classpath refid=\"classpath\"/>\n      </taskdef>\n      <deb destfile=\"${package.buildroot}/${name}_${version}-${package.release}_${os.arch}.deb\" control=\"${package.build.dir}/zkpython.control\">\n        <data src=\"${python.lib}\" />\n      </deb>\n      <copy todir=\"${build.dir}/\" flatten=\"true\">\n        <fileset dir=\"${package.buildroot}\">\n          <include name=\"**/${name}_*.deb\" />\n        </fileset>\n      </copy>\n      <delete dir=\"${package.buildroot}\" quiet=\"true\" verbose=\"false\"/>\n    </target>\n</project>\n\n"
  },
  {
    "path": "src/contrib/zkpython/ivy.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<ivy-module version=\"2.0\"\n            xmlns:e=\"http://ant.apache.org/ivy/extra\">\n\n  <info organisation=\"org.apache.zookeeper\"\n        module=\"${name}\" revision=\"${version}\">\n    <license name=\"Apache 2.0\"/>\n    <ivyauthor name=\"Apache ZooKeeper\" url=\"http://zookeeper.apache.org\"/>\n    <description>ZKPython</description>\n  </info>\n\n  <configurations defaultconfmapping=\"default\">\n    <conf name=\"default\"/>\n    <conf name=\"test\"/>\n    <conf name=\"jdiff\" visibility=\"private\"/>\n    <conf name=\"releaseaudit\" visibility=\"private\" description=\"Artifacts required for releaseaudit target\"/>\n  </configurations>\n\n  <dependencies>\n\n    <dependency org=\"org.vafer\" name=\"jdeb\" rev=\"0.8\">\n      <artifact name=\"jdeb\" type=\"jar\" conf=\"default\"/>\n    </dependency>\n\n  </dependencies>\n\n</ivy-module>\n"
  },
  {
    "path": "src/contrib/zkpython/src/c/pyzk_docstrings.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef PYZK_DOCSTRINGS_H\n#define PYZK_DOCSTRINGS_H\n\nconst char pyzk_acreate_doc[] = \n\"Create a node asynchronously.\\n\"\n\"\\n\"\n\"This method will create a node in ZooKeeper. A node can only be created if\\n\"\n\"it does not already exists. The Create Flags affect the creation of nodes.\\n\"\n\"If EPHEMERAL flag is set, the node will automatically get removed if the\\n\"\n\"client session goes away. If the SEQUENCE flag is set, a unique\\n\"\n\"monotonically increasing sequence number is appended to the path name.\\n\"\n\"\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: The name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" value: The data to be stored in the node.\\n\"\n\" acl: The initial ACL of the node. If None, the ACL of the parent will be\\n\"\n\"   used.\\n\"\n\"\\n\"\n\" (Subsequent parameters are optional)\\n\"\n\" flags: this parameter can be set to 0 for normal create or an OR\\n\"\n\"   of the Create Flags\\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the parent node does not exist.\\n\"\n\"NODEEXISTS the node already exists\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"NOCHILDRENFOREPHEMERALS cannot create children of ephemeral nodes.\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\"Returns OK on success or throws of the following errcodes on failure:\\n\"\n\"EXCEPTIONS:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_client_id_doc[] = \n\"Return the client session id, only valid if the connections\\n\"\n\" is currently connected (ie. last watcher state is CONNECTED_STATE)\";\n\nstatic const char pyzk_state_doc[] = \n\"Get the state of the zookeeper connection.\\n\"\n  \"The return value will be one of the State Consts.\";\n  \nstatic const char pyzk_adelete_doc[] = \n\" Delete a node in zookeeper.\\n\"\n\"\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" version: the expected version of the node. The function will fail if the\\n\"\n\"   actual version of the node does not match the expected version.\\n\"\n\" If -1 is used the version check will not take place. \\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"NOTEMPTY children are present; node cannot be deleted.\\n\"\n\"Returns OK on success or one of the following errcodes on failure:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_aexists_doc[] = \n\" checks the existence of a node in zookeeper.\\n\"\n\"\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" watch: if not None, a watch will be set at the server to notify the \\n\"\n\"client if the node changes. The watch will be set even if the node does not \\n\"\n\"exist. This allows clients to watch for nodes to appear.\\n\"\n\"\\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\" OK operation completed successfully\\n\"\n\" NONODE the node does not exist.\\n\"\n\" NOAUTH the client does not have permission.\\n\"\n\" data the data that will be passed to the completion routine when the \\n\"\n\"function completes.\\n\"\n\" OK on success or one of the following errcodes on failure:\\n\"\n\" BADARGUMENTS - invalid input parameters\\n\"\n\" INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\" MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_aget_doc[] = \n\"Gets the data associated with a node.\\n\"\n\"\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" watcher if not None, a watch will be set at the server to notify \\n\"\n\"the client if the node changes.\\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\" OK operation completed successfully\\n\"\n\" NONODE the node does not exist.\\n\"\n\" NOAUTH the client does not have permission.\\n\"\n\" data the data that will be passed to the completion routine when \\n\"\n\"the function completes.\\n\"\n\"Returns OK on success or one of the following errcodes on failure:\\n\"\n\" BADARGUMENTS - invalid input parameters\\n\"\n\" INVALIDSTATE - zhandle state is either in SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \" MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_aset_doc[] = \n\" Sets the data associated with a node.\\n\"\n\"\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" buffer the buffer holding data to be written to the node.\\n\"\n\" buflen the number of bytes from buffer to write.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" version the expected version of the node. The function will fail if \\n\"\n\"the actual version of the node does not match the expected version. If -1 is \\n\"\n\"used the version check will not take place.\\n\"\n\"completion: If None, \\n\"\n\"the function will execute synchronously. Otherwise, the function will return \\n\"\n\"immediately and invoke the completion routine when the request completes.\\n\"\n\" completion the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\" data the data that will be passed to the completion routine when \\n\"\n\"the function completes.\\n\"\n\"Returns OK on success or one of the following errcodes on failure:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_aget_children_doc[] = \n\" Lists the children of a node.\\n\"\n\"\\n\"\n\"This function is similar to zoo_aget_children except it allows one specify \\n\"\n\"a watcher object rather than a boolean watch flag.\\n\"\n\" \\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" watcher if non-null, a watch will be set at the server to notify \\n\"\n\"the client if the node changes.\\n\"\n\"\\n\"\n\" completion the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"\\n\"\n\"Returns OK on success or one of the following errcodes on failure:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nstatic const char pyzk_async_doc[] = \n\" Flush leader channel.\\n\"\n\"\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes\\n\"\n\"separating ancestors of the node.\\n\"\n\" completion the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"\\n\"\n\"Returns OK on success or one of the following errcodes on failure:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nconst static char pyzk_aget_acl_doc[] = \n\" Gets the acl associated with a node.\\n\"\n\"\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"\\n\"\n\"Returns:\\n\"\n\" OK on success or one of the following errcodes on failure:\\n\"\n\" BADARGUMENTS - invalid input parameters\\n\"\n\" INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\" MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nconst char pyzk_aset_acl_doc[] = \n\" Sets the acl associated with a node.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" buffer: the buffer holding the acls to be written to the node.\\n\"\n\" completion: the routine to invoke when the request completes. The completion\\n\"\n\"will be triggered with one of the following codes passed in as the rc argument:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"INVALIDACL invalid ACL specified\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"\"\n\" Returns OK on success or one of the following errcodes on failure:\\n\"\n\" BADARGUMENTS - invalid input parameters\\n\"\n\" INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\" MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\";\n\nconst char pyzk_zerror_doc[] = \n\"Returns an error string corresponding to an integer error code.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" err: Error code\\n\"\n\"RETURNS:\\n\"\n  \" string corresponding to the return code\\n\";\n\nconst char pyzk_add_auth_doc[] = \n\" specify application credentials.\\n\"\n\"\\n\"\n\"The application calls this function to specify its credentials for purposes\\n\"\n\"of authentication. The server will use the security provider specified by \\n\"\n\"the scheme parameter to authenticate the client connection. If the \\n\"\n\"authentication request has failed:\\n\"\n\"- the server connection is dropped\\n\"\n\"- the watcher is called with the AUTH_FAILED_STATE value as the state \\n\"\n\"parameter.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" scheme the id of authentication scheme. Natively supported:\\n\"\n\"'digest' password-based authentication\\n\"\n\" cert: application credentials. The actual value depends on the scheme.\\n\"\n\" completion: the routine to invoke when the request completes. One of \\n\"\n\"the following result codes may be passed into the completion callback:\\n\"\n\"OK operation completed successfully\\n\"\n\"AUTHFAILED authentication failed \\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\"OK on success or one of the following errcodes on failure:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n\"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\"\n  \"SYSTEMERROR - a system error occurred\\n\";\n\nconst char pyzk_is_unrecoverable_doc[] = \n\" checks if the current zookeeper connection state can't be recovered.\\n\"\n\"\\n\"\n\" The application must close the zhandle and try to reconnect.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh the zookeeper handle (see zookeeper.init)\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n  \"True if connection is unrecoverable, otherwise False\\n\";\n\nconst char pyzk_set_debug_level_doc[] = \n\"\\brief sets the debugging level for the library \\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" logLevel: One of LOG_LEVEL_ERROR, LOG_LEVEL_WARN, LOG_LEVEL_INFO or LOG_LEVEL_DEBUG\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n  \" None\\n\";\n\nstatic const char pyzk_set_log_stream_doc[] = \n\" sets the stream to be used by the library for logging \\n\"\n\"\\n\"\n\"The zookeeper library uses stderr as its default log stream. Applications\\n\"\n\"must make sure the stream is writable. Passing in NULL resets the stream \\n\"\n  \"to its default value (stderr).\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" logStream: a writable file object\\n\"\n\"RETURNS:\\n\"\n\" None\\n\";\n\nstatic const char pyzk_deterministic_conn_order_doc[] = \n\" enable/disable quorum endpoint order randomization\\n\"\n\"\\n\"\n\"If passed a non-zero value, will make the client connect to quorum peers\\n\"\n\"in the order as specified in the zookeeper.init() call.\\n\"\n\"A zero value causes zookeeper.init() to permute the peer endpoints\\n\"\n\"which is good for more even client connection distribution among the \\n\"\n\"quorum peers.\\n\"\n\"PARAMETERS:\\n\"\n\" yesOrNo\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n  \" None\\n\";\n\nstatic const char pyzk_create_doc[] = \n\" create a node synchronously.\\n\"\n\"\\n\"\n\"This method will create a node in ZooKeeper. A node can only be created if\\n\"\n\"it does not already exists. The Create Flags affect the creation of nodes.\\n\"\n\"If the EPHEMERAL flag is set, the node will automatically get removed if the\\n\"\n\"client session goes away. If the SEQUENCE flag is set, a unique\\n\"\n\"monotonically increasing sequence number is appended to the path name.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: The name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" value: The data to be stored in the node.\\n\"\n\" acl: The initial ACL of the node. If null, the ACL of the parent will be\\n\"\n\"   used.\\n\"\n\" flags: this parameter can be set to 0 for normal create or an OR\\n\"\n\"   of the Create Flags\\n\"\n\" realpath: the real path that is created (this might be different than the\\n\"\n\"   path to create because of the SEQUENCE flag.\\n\"\n\" the maximum length of real path you would want.\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" The actual znode path that was created (may be different from path due to use of SEQUENTIAL\\n\" \n\" flag).\\n\"\n\"EXCEPTIONS:\\n\"\n\" NONODE the parent node does not exist.\\n\"\n\" NODEEXISTS the node already exists\\n\"\n\" NOAUTH the client does not have permission.\\n\"\n\" NOCHILDRENFOREPHEMERALS cannot create children of ephemeral nodes.\\n\"\n\" BADARGUMENTS - invalid input parameters\\n\"\n\" INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \" MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_delete_doc[] = \n\" delete a node in zookeeper synchronously.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" version: the expected version of the node. The function will fail if the\\n\"\n\"   actual version of the node does not match the expected version.\\n\"\n\" If -1 (the default) is used the version check will not take place. \\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\"One of the following values is returned.\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"NOTEMPTY children are present; node cannot be deleted.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_exists_doc[] = \n\" checks the existence of a node in zookeeper synchronously.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(Subsequent parameters are optional)\\n\"\n\" watch: if nonzero, a watch will be set at the server to notify the \\n\"\n\"client if the node changes. The watch will be set even if the node does not \\n\"\n\"exist. This allows clients to watch for nodes to appear.\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" the return stat value of the node.\\n\"\n\"EXCEPTIONS:\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\n\nstatic const char pyzk_get_children_doc[] =\n\" lists the children of a node synchronously.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(subsequent parameters are optional)\\n\"\n\" watcher: if non-null, a watch will be set at the server to notify \\n\"\n\"the client if the node changes.\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" A list of znode names\\n\"\n\"EXCEPTIONS:\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_set_doc[] = \n\"\\n\"\n\" sets the data associated with a node. See set2 function if\\n\"\n\"you require access to the stat information associated with the znode.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" buffer: the buffer holding data to be written to the node.\\n\"\n\"\\n\"\n\"(subsequent parameters are optional)\\n\"\n\" version: the expected version of the node. The function will fail if \\n\"\n\"the actual version of the node does not match the expected version. If -1 is \\n\"\n\"used the version check will not take place. \\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" the return code for the function call.\\n\"\n\"OK operation completed successfully\\n\"\n\"EXCEPTIONS:\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_get_acl_doc[] = \n\" gets the acl associated with a node synchronously.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" acl: the return value of acls on the path.\\n\"\n\"RETURNS:\"\n\" returns the stat of the path specified.\\n\"\n\"EXCEPTIONS:\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\n\nstatic const char pyzk_set_acl_doc[] = \n\" sets the acl associated with a node synchronously.\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" version: the expected version of the path.\\n\"\n\" acl: the acl to be set on the path. \\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\"OK operation completed successfully\\n\"\n\"EXCEPTIONS:\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"INVALIDACL invalid ACL specified\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_close_doc[] = \n\" close the zookeeper handle and free up any resources.\\n\"\n\"\\n\"\n\"After this call, the client session will no longer be valid. The function\\n\"\n\"will flush any outstanding send requests before return. As a result it may \\n\"\n\"block.\\n\"\n\"\\n\"\n\"This method should only be called only once on a zookeeper handle. Calling\\n\"\n\"twice will cause undefined (and probably undesirable behavior).\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\"RETURNS:\\n\"\n\"Regardless of the error code returned, the zhandle \\n\"\n\"will be destroyed and all resources freed. \\n\"\n\"OK - success\\n\"\n\"EXCEPTIONS:\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\"\n\"OPERATIONTIMEOUT - failed to flush the buffers within the specified timeout.\\n\"\n\"CONNECTIONLOSS - a network error occurred while attempting to send request to server\\n\"\n  \"SYSTEMERROR -- a system (OS) error occurred; it's worth checking errno to get details\\n\";\n\nstatic const char pyzk_set2_doc[] = \n\"\\n\"\n\" sets the data associated with a node, and returns the associated stat structure.\\n\" \n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh: the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path: the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\" buffer: the buffer holding data to be written to the node.\\n\"\n\"\\n\"\n\"(subsequent parameters are optional)\\n\"\n\" version: the expected version of the node. The function will fail if \\n\"\n\"the actual version of the node does not match the expected version. If -1 is \\n\"\n\"used the version check will not take place. \\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" the stat structure for the target znode\\n\"\n\"OK operation completed successfully\\n\"\n\"EXCEPTIONS:\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADVERSION expected version does not match actual version.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\nstatic const char pyzk_init_doc[] = \n\"This method creates a new handle and a zookeeper session that corresponds\\n\"\n\"to that handle. Session establishment is asynchronous, meaning that the\\n\"\n\"session should not be considered established until (and unless) an\\n\"\n\"event of state CONNECTED_STATE is received.\\n\"\n\"PARAMETERS:\\n\"\n\" host: comma separated host:port pairs, each corresponding to a zk\\n\"\n\"  server. e.g. '127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002'\\n\"\n\"\\n\"\n\"(subsequent parameters are optional)\\n\"\n\" fn: the global watcher callback function. When notifications are\\n\"\n\"  triggered this function will be invoked.\\n\"\n\" recv_timeout: \\n\"\n\" (clientid, passwd)\\n\"\n\" clientid the id of a previously established session that this\\n\"\n\"  client will be reconnecting to. Clients can access the session id of an established, valid,\\n\"\n\"  connection by calling zoo_client_id. If\\n\"\n\"  the specified clientid has expired, or if the clientid is invalid for \\n\"\n\"  any reason, the returned zhandle_t will be invalid -- the zhandle_t \\n\"\n\"  state will indicate the reason for failure (typically\\n\"\n\"  EXPIRED_SESSION_STATE).\\n\"\n\"\\n\"\n\"RETURNS:\\n\"\n\" an integer handle. If it fails to create \\n\"\n\" a new zhandle the function throws an exception.\\n\";\n\nstatic const char pyzk_get_doc[] = \n\" gets the data associated with a node synchronously.\\n\"\n\"\\n\"\n\"\\n\"\n\"PARAMETERS:\\n\"\n\" zh the zookeeper handle obtained by a call to zookeeper.init\\n\"\n\" path the name of the node. Expressed as a file name with slashes \\n\"\n\"separating ancestors of the node.\\n\"\n\"\\n\"\n\"(subsequent parameters are optional)\\n\"\n\" watcher if not None, a watch will be set at the server to notify \\n\"\n\" the client if the node changes.\\n\"\n\" bufferlen: This value defaults to 1024*1024 - 1Mb. This method returns \\n\"\n\" the minimum of bufferlen and the true length of the znode's data. \\n\"\n\"RETURNS:\\n\"\n\" the data associated with the node\\n\"\n\"OK operation completed successfully\\n\"\n\"NONODE the node does not exist.\\n\"\n\"NOAUTH the client does not have permission.\\n\"\n\"BADARGUMENTS - invalid input parameters\\n\"\n\"INVALIDSTATE - zhandle state is either in SESSION_EXPIRED_STATE or AUTH_FAILED_STATE\\n\"\n  \"MARSHALLINGERROR - failed to marshall a request; possibly, out of memory\\n\";\n\n#endif\n"
  },
  {
    "path": "src/contrib/zkpython/src/c/zookeeper.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <Python.h>\n#include <zookeeper.h>\n#include <assert.h>\n  \n//////////////////////////////////////////////\n// EXCEPTIONS\nPyObject *ZooKeeperException = NULL;\nPyObject *SystemErrorException;\nPyObject *RuntimeInconsistencyException;\nPyObject *DataInconsistencyException;\nPyObject *ConnectionLossException;\nPyObject *MarshallingErrorException;\nPyObject *UnimplementedException;\nPyObject *OperationTimeoutException;\nPyObject *BadArgumentsException;\nPyObject *InvalidStateException;\n\nPyObject *ApiErrorException;\nPyObject *NoNodeException;\nPyObject *NoAuthException;\nPyObject *NodeExistsException;\nPyObject *BadVersionException;\nPyObject *NoChildrenForEphemeralsException;\nPyObject *NotEmptyException;\nPyObject *SessionExpiredException;\nPyObject *SessionMovedException;\nPyObject *InvalidCallbackException;\nPyObject *InvalidACLException;\nPyObject *AuthFailedException;\nPyObject *ClosingException;\nPyObject *NothingException;\n\nPyObject *err_to_exception(int errcode) {\n  switch (errcode) {\n  case ZSYSTEMERROR:\n    return SystemErrorException;\n  case ZINVALIDSTATE:\n    return InvalidStateException;\n  case ZRUNTIMEINCONSISTENCY:\n    return RuntimeInconsistencyException;\n  case ZDATAINCONSISTENCY:\n    return DataInconsistencyException;\n  case ZCONNECTIONLOSS:\n    return ConnectionLossException;\n  case ZMARSHALLINGERROR:\n    return MarshallingErrorException;\n  case ZUNIMPLEMENTED:\n    return UnimplementedException;\n  case ZOPERATIONTIMEOUT:\n    return OperationTimeoutException;\n  case ZBADARGUMENTS:\n    return BadArgumentsException;\n  case ZAPIERROR:\n    return ApiErrorException;\n  case ZNONODE:\n    return NoNodeException;\n  case ZNOAUTH:\n    return NoAuthException;\n  case ZBADVERSION:\n    return BadVersionException;\n  case ZNOCHILDRENFOREPHEMERALS:\n    return NoChildrenForEphemeralsException;\n  case ZNODEEXISTS:\n    return NodeExistsException;\n  case ZINVALIDACL:\n    return InvalidACLException;\n  case ZAUTHFAILED:\n    return AuthFailedException;\n  case ZNOTEMPTY:\n    return NotEmptyException;\n  case ZSESSIONEXPIRED:\n    return SessionExpiredException;\n  case ZINVALIDCALLBACK:\n    return InvalidCallbackException;\n  case ZSESSIONMOVED:\n    return SessionMovedException;\n  case ZCLOSING:\n    return ClosingException;\n  case ZNOTHING:\n    return NothingException;\n  case ZOK:\n  default:\n    return NULL;\n  }\n}\n\n\n#define CHECK_ZHANDLE(z) if ( (z) < 0 || (z) >= num_zhandles) {     \\\n  PyErr_SetString( ZooKeeperException, \"zhandle out of range\" ); \\\nreturn NULL;                           \\\n} else if ( zhandles[(z)] == NULL ) {               \\\n    PyErr_SetString(ZooKeeperException, \"zhandle already freed\"); \\\n    return NULL;                         \\\n  }\n\n/* Contains all the state required for a watcher callback - these are\n   passed to the *dispatch functions as void*, cast to pywatcher_t and\n   then their callback member is invoked if not NULL */\ntypedef struct {\n  int zhandle;\n  PyObject *callback;\n  int permanent;\n}pywatcher_t;\n\n/* This array exists because we need to ref. count the global watchers\n for each connection - but they're inaccessible without pulling in\n zk_adaptor.h, which I'm trying to avoid. */\nstatic pywatcher_t **watchers;\n\n/* We keep an array of zhandles available for use.  When a zhandle is\n correctly closed, the C client frees the memory so we set the\n zhandles[i] entry to NULL.  This entry can then be re-used. */\nstatic zhandle_t** zhandles = NULL;\nstatic int num_zhandles = 0;\nstatic int max_zhandles = 0;\n#define REAL_MAX_ZHANDLES 32768\n\n/* -------------------------------------------------------------------------- */\n/* zhandles - unique connection ids - tracking */\n/* -------------------------------------------------------------------------- */\n\n\n/* Allocates an initial zhandle and watcher array */\nint init_zhandles(int num) {\n  zhandles = malloc(sizeof(zhandle_t*)*num);\n  watchers = malloc(sizeof(pywatcher_t*)*num);\n  if (zhandles == NULL || watchers == NULL) {\n    return 0;\n  }\n  max_zhandles = num;\n  num_zhandles = 0;\n  memset(zhandles, 0, sizeof(zhandle_t*)*max_zhandles);\n  return 1;\n}\n\n/* Note that the following zhandle functions are not thread-safe. The\n C-Python runtime does not seem to pre-empt a thread that is in a C\n module, so there's no need for synchronisation.  */\n\n/* Doubles the size of the zhandle / watcher array Returns 0 if the\n new array would be >= REAL_MAX_ZHANDLES in size. Called when zhandles\n is full. Returns 0 if allocation failed or if max num zhandles\n exceeded. */\nint resize_zhandles(void) {\n  zhandle_t **tmp = zhandles;\n  pywatcher_t ** wtmp = watchers;\n  if (max_zhandles >= REAL_MAX_ZHANDLES >> 1) {\n    return 0;\n  }\n  max_zhandles *= 2;\n  zhandles = malloc(sizeof(zhandle_t*)*max_zhandles);\n  if (zhandles == NULL) {\n    PyErr_SetString(PyExc_MemoryError, \"malloc for new zhandles failed\");\n    return 0;\n  }\n  memset(zhandles, 0, sizeof(zhandle_t*)*max_zhandles);\n  memcpy(zhandles, tmp, sizeof(zhandle_t*)*max_zhandles/2);\n\n  watchers = malloc(sizeof(pywatcher_t*)*max_zhandles);\n  if (watchers == NULL) {\n    PyErr_SetString(PyExc_MemoryError, \"malloc for new watchers failed\");\n    return 0;\n  }\n  memset(watchers, 0, sizeof(pywatcher_t*)*max_zhandles);\n  memcpy(watchers, wtmp, sizeof(pywatcher_t*)*max_zhandles/2);\n\n  free(wtmp);\n  free(tmp);\n  return 1;\n}\n\n/* Find a free zhandle - this iterates through the list of open\n zhandles, but we expect it to be infrequently called.  There are\n optimisations that can be made if this turns out to be problematic.\n Returns -1 if no free handle is found - resize_handles() can be\n called in that case. */\nunsigned int next_zhandle(void) {\n  int i = 0;\n  for (i=0;i<max_zhandles;++i) {\n    if (zhandles[i] == NULL) {\n      num_zhandles++;\n      return i;\n    }\n  }\n \n  return -1;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Utility functions to construct and deallocate data structures */\n/* -------------------------------------------------------------------------- */\n\n\n/* Creates a new pywatcher_t to hold connection state, a callback\n   object and a flag to say if the watcher is permanent. Takes a new\n   reference to the callback object. */\npywatcher_t *create_pywatcher(int zh, PyObject* cb, int permanent)\n{\n  pywatcher_t *ret = (pywatcher_t*)calloc(sizeof(pywatcher_t),1);\n  if (ret == NULL) {\n    PyErr_SetString(PyExc_MemoryError, \"calloc failed in create_pywatcher\");\n    return NULL;\n  }\n  Py_INCREF(cb);\n  ret->zhandle = zh; ret->callback = cb; ret->permanent = permanent;\n  return ret;\n}\n\n/* Releases the reference taken in create_pywatcher to the callback,\n   then frees the allocated pywatcher_t* */\nvoid free_pywatcher(pywatcher_t *pw)\n{\n  if (pw == NULL) {\n    return;\n  }\n  Py_DECREF(pw->callback);\n\n  free(pw);\n}\n\n/* Constructs a new stat object. Returns Py_None if stat == NULL or a\n   dictionary containing all the stat information otherwise. In either\n   case, takes a reference to the returned object. */\nPyObject *build_stat( const struct Stat *stat )\n{\n  if (stat == NULL) { \n    Py_INCREF(Py_None);\n    return Py_None;\n  }\n  return Py_BuildValue( \"{s:K, s:K, s:K, s:K,\"\n                        \"s:i, s:i, s:i, s:K,\"\n                        \"s:i, s:i, s:K}\",\n                        \"czxid\", stat->czxid,\n                        \"mzxid\", stat->mzxid,\n                        \"ctime\", stat->ctime,\n                        \"mtime\", stat->mtime,\n                        \"version\", stat->version,\n                        \"cversion\", stat->cversion,\n                        \"aversion\", stat->aversion,\n                        \"ephemeralOwner\", stat->ephemeralOwner,\n                        \"dataLength\", stat->dataLength,\n                        \"numChildren\", stat->numChildren,\n                        \"pzxid\", stat->pzxid );\n}\n\n/* Creates a new list of strings from a String_vector. Returns the\n   empty list if the String_vector is NULL. Takes a reference to the\n   returned PyObject and gives that reference to the caller. */\nPyObject *build_string_vector(const struct String_vector *sv)\n{\n  PyObject *ret;\n  if (!sv) {\n    return PyList_New(0);\n  }\n\n  ret = PyList_New(sv->count);\n  if (ret) {\n    int i;\n    for (i=0;i<sv->count;++i)  {\n#if PY_MAJOR_VERSION >= 3\n      PyObject *s = PyUnicode_FromString(sv->data[i]);\n#else\n      PyObject *s = PyString_FromString(sv->data[i]);\n#endif\n      if (!s) {\n        if (ret != Py_None) {\n          Py_DECREF(ret);\n        }\n        ret = NULL;\n        break;\n      }\n      PyList_SetItem(ret, i, s);\n    }\n  }\n  return ret;\n}\n\n/* Returns 1 if the PyObject is a valid representation of an ACL, and\n   0 otherwise. */\nint check_is_acl(PyObject *o) {\n  int i;\n  PyObject *entry;\n  if (o == NULL) {\n    return 0;\n  }\n  if (!PyList_Check(o)) {\n    return 0;\n  }\n  for (i=0;i<PyList_Size(o);++i) {\n    PyObject *element = PyList_GetItem(o,i);\n    if (!PyDict_Check(element)) {\n      return 0;\n    }\n    entry = PyDict_GetItemString( element, \"perms\" );\n    if (entry == NULL) {\n      return 0;\n    }\n\n    entry = PyDict_GetItemString( element, \"scheme\" );\n    if (entry == NULL) {\n      return 0;\n    }\n\n    entry = PyDict_GetItemString( element, \"id\" );\n    if (entry == NULL) {\n      return 0;\n    }\n  }\n\n  return 1;\n}\n\n/* Macro form to throw exception if o is not an ACL */\n#define CHECK_ACLS(o) if (check_is_acl(o) == 0) {                       \\\n    PyErr_SetString(err_to_exception(ZINVALIDACL), zerror(ZINVALIDACL)); \\\n    return NULL;                                                        \\\n  }\n\n\n/* Creates a new list of ACL dictionaries from an ACL_vector. Returns\n   the empty list if the ACL_vector is NULL. Takes a reference to the\n   returned PyObject and gives that reference to the caller. */\nPyObject *build_acls( const struct ACL_vector *acls )\n{\n  if (acls == NULL) {\n    return PyList_New(0);\n  }\n\n  PyObject *ret = PyList_New(acls->count);\n  int i;\n  for (i=0;i<acls->count;++i) {\n    PyObject *acl = Py_BuildValue( \"{s:i, s:s, s:s}\", \n                                   \"perms\", acls->data[i].perms, \n                                   \"scheme\", acls->data[i].id.scheme,\n                                   \"id\", acls->data[i].id.id );\n    PyList_SetItem(ret, i, acl);\n  }\n  return ret;\n}\n\n/* Parse the Python representation of an ACL list into an ACL_vector\n   (which needs subsequent freeing) */\nint parse_acls(struct ACL_vector *acls, PyObject *pyacls)\n{\n  PyObject *a;\n  int i;\n  if (acls == NULL || pyacls == NULL) {\n    PyErr_SetString(PyExc_ValueError, \"acls or pyacls NULL in parse_acls\");\n    return 0;\n  }\n\n  acls->count = PyList_Size( pyacls );\n\n  // Is this a list? If not, we can't do anything\n  if (PyList_Check(pyacls) == 0) {\n    PyErr_SetString(InvalidACLException, \"List of ACLs required in parse_acls\");\n    return 0;\n  }\n\n  acls->data = (struct ACL *)calloc(acls->count, sizeof(struct ACL));\n  if (acls->data == NULL) {\n    PyErr_SetString(PyExc_MemoryError, \"calloc failed in parse_acls\");\n    return 0;\n  }\n\n  for (i=0;i<acls->count;++i) {\n    a = PyList_GetItem(pyacls, i);\n    // a is now a dictionary\n    PyObject *perms = PyDict_GetItemString( a, \"perms\" );\n#if PY_MAJOR_VERSION >= 3\n    acls->data[i].perms = (int32_t)(PyLong_AsLong(perms));\n    acls->data[i].id.id = strdup( PyUnicode_AsUnicode( PyDict_GetItemString( a, \"id\" ) ) );\n    acls->data[i].id.scheme = strdup( PyUnicode_AsUnicode( PyDict_GetItemString( a, \"scheme\" ) ) );\n#else\n    acls->data[i].perms = (int32_t)(PyInt_AsLong(perms));\n    acls->data[i].id.id = strdup( PyString_AsString( PyDict_GetItemString( a, \"id\" ) ) );\n    acls->data[i].id.scheme = strdup( PyString_AsString( PyDict_GetItemString( a, \"scheme\" ) ) );\n#endif\n  }\n  return 1;\n}\n\n/* Deallocates the memory allocated inside an ACL_vector, but not the\n   ACL_vector itself */\nvoid free_acls( struct ACL_vector *acls )\n{\n  if (acls == NULL) {\n    return;\n  }\n  int i;\n  for (i=0;i<acls->count;++i) {\n    free(acls->data[i].id.id);\n    free(acls->data[i].id.scheme);\n  }\n  free(acls->data);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Watcher and callback implementation */\n/* -------------------------------------------------------------------------- */\n\n/* Every watcher invocation goes through this dispatch point, which \n   a) acquires the global interpreter lock\n\n   b) unpacks the PyObject to call from the passed context pointer,\n   which handily includes the index of the relevant zookeeper handle\n   to pass back to Python.\n\n   c) Makes the call into Python, checking for error conditions which\n   we are responsible for detecting and doing something about (we just\n   print the error and plough right on)\n\n   d) releases the lock after freeing up the context object, which is\n   only used for one watch invocation (watches are one-shot, unless\n   'permanent' != 0)\n*/\nvoid watcher_dispatch(zhandle_t *zzh, int type, int state, \n                      const char *path, void *context)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)context;\n  PyObject *callback = pyw->callback;\n  if (callback == NULL) {\n    // This is unexpected\n    char msg[256];\n    sprintf(msg, \"pywatcher: %d %p %d\", pyw->zhandle, pyw->callback, pyw->permanent);\n    PyErr_SetString(PyExc_ValueError, msg);\n    return;\n  }\n\n  gstate = PyGILState_Ensure();\n  PyObject *arglist = Py_BuildValue(\"(i,i,i,s)\", pyw->zhandle,type, state, path);\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL) {\n    PyErr_Print();\n  }\n  Py_DECREF(arglist);\n  if (pyw->permanent == 0 && (type != ZOO_SESSION_EVENT || state < 0)) {\n    free_pywatcher(pyw);\n  }\n  PyGILState_Release(gstate);\n}\n\n/* The completion callbacks (from asynchronous calls) are implemented similarly */\n\n/* Called when an asynchronous call that returns void completes and\n   dispatches user provided callback */\nvoid void_completion_dispatch(int rc, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL)\n    return;\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *arglist = Py_BuildValue(\"(i,i)\", pyw->zhandle, rc);\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL)\n    PyErr_Print();\n  Py_DECREF(arglist);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* Called when an asynchronous call that returns a stat structure\n   completes and dispatches user provided callback */\nvoid stat_completion_dispatch(int rc, const struct Stat *stat, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL)\n    return;\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *pystat = build_stat(stat);\n  PyObject *arglist = Py_BuildValue(\"(i,i,O)\", pyw->zhandle,rc, pystat);\n  Py_DECREF(pystat);\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL)\n    PyErr_Print();\n  Py_DECREF(arglist);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* Called when an asynchronous call that returns a stat structure and\n   some untyped data completes and dispatches user provided\n   callback (used by aget) */\nvoid data_completion_dispatch(int rc, const char *value, int value_len, const struct Stat *stat, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL)\n    return;\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *pystat = build_stat(stat);\n  PyObject *arglist = Py_BuildValue(\"(i,i,s#,O)\", pyw->zhandle,rc, value,value_len, pystat);\n  Py_DECREF(pystat);\n\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL)\n    PyErr_Print();\n  Py_DECREF(arglist);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* Called when an asynchronous call that returns a list of strings\n   completes and dispatches user provided callback */\nvoid strings_completion_dispatch(int rc, const struct String_vector *strings, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL)\n    return;\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *pystrings = build_string_vector(strings);\n  if (pystrings)\n    {\n      PyObject *arglist = Py_BuildValue(\"(i,i,O)\", pyw->zhandle, rc, pystrings);   \n      if (arglist == NULL || PyObject_CallObject((PyObject*)callback, arglist) == NULL)\n        PyErr_Print();\n      Py_DECREF(arglist);\n    }\n  else\n    PyErr_Print();\n  Py_DECREF(pystrings);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* Called when an asynchronous call that returns a single string\n   completes and dispatches user provided callback */\nvoid string_completion_dispatch(int rc, const char *value, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL) {\n    return;\n  }\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *arglist = Py_BuildValue(\"(i,i,s)\", pyw->zhandle,rc, value);\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL)\n    PyErr_Print();\n  Py_DECREF(arglist);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* Called when an asynchronous call that returns a list of ACLs\n   completes and dispatches user provided callback */\nvoid acl_completion_dispatch(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data)\n{\n  PyGILState_STATE gstate;\n  pywatcher_t *pyw = (pywatcher_t*)data;\n  if (pyw == NULL) {\n    return;\n  }\n  PyObject *callback = pyw->callback;\n  gstate = PyGILState_Ensure();\n  PyObject *pystat = build_stat(stat);\n  PyObject *pyacls = build_acls(acl);\n  PyObject *arglist = Py_BuildValue(\"(i,i,O,O)\", pyw->zhandle,rc, pyacls, pystat);\n\n  Py_DECREF(pystat);\n  Py_DECREF(pyacls);\n\n  if (PyObject_CallObject((PyObject*)callback, arglist) == NULL) {\n    PyErr_Print();\n  }\n  Py_DECREF(arglist);\n  free_pywatcher(pyw);\n  PyGILState_Release(gstate);\n}\n\n/* -------------------------------------------------------------------------- */\n/* ZOOKEEPER API IMPLEMENTATION */\n/* -------------------------------------------------------------------------- */\n\nstatic PyObject *pyzookeeper_init(PyObject *self, PyObject *args)\n{\n  const char *host;\n  PyObject *watcherfn = Py_None;\n  int recv_timeout = 10000;\n  //  int clientid = -1;\n  clientid_t cid;\n  cid.client_id = -1;\n  const char *passwd;\n  int handle = next_zhandle();\n  if (handle == -1) {\n    if (resize_zhandles() == 0) {\n      return NULL;\n    }\n    handle = next_zhandle();\n  }\n\n  if (handle == -1) {\n    PyErr_SetString(ZooKeeperException,\"Couldn't find a free zhandle, something is very wrong\");\n    return NULL;\n  }\n\n  if (!PyArg_ParseTuple(args, \"s|Oi(Ls)\", &host, &watcherfn, &recv_timeout, &cid.client_id, &passwd)) \n    return NULL;\n  \n  if (cid.client_id != -1) {\n    strncpy(cid.passwd, passwd, 16*sizeof(char));\n  }\n  pywatcher_t *pyw = NULL;\n  if (watcherfn != Py_None) {\n    pyw = create_pywatcher(handle, watcherfn,1);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n  watchers[handle] = pyw;\n  zhandle_t *zh = zookeeper_init( host, watcherfn != Py_None ? watcher_dispatch : NULL, \n                                  recv_timeout, cid.client_id == -1 ? 0 : &cid, \n                                  pyw,\n                                  0 ); \n\n  if (zh == NULL)\n    {\n      PyErr_SetString( ZooKeeperException, \"Could not internally obtain zookeeper handle\" );\n      return NULL;\n    }\n\n  zhandles[handle] = zh;\n  return Py_BuildValue( \"i\", handle);\n}\n\n\n/* -------------------------------------------------------------------------- */\n/* Asynchronous API implementation */\n/* -------------------------------------------------------------------------- */\n\n/* Asynchronous node creation, returns integer error code */\nPyObject *pyzoo_acreate(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; char *value; int valuelen;\n  struct ACL_vector acl; int flags = 0;\n  PyObject *completion_callback = Py_None;\n  PyObject *pyacls = Py_None;\n  if (!PyArg_ParseTuple(args, \"iss#O|iO\", &zkhid, &path, \n                        &value, &valuelen, &pyacls, &flags, \n                        &completion_callback)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  CHECK_ACLS(pyacls);\n  if (parse_acls(&acl, pyacls) == 0) {\n    return NULL;\n  }\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n  int err = zoo_acreate( zhandles[zkhid],\n                         path,\n                         value,\n                         valuelen,\n                         pyacls == Py_None ? NULL : &acl,\n                         flags,\n                         string_completion_dispatch,\n                         pyw);\n  free_acls(&acl);\n  if (err != ZOK)\n    {\n      PyErr_SetString(err_to_exception(err), zerror(err));\n      return NULL;\n    }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Asynchronous node deletion, returns integer error code */\nPyObject *pyzoo_adelete(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; int version = -1;\n  PyObject *completion_callback = Py_None;\n  if (!PyArg_ParseTuple(args, \"is|iO\", &zkhid, &path, &version, &completion_callback))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_adelete( zhandles[zkhid],\n                         path,\n                         version,\n                         void_completion_dispatch,\n                         pyw);\n    \n  if (err != ZOK) {\n      PyErr_SetString(err_to_exception(err), zerror(err));\n      return NULL;\n    }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Asynchronous node existence check, returns integer error code */\nPyObject *pyzoo_aexists(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; \n  PyObject *completion_callback = Py_None;\n  PyObject *exists_watch = Py_None;\n  if (!PyArg_ParseTuple(args, \"is|OO\", &zkhid, &path, \n                        &exists_watch, &completion_callback))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  void *comp_pyw = NULL;\n  if (completion_callback != Py_None) {\n    comp_pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (comp_pyw == NULL) {\n      return NULL;\n    }\n  }\n  void *exist_pyw = NULL;\n  if (exists_watch != Py_None) {\n    exist_pyw = create_pywatcher(zkhid, exists_watch, 0);\n    if (exist_pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_awexists( zhandles[zkhid],\n                          path,\n                          exists_watch != Py_None ? watcher_dispatch : NULL,\n                          exist_pyw,\n                          stat_completion_dispatch,\n                          comp_pyw);\n    \n  if (err != ZOK)\n    {\n      PyErr_SetString(err_to_exception(err), zerror(err));\n      return NULL;\n    }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* Asynchronous node data retrieval, returns integer error code */\nPyObject *pyzoo_aget(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; \n  PyObject *completion_callback = Py_None;\n  PyObject *get_watch = Py_None;\n  void *comp_pw = NULL;\n  void *watch_pw = NULL;\n\n  if (!PyArg_ParseTuple(args, \"is|OO\", &zkhid, &path, \n                        &get_watch, &completion_callback)) {\n    return NULL;\n  }\n\n  CHECK_ZHANDLE(zkhid);\n\n  if (get_watch != Py_None) {\n    if ((watch_pw = create_pywatcher(zkhid, get_watch, 0)) == NULL) {\n      return NULL;\n    }\n  }\n\n  if (completion_callback != Py_None) {\n    if ((comp_pw = create_pywatcher(zkhid, completion_callback, 0)) == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_awget( zhandles[zkhid],\n                       path,\n                       get_watch != Py_None ? watcher_dispatch : NULL,\n                       watch_pw,\n                       data_completion_dispatch,\n                       comp_pw);\n    \n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Asynchronous node contents update, returns integer error code */\nPyObject *pyzoo_aset(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; char *buffer; int buflen; int version=-1;\n  PyObject *completion_callback = Py_None;\n  if (!PyArg_ParseTuple(args, \"iss#|iO\", &zkhid, &path, &buffer, &buflen, &version, &completion_callback))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n  int err = zoo_aset( zhandles[zkhid],\n                      path,\n                      buffer,\n                      buflen,\n                      version,\n                      stat_completion_dispatch,\n                      pyw);\n    \n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Asynchronous node child retrieval, returns integer error code */\nPyObject *pyzoo_aget_children(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; \n  PyObject *completion_callback = Py_None;\n  PyObject *get_watch;\n  if (!PyArg_ParseTuple(args, \"is|OO\", &zkhid,  &path,\n                        &get_watch, &completion_callback))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n\n  void *get_pyw = NULL;\n  if (get_watch != Py_None) {\n    get_pyw = create_pywatcher(zkhid, get_watch, 0);\n    if (get_pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_awget_children( zhandles[zkhid],\n                                path,\n                                get_watch != Py_None ? watcher_dispatch : NULL,\n                                get_pyw,\n                                strings_completion_dispatch,\n                                pyw);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* Asynchronous sync, returns integer error code */\nPyObject *pyzoo_async(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; \n  PyObject *completion_callback = Py_None;\n  if (!PyArg_ParseTuple(args, \"is|O\", &zkhid, &path, \n                        &completion_callback)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_async( zhandles[zkhid],\n                       path,\n                       string_completion_dispatch,\n                       pyw);\n \n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* Asynchronous node ACL retrieval, returns integer error code */\nPyObject *pyzoo_aget_acl(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; \n  PyObject *completion_callback = Py_None;\n  if (!PyArg_ParseTuple(args, \"is|O\", &zkhid, &path, \n                        &completion_callback)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_aget_acl( zhandles[zkhid],\n                          path,\n                          acl_completion_dispatch,\n                          pyw);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* Asynchronous node ACL update, returns integer error code */\nPyObject *pyzoo_aset_acl(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; int version; \n  PyObject *completion_callback = Py_None, *pyacl;\n  struct ACL_vector aclv;\n  if (!PyArg_ParseTuple(args, \"isiO|O\", &zkhid, &path, &version, \n                        &pyacl, &completion_callback)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  CHECK_ACLS(pyacl);\n  if (parse_acls(&aclv, pyacl) == 0) {\n    return NULL;\n  }\n\n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_aset_acl( zhandles[zkhid],\n                          path,\n                          version,\n                          &aclv,\n                          void_completion_dispatch,\n                          pyw);\n  free_acls(&aclv);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* Asynchronous authorization addition, returns integer error code */\nPyObject *pyzoo_add_auth(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *scheme, *cert;\n  int certLen;\n  PyObject *completion_callback;\n\n  if (!PyArg_ParseTuple(args, \"iss#O\", &zkhid, &scheme, &cert, &certLen, \n                        &completion_callback)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  \n  void *pyw = NULL;\n  if (completion_callback != Py_None) {\n    pyw = create_pywatcher(zkhid, completion_callback, 0);\n    if (pyw == NULL) {\n      return NULL;\n    }\n  }\n\n  int err = zoo_add_auth( zhandles[zkhid],\n                          scheme,\n                          cert,\n                          certLen,\n                          void_completion_dispatch,\n                          pyw);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Synchronous API implementation */\n/* -------------------------------------------------------------------------- */\n\n/* Synchronous node creation, returns node path string */\nstatic PyObject *pyzoo_create(PyObject *self, PyObject *args)\n{\n  char *path;\n  int zkhid;\n  char* values;\n  int valuelen;\n  PyObject *acl = NULL;  \n  int flags = 0;\n  char realbuf[256];\n  const int maxbuf_len = 256;\n  if (!PyArg_ParseTuple(args, \"iss#O|i\",&zkhid, &path, &values, &valuelen,&acl,&flags))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  struct ACL_vector aclv;\n  CHECK_ACLS(acl);\n  if (parse_acls(&aclv,acl) == 0) {\n    return NULL;\n  }\n  zhandle_t *zh = zhandles[zkhid];\n  int err = zoo_create(zh, path, values, valuelen, &aclv, flags, realbuf, maxbuf_len);\n  free_acls(&aclv);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n\n  return Py_BuildValue(\"s\", realbuf);\n}\n\n/* Synchronous node deletion, returns integer error code */\nstatic PyObject *pyzoo_delete(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  int version = -1;\n  if (!PyArg_ParseTuple(args, \"is|i\",&zkhid,&path,&version))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  zhandle_t *zh = zhandles[zkhid];\n  int err = zoo_delete(zh, path, version);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Synchronous node existence check, returns stat if exists, None if\n   absent */\nstatic PyObject *pyzoo_exists(PyObject *self, PyObject *args)\n{\n  int zkhid; char *path; PyObject *watcherfn = Py_None;\n  struct Stat stat;\n  if (!PyArg_ParseTuple(args, \"is|O\", &zkhid, &path, &watcherfn)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  zhandle_t *zh = zhandles[zkhid];\n  pywatcher_t *pw = NULL;\n  void *callback = NULL;\n  if (watcherfn != Py_None) {\n    pw = create_pywatcher(zkhid, watcherfn,0);\n    callback = watcher_dispatch;\n    if (pw == NULL) {\n      return NULL;\n    }\n  }\n  int err = zoo_wexists(zh,  path, callback, pw, &stat);\n  if (err != ZOK && err != ZNONODE) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    free_pywatcher(pw);\n    return NULL;\n  }\n  if (err == ZNONODE) {\n    Py_INCREF(Py_None);\n    return Py_None; // This isn't exceptional\n  }\n  return build_stat(&stat);\n}\n\n/* Synchronous node child retrieval, returns list of children's path\n   as strings */\nstatic PyObject *pyzoo_get_children(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  PyObject *watcherfn = Py_None;\n  struct String_vector strings; \n  if (!PyArg_ParseTuple(args, \"is|O\", &zkhid, &path, &watcherfn)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  pywatcher_t *pw = NULL;\n  void *callback = NULL;\n  if (watcherfn != Py_None) {\n    pw = create_pywatcher( zkhid, watcherfn, 0 );\n    callback = watcher_dispatch;\n    if (pw == NULL) {\n      return NULL;\n    }\n  }\n  int err = zoo_wget_children(zhandles[zkhid], path, \n                              callback,\n                              pw, &strings );\n\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    free_pywatcher(pw);\n    return NULL;\n  }\n\n  PyObject *ret = build_string_vector(&strings);\n  deallocate_String_vector(&strings);\n  return ret;\n}\n\n/* Synchronous node data update, returns integer error code */\nstatic PyObject *pyzoo_set(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  char *buffer;\n  int buflen;\n  int version = -1; \n  if (!PyArg_ParseTuple(args, \"iss#|i\", &zkhid, &path, &buffer, &buflen, \n                        &version)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n\n  int err = zoo_set(zhandles[zkhid], path, buffer, buflen, version);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n\n  return Py_BuildValue(\"i\", err);\n}\n\n/* Synchronous node data update, returns node's stat data structure */\nstatic PyObject *pyzoo_set2(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  char *buffer;\n  int buflen;\n  int version = -1; \n  if (!PyArg_ParseTuple(args, \"iss#|i\", &zkhid, &path, &buffer, &buflen, \n                        &version)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  struct Stat stat;\n  int err = zoo_set2(zhandles[zkhid], path, buffer, buflen, version, &stat);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n\n  return build_stat(&stat);\n}\n\n/* As per ZK documentation, datanodes are limited to 1Mb. Why not do a\n stat followed by a get, to determine how big the buffer should be?\n Because the znode may get updated between calls, so we can't\n guarantee a complete get anyhow.  */\n#define GET_BUFFER_SIZE 1024*1024\n\n/* pyzoo_get has an extra parameter over the java/C equivalents.  If\n you set the fourth integer parameter buffer_len, we return\n min(buffer_len, datalength) bytes. This is set by default to\n GET_BUFFER_SIZE */\nstatic PyObject *pyzoo_get(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  char *buffer; \n  int buffer_len=GET_BUFFER_SIZE;\n  struct Stat stat;\n  PyObject *watcherfn = Py_None;\n  pywatcher_t *pw = NULL;\n  if (!PyArg_ParseTuple(args, \"is|Oi\", &zkhid, &path, &watcherfn, &buffer_len)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  if (watcherfn != Py_None) {\n    pw = create_pywatcher( zkhid, watcherfn,0 );\n    if (pw == NULL) {\n      return NULL;\n    }\n  }\n  buffer = malloc(sizeof(char)*buffer_len);\n  if (buffer == NULL) {\n    free_pywatcher(pw);\n    PyErr_SetString(PyExc_MemoryError, \"buffer could not be allocated in pyzoo_get\");\n    return NULL;\n  }\n      \n  int err = zoo_wget(zhandles[zkhid], path, \n                     watcherfn != Py_None ? watcher_dispatch : NULL, \n                     pw, buffer, \n                     &buffer_len, &stat);\n \n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    free_pywatcher(pw);\n    free(buffer);\n    return NULL;\n  }\n\n  PyObject *stat_dict = build_stat( &stat );\n  PyObject *ret = Py_BuildValue( \"(s#,N)\", buffer,buffer_len < 0 ? 0 : buffer_len, stat_dict );\n  free(buffer);\n\n  return ret;\n}\n\n/* Synchronous node ACL retrieval, returns list of ACLs */\nPyObject *pyzoo_get_acl(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  struct ACL_vector acl;\n  struct Stat stat;\n  if (!PyArg_ParseTuple(args, \"is\", &zkhid, &path))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  int err = zoo_get_acl( zhandles[zkhid], path, &acl, &stat );\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL; \n  }\n  PyObject *pystat = build_stat( &stat ); \n  PyObject *acls = build_acls( &acl );\n  PyObject *ret = Py_BuildValue( \"(O,O)\", pystat, acls );\n  Py_DECREF(pystat);\n  Py_DECREF(acls);\n  return ret;\n}\n\n/* Synchronous node ACL update, returns integer error code */\nPyObject *pyzoo_set_acl(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  char *path;\n  int version;\n  PyObject *pyacls;\n  struct ACL_vector acl;\n  if (!PyArg_ParseTuple(args, \"isiO\", &zkhid, &path, &version, &pyacls)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  if (parse_acls(&acl, pyacls) == 0) {\n    return NULL;\n  }\n  int err = zoo_set_acl(zhandles[zkhid], path, version, &acl );\n  free_acls(&acl);\n  if (err != ZOK) {\n    PyErr_SetString(err_to_exception(err), zerror(err));\n    return NULL;\n  }\n  return Py_BuildValue(\"i\", err);;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Session and context methods */\n/* -------------------------------------------------------------------------- */\n\n/* Closes a connection, returns integer error code */\nPyObject *pyzoo_close(PyObject *self, PyObject *args)\n{\n  int zkhid, ret;\n  if (!PyArg_ParseTuple(args, \"i\", &zkhid)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  zhandle_t *handle = zhandles[zkhid];\n  Py_BEGIN_ALLOW_THREADS\n  ret = zookeeper_close(handle);\n  Py_END_ALLOW_THREADS\n  zhandles[zkhid] = NULL; // The zk C client frees the zhandle\n  return Py_BuildValue(\"i\", ret);\n}\n\n/* Returns the ID of current client as a tuple (client_id, passwd) */\nPyObject *pyzoo_client_id(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  if (!PyArg_ParseTuple(args, \"i\", &zkhid)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  const clientid_t *cid = zoo_client_id(zhandles[zkhid]);\n  return Py_BuildValue(\"(L,s)\", cid->client_id, cid->passwd);\n}\n\n/* DO NOT USE - context is used internally. This method is not exposed\n   in the Python module */\nPyObject *pyzoo_get_context(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  if (!PyArg_ParseTuple(args, \"i\", &zkhid))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  PyObject *context = NULL;\n  context = (PyObject*)zoo_get_context(zhandles[zkhid]);\n  if (context) return context;\n  Py_INCREF(Py_None);\n  return Py_None;  \n}\n\n/* DO NOT USE - context is used internally. This method is not exposed\n   in the Python module */\nPyObject *pyzoo_set_context(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  PyObject *context;\n  if (!PyArg_ParseTuple(args, \"iO\", &zkhid, &context)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  PyObject *py_context = (PyObject*)zoo_get_context(zhandles[zkhid]);\n  if (py_context != NULL && py_context != Py_None) {\n    Py_DECREF(py_context);\n  }\n  Py_INCREF(context);\n  zoo_set_context(zhandles[zkhid], (void*)context);\n  Py_INCREF(Py_None);\n  return Py_None;\n}\n\n\n/* -------------------------------------------------------------------------- */\n/* Miscellaneous methods */\n/* -------------------------------------------------------------------------- */\n\n/* Sets the global watcher. Returns None */\nPyObject *pyzoo_set_watcher(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  PyObject *watcherfn;\n  if (!PyArg_ParseTuple(args, \"iO\", &zkhid, &watcherfn)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  pywatcher_t *pyw = watchers[zkhid];\n  if (pyw != NULL) {\n    free_pywatcher( pyw );\n  }\n  \n  // Create a *permanent* watcher object, not deallocated when called\n  pyw = create_pywatcher(zkhid, watcherfn,1);\n  if (pyw == NULL) {\n    return NULL;\n  }\n  watchers[zkhid] = pyw;\n  zoo_set_watcher(zhandles[zkhid], watcher_dispatch);\n  zoo_set_context(zhandles[zkhid], pyw);\n  Py_INCREF(Py_None);\n  return Py_None; \n}\n\n/* Returns an integer code representing the current connection\n   state */\nPyObject *pyzoo_state(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  if (!PyArg_ParseTuple(args,\"i\",&zkhid)) {\n    return NULL;\n  }\n  CHECK_ZHANDLE(zkhid);\n  int state = zoo_state(zhandles[zkhid]);\n  return Py_BuildValue(\"i\",state);\n}\n\n\n/* Convert an integer error code into a string */\nPyObject *pyzerror(PyObject *self, PyObject *args)\n{\n  int rc;\n  if (!PyArg_ParseTuple(args,\"i\", &rc))\n    return NULL;\n  return Py_BuildValue(\"s\", zerror(rc));\n}\n\n/* Returns the integer receive timeout for a connection */\nPyObject *pyzoo_recv_timeout(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  if (!PyArg_ParseTuple(args,\"i\",&zkhid))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  int recv_timeout = zoo_recv_timeout(zhandles[zkhid]);\n  return Py_BuildValue(\"i\",recv_timeout);  \n}\n\n/* Returns True if connection is unrecoverable, False otherwise */\nPyObject *pyis_unrecoverable(PyObject *self, PyObject *args)\n{\n  int zkhid;\n  if (!PyArg_ParseTuple(args,\"i\",&zkhid))\n    return NULL;\n  CHECK_ZHANDLE(zkhid);\n  int ret = is_unrecoverable(zhandles[zkhid]);\n  if (ret == ZINVALIDSTATE)\n    Py_RETURN_TRUE;\n  Py_RETURN_FALSE;\n}\n\n/* Set the debug level for logging, returns None */\nPyObject *pyzoo_set_debug_level(PyObject *self, PyObject *args)\n{\n  int loglevel;\n  if (!PyArg_ParseTuple(args, \"i\", &loglevel))\n    return NULL;\n  zoo_set_debug_level((ZooLogLevel)loglevel);\n  Py_INCREF(Py_None);\n  return Py_None;\n}\n\nstatic PyObject *log_stream = NULL;\n\n/* Set the output file-like object for logging output. Returns Py_None */\nPyObject *pyzoo_set_log_stream(PyObject *self, PyObject *args)\n{\n  PyObject *pystream = NULL;\n  if (!PyArg_ParseTuple(args,\"O\",&pystream)) {\n    PyErr_SetString(PyExc_ValueError, \"Must supply a Python object to set_log_stream\");\n    return NULL;\n  }\n  \n#if PY_MAJOR_VERSION >= 3\n  extern PyTypeObject PyIOBase_Type;\n  if (!PyObject_IsInstance(pystream, (PyObject *)&PyIOBase_Type)) {\n#else\n  if(!PyFile_Check(pystream)) {\n#endif\n\n    PyErr_SetString(PyExc_ValueError, \"Must supply a file object to set_log_stream\");\n    return NULL;\n  }\n  /* Release the previous reference to log_stream that we took */\n  if (log_stream != NULL) {\n    Py_DECREF(log_stream);\n  }\n\n  log_stream = pystream;\n  Py_INCREF(log_stream);\n\n#if PY_MAJOR_VERSION >= 3\n  int fd = PyObject_AsFileDescriptor(log_stream);\n  FILE *fp = fdopen(fd, \"w\");\n#else \n  FILE *fp = PyFile_AsFile(log_stream);\n#endif\n  zoo_set_log_stream(fp);\n\n  Py_INCREF(Py_None);\n  return Py_None;\n}\n\n/* Set the connection order - randomized or in-order. Returns None. */\nPyObject *pyzoo_deterministic_conn_order(PyObject *self, PyObject *args)\n{\n  int yesOrNo;\n  if (!PyArg_ParseTuple(args, \"i\",&yesOrNo))\n    return NULL;\n  zoo_deterministic_conn_order( yesOrNo );\n  Py_INCREF(Py_None);\n  return Py_None;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Module setup */\n/* -------------------------------------------------------------------------- */\n\n#include \"pyzk_docstrings.h\"\n\nstatic PyMethodDef ZooKeeperMethods[] = {\n  {\"init\", pyzookeeper_init, METH_VARARGS, pyzk_init_doc },\n  {\"create\",pyzoo_create, METH_VARARGS, pyzk_create_doc },\n  {\"delete\",pyzoo_delete, METH_VARARGS, pyzk_delete_doc },\n  {\"get_children\", pyzoo_get_children, METH_VARARGS, pyzk_get_children_doc },\n  {\"set\", pyzoo_set, METH_VARARGS, pyzk_set_doc },\n  {\"set2\", pyzoo_set2, METH_VARARGS, pyzk_set2_doc },\n  {\"get\",pyzoo_get, METH_VARARGS, pyzk_get_doc },\n  {\"exists\",pyzoo_exists, METH_VARARGS, pyzk_exists_doc },\n  {\"get_acl\", pyzoo_get_acl, METH_VARARGS, pyzk_get_acl_doc },\n  {\"set_acl\", pyzoo_set_acl, METH_VARARGS, pyzk_set_acl_doc },\n  {\"close\", pyzoo_close, METH_VARARGS, pyzk_close_doc },\n  {\"client_id\", pyzoo_client_id, METH_VARARGS, pyzk_client_id_doc },\n  {\"set_watcher\", pyzoo_set_watcher, METH_VARARGS }, \n  {\"state\", pyzoo_state, METH_VARARGS, pyzk_state_doc },\n  {\"recv_timeout\",pyzoo_recv_timeout, METH_VARARGS },\n  {\"is_unrecoverable\",pyis_unrecoverable, METH_VARARGS, pyzk_is_unrecoverable_doc },\n  {\"set_debug_level\",pyzoo_set_debug_level, METH_VARARGS, pyzk_set_debug_level_doc }, \n  {\"set_log_stream\",pyzoo_set_log_stream, METH_VARARGS, pyzk_set_log_stream_doc },\n  {\"deterministic_conn_order\",pyzoo_deterministic_conn_order, METH_VARARGS, pyzk_deterministic_conn_order_doc },\n  {\"acreate\", pyzoo_acreate, METH_VARARGS, pyzk_acreate_doc },\n  {\"adelete\", pyzoo_adelete, METH_VARARGS,pyzk_adelete_doc },\n  {\"aexists\", pyzoo_aexists, METH_VARARGS,pyzk_aexists_doc },\n  {\"aget\", pyzoo_aget, METH_VARARGS, pyzk_aget_doc },\n  {\"aset\", pyzoo_aset, METH_VARARGS, pyzk_aset_doc },\n  {\"aget_children\", pyzoo_aget_children, METH_VARARGS, pyzk_aget_children_doc },\n  {\"async\", pyzoo_async, METH_VARARGS, pyzk_async_doc },\n  {\"aget_acl\", pyzoo_aget_acl, METH_VARARGS, pyzk_aget_acl_doc },\n  {\"aset_acl\", pyzoo_aset_acl, METH_VARARGS, pyzk_aset_acl_doc },\n  {\"zerror\", pyzerror, METH_VARARGS, pyzk_zerror_doc },\n  {\"add_auth\", pyzoo_add_auth, METH_VARARGS, pyzk_add_auth_doc },\n  /* DO NOT USE get / set_context. Context is used internally to pass\n   the python watcher to a dispatch function. If you want context, set\n   it through set_watcher. */\n  // {\"get_context\", pyzoo_get_context, METH_VARARGS, \"\" },\n  // {\"set_context\", pyzoo_set_context, METH_VARARGS, \"\" },\n  {NULL, NULL}\n};\n\n#if PY_MAJOR_VERSION >= 3 \nstatic struct PyModuleDef zookeeper_moddef = {\n  PyModuleDef_HEAD_INIT,\n  \"zookeeper\",\n  NULL,\n  0,\n  ZooKeeperMethods,\n  0,\n  0,\n  0,\n  0\n};\n#endif\n\n#define ADD_INTCONSTANT(x) PyModule_AddIntConstant(module, #x, ZOO_##x)\n#define ADD_INTCONSTANTZ(x) PyModule_AddIntConstant(module, #x, Z##x)\n\n#define ADD_EXCEPTION(x) x = PyErr_NewException(\"zookeeper.\"#x, ZooKeeperException, NULL); \\\n  Py_INCREF(x);                                                         \\\n  PyModule_AddObject(module, #x, x);\n\n#if PY_MAJOR_VERSION >= 3\nPyMODINIT_FUNC PyInit_zookeeper(void) {\n#else\nPyMODINIT_FUNC initzookeeper(void) {\n#endif\n  PyEval_InitThreads();\n\n#if PY_MAJOR_VERSION >= 3\n  PyObject *module = PyModule_Create(&zookeeper_moddef);\n#else\n  PyObject *module = Py_InitModule(\"zookeeper\", ZooKeeperMethods);\n#endif\n  if (init_zhandles(32) == 0) {\n    return; // TODO: Is there any way to raise an exception here?\n  }\n\n  ZooKeeperException = PyErr_NewException(\"zookeeper.ZooKeeperException\",\n                                          PyExc_Exception,\n                                          NULL);\n\n  PyModule_AddObject(module, \"ZooKeeperException\", ZooKeeperException);\n  Py_INCREF(ZooKeeperException);\n\n  int size = 10;\n  char version_str[size];\n  snprintf(version_str, size, \"%i.%i.%i\", ZOO_MAJOR_VERSION, ZOO_MINOR_VERSION, ZOO_PATCH_VERSION);\n\n  PyModule_AddStringConstant(module, \"__version__\", version_str);\n\n  ADD_INTCONSTANT(PERM_READ);\n  ADD_INTCONSTANT(PERM_WRITE);\n  ADD_INTCONSTANT(PERM_CREATE);\n  ADD_INTCONSTANT(PERM_DELETE);\n  ADD_INTCONSTANT(PERM_ALL);\n  ADD_INTCONSTANT(PERM_ADMIN);\n\n  ADD_INTCONSTANT(EPHEMERAL);\n  ADD_INTCONSTANT(SEQUENCE);\n\n  ADD_INTCONSTANT(EXPIRED_SESSION_STATE);\n  ADD_INTCONSTANT(AUTH_FAILED_STATE);\n  ADD_INTCONSTANT(CONNECTING_STATE);\n  ADD_INTCONSTANT(ASSOCIATING_STATE);\n  ADD_INTCONSTANT(CONNECTED_STATE);\n\n  ADD_INTCONSTANT(CREATED_EVENT);\n  ADD_INTCONSTANT(DELETED_EVENT);\n  ADD_INTCONSTANT(CHANGED_EVENT);\n  ADD_INTCONSTANT(CHILD_EVENT);\n  ADD_INTCONSTANT(SESSION_EVENT);\n  ADD_INTCONSTANT(NOTWATCHING_EVENT);\n\n  ADD_INTCONSTANT(LOG_LEVEL_ERROR);\n  ADD_INTCONSTANT(LOG_LEVEL_WARN);\n  ADD_INTCONSTANT(LOG_LEVEL_INFO);\n  ADD_INTCONSTANT(LOG_LEVEL_DEBUG);\n\n  ADD_INTCONSTANTZ(SYSTEMERROR);\n  ADD_INTCONSTANTZ(RUNTIMEINCONSISTENCY);\n  ADD_INTCONSTANTZ(DATAINCONSISTENCY);\n  ADD_INTCONSTANTZ(CONNECTIONLOSS);\n  ADD_INTCONSTANTZ(MARSHALLINGERROR);\n  ADD_INTCONSTANTZ(UNIMPLEMENTED);\n  ADD_INTCONSTANTZ(OPERATIONTIMEOUT);\n  ADD_INTCONSTANTZ(BADARGUMENTS);\n  ADD_INTCONSTANTZ(INVALIDSTATE);\n\n  ADD_EXCEPTION(SystemErrorException);\n  ADD_EXCEPTION(RuntimeInconsistencyException);\n  ADD_EXCEPTION(DataInconsistencyException);\n  ADD_EXCEPTION(ConnectionLossException);\n  ADD_EXCEPTION(MarshallingErrorException);\n  ADD_EXCEPTION(UnimplementedException);\n  ADD_EXCEPTION(OperationTimeoutException);\n  ADD_EXCEPTION(BadArgumentsException);\n  ADD_EXCEPTION(InvalidStateException);  \n\n  ADD_INTCONSTANTZ(OK);  \n  ADD_INTCONSTANTZ(APIERROR);\n  ADD_INTCONSTANTZ(NONODE);\n  ADD_INTCONSTANTZ(NOAUTH);\n  ADD_INTCONSTANTZ(BADVERSION);\n  ADD_INTCONSTANTZ(NOCHILDRENFOREPHEMERALS);\n  ADD_INTCONSTANTZ(NODEEXISTS);\n  ADD_INTCONSTANTZ(NOTEMPTY);\n  ADD_INTCONSTANTZ(SESSIONEXPIRED);\n  ADD_INTCONSTANTZ(INVALIDCALLBACK);\n  ADD_INTCONSTANTZ(INVALIDACL);\n  ADD_INTCONSTANTZ(AUTHFAILED);\n  ADD_INTCONSTANTZ(CLOSING);\n  ADD_INTCONSTANTZ(NOTHING);\n  ADD_INTCONSTANTZ(SESSIONMOVED);\n\n  ADD_EXCEPTION(ApiErrorException);\n  ADD_EXCEPTION(NoNodeException);\n  ADD_EXCEPTION(NoAuthException);\n  ADD_EXCEPTION(BadVersionException);\n  ADD_EXCEPTION(NoChildrenForEphemeralsException);\n  ADD_EXCEPTION(NodeExistsException);\n  ADD_EXCEPTION(NotEmptyException);\n  ADD_EXCEPTION(SessionExpiredException);\n  ADD_EXCEPTION(InvalidCallbackException);\n  ADD_EXCEPTION(InvalidACLException);\n  ADD_EXCEPTION(AuthFailedException);\n  ADD_EXCEPTION(ClosingException);\n  ADD_EXCEPTION(NothingException);\n  ADD_EXCEPTION(SessionMovedException);\n\n#if PY_MAJOR_VERSION >= 3\n  return module;\n#endif\n}\n"
  },
  {
    "path": "src/contrib/zkpython/src/examples/README",
    "content": "\nThis folder contains sample showing how you can use ZooKeeper from Python.\n\nYou should also check the following projects:\n\n* http://github.com/phunt/zk-smoketest\n* http://github.com/henryr/pyzk-recipes \n\n"
  },
  {
    "path": "src/contrib/zkpython/src/examples/watch_znode_for_changes.py",
    "content": "#!/usr/bin/env python2.6\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\" ZNode Change Watcher Skeleton Script\n\nThis script shows you how to write a python program that watches a specific \nznode for changes and reacts to them.\n\nSteps to understand how this script works:\n\n1. start a standalone ZooKeeper server (by default it listens on localhost:2181)\n\nDid you know you can deploy \"local clusters\" by using zkconf[1]? \n[1] http://github.com/phunt/zkconf\n\n2. enter the command line console\n\n3. create the test node:\n    [zk: (CONNECTED) 1] create /watch-test dummy-data \n    Created /watch-test\n\n4. in another shell start this script in verbose mode\n    $ python watch_znode_for_changes.py -v \n\n    # you should see a lot of log messages. have a look over them because\n    # you can easily understand how zookeeper works\n\n5. update the node data:\n\n    [zk: (CONNECTED) 2] set /watch-test new-data \n    cZxid = 0xa0000001a\n    ctime = Fri Jul 09 19:14:45 EEST 2010\n    mZxid = 0xa0000001e\n    mtime = Fri Jul 09 19:18:18 EEST 2010\n    pZxid = 0xa0000001a\n    cversion = 0\n    dataVersion = 1\n    aclVersion = 0\n    ephemeralOwner = 0x0\n    dataLength = 8\n    numChildren = 0\n\n    ... and you should see similar log messages:\n\n    2010-07-09 19:18:18,537:11542(0xb6ea5b70):ZOO_DEBUG@process_completions@1765: Calling a watcher for node [/watch-test], type = -1 event=ZOO_CHANGED_EVENT\n    2010-07-09 19:18:18,537 watch_znode_for_changes.py:83 - Running watcher: zh=0 event=3 state=3 path=/watch-test\n    2010-07-09 19:18:18,537:11542(0xb6ea5b70):ZOO_DEBUG@zoo_awget@2400: Sending request xid=0x4c374b33 for path [/watch-test] to 127.0.0.1:2181\n    2010-07-09 19:18:18,545:11542(0xb76a6b70):ZOO_DEBUG@zookeeper_process@1980: Queueing asynchronous response\n    2010-07-09 19:18:18,545:11542(0xb6ea5b70):ZOO_DEBUG@process_completions@1772: Calling COMPLETION_DATA for xid=0x4c374b33 rc=0\n    2010-07-09 19:18:18,545 watch_znode_for_changes.py:54 - This is where your application does work.\n\n    You can repeat this step multiple times. \n\n6. that's all. in the end you can delete the node and you should see a ZOO_DELETED_EVENT\n\n\"\"\"\n\nimport logging\nimport logging.handlers\nimport signal\nimport sys\nimport time\nimport threading\nimport zookeeper\n\nfrom optparse import OptionParser\n\nlogger = logging.getLogger()\n\nclass MyClass(threading.Thread):\n  znode = '/watch-test'\n\n  def __init__(self, options, args):\n    threading.Thread.__init__(self)\n\n    logger.debug('Initializing MyClass thread.')\n    if options.verbose:\n      zookeeper.set_debug_level(zookeeper.LOG_LEVEL_DEBUG)\n\n    self.zh = zookeeper.init(options.servers)\n    if zookeeper.OK != zookeeper.aget(self.zh, self.znode,\n                                      self.watcher, self.handler):\n      logger.critical('Unable to get znode! Exiting.')\n      sys.exit(1)\n\n  def __del__(self):\n    zookeeper.close(self.zh)\n\n  def aget(self):\n    return zookeeper.aget(self.zh, self.znode, self.watcher, self.handler)\n\n  def handler(self, zh, rc, data, stat):\n    \"\"\"Handle zookeeper.aget() responses.\n\n    This code handles the zookeeper.aget callback. It does not handle watches.\n\n    Numeric arguments map to constants. See ``DATA`` in ``help(zookeeper)``\n    for more information.\n\n    Args:\n      zh Zookeeper handle that made this request.\n      rc Return code.\n      data Data stored in the znode.\n\n    Does not provide a return value.\n    \"\"\"\n    if zookeeper.OK == rc:\n      logger.debug('This is where your application does work.')\n    else:\n      if zookeeper.NONODE == rc:\n        # avoid sending too many requests if the node does not yet exists\n        logger.info('Node not found. Trying again to set the watch.')\n        time.sleep(1)\n \n      if zookeeper.OK != self.aget():\n        logger.critical('Unable to get znode! Exiting.')\n        sys.exit(1)\n\n  def watcher(self, zh, event, state, path):\n    \"\"\"Handle zookeeper.aget() watches.\n\n    This code is called when a znode changes and triggers a data watch.\n    It is not called to handle the zookeeper.aget call itself.\n\n    Numeric arguments map to constants. See ``DATA`` in ``help(zookeeper)``\n    for more information.\n\n    Args:\n      zh Zookeeper handle that set this watch.\n      event Event that caused the watch (often called ``type`` elsewhere).\n      state Connection state.\n      path Znode that triggered this watch.\n\n    Does not provide a return value.\n    \"\"\"\n    out = ['Running watcher:',\n           'zh=%d' % zh,\n           'event=%d' % event,\n           'state=%d' % state,\n           'path=%s' % path]\n    logger.debug(' '.join(out))\n    if event == zookeeper.CHANGED_EVENT and \\\n       state == zookeeper.CONNECTED_STATE and \\\n       self.znode == path:\n      if zookeeper.OK != self.aget():\n        logger.critical('Unable to get znode! Exiting.')\n        sys.exit(1)\n\n  def run(self):\n    while True:\n      time.sleep(86400)\n\n\ndef main(argv=None):\n  # Allow Ctrl-C\n  signal.signal(signal.SIGINT, signal.SIG_DFL)\n\n  parser = OptionParser()\n  parser.add_option('-v', '--verbose',\n    dest='verbose',\n    default=False,\n    action='store_true',\n    help='Verbose logging. (default: %default)')\n  parser.add_option('-s', '--servers',\n    dest='servers',\n    default='localhost:2181',\n    help='Comma-separated list of host:port pairs. (default: %default)')\n\n  (options, args) = parser.parse_args()\n\n  if options.verbose:\n    logger.setLevel(logging.DEBUG)\n  else:\n    logger.setLevel(logging.INFO)\n\n  formatter = logging.Formatter(\"%(asctime)s %(filename)s:%(lineno)d - %(message)s\")\n  stream_handler = logging.StreamHandler()\n  stream_handler.setFormatter(formatter)\n  logger.addHandler(stream_handler)\n\n  logger.info('Starting Zookeeper python example: %s' % ' '.join(sys.argv))\n\n  mc = MyClass(options, args)\n  mc.start()\n  mc.join()\n\n\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/packages/deb/zkpython.control/control",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nPackage: zkpython\nVersion: @version@\nSection: misc\nPriority: optional\nArchitecture: all\nDepends: python\nMaintainer: Apache Software Foundation <dev@zookeeper.apache.org>\nDescription: ZooKeeper python binding library\nDistribution: development\n"
  },
  {
    "path": "src/contrib/zkpython/src/packages/rpm/spec/zkpython.spec",
    "content": "#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n\n#\n# RPM Spec file for ZooKeeper version @version@\n#\n\n%define name         zkpython\n%define version      @version@\n%define release      @package.release@\n\n# Installation Locations\n%define _prefix      @package.prefix@\n\n# Build time settings\n%define _build_dir    @package.build.dir@\n%define _final_name   @final.name@\n%define _python_lib   @python.lib@\n%define debug_package %{nil}\n\n# Disable brp-java-repack-jars for aspect J\n%define __os_install_post    \\\n    /usr/lib/rpm/redhat/brp-compress \\\n    %{!?__debug_package:/usr/lib/rpm/redhat/brp-strip %{__strip}} \\\n    /usr/lib/rpm/redhat/brp-strip-static-archive %{__strip} \\\n    /usr/lib/rpm/redhat/brp-strip-comment-note %{__strip} %{__objdump} \\\n    /usr/lib/rpm/brp-python-bytecompile %{nil}\n\n# RPM searches perl files for dependancies and this breaks for non packaged perl lib\n# like thrift so disable this\n%define _use_internal_dependency_generator 0\n\nSummary: ZooKeeper python binding library\nGroup: Development/Libraries\nLicense: Apache License, Version 2.0\nURL: http://zookeeper.apache.org/\nVendor: Apache Software Foundation\nName: %{name}\nVersion: %{version}\nRelease: %{release} \nSource0: %{_python_lib}\nPrefix: %{_prefix}\nRequires: zookeeper-lib == %{version}\nAutoReqProv: no\nProvides: zkpython\n\n%description\nZooKeeper python binding library\n\n%prep\ntar fxz %{_python_lib} -C %{_build_dir}\n\n%build\n\n#########################\n#### INSTALL SECTION ####\n#########################\n%install\n\n%pre\n\n%post\n\n%preun\n\n%files \n%defattr(-,root,root)\n%{_prefix}\n\n"
  },
  {
    "path": "src/contrib/zkpython/src/python/setup.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom distutils.core import setup, Extension\n\nzookeeper_basedir = \"../../../\"\n\nzookeepermodule = Extension(\"zookeeper\",\n                            sources=[\"src/c/zookeeper.c\"],\n                            include_dirs=[zookeeper_basedir + \"/src/c/include\",\n                                          zookeeper_basedir + \"/build/c\",\n                                          zookeeper_basedir + \"/src/c/generated\"],\n                            libraries=[\"zookeeper_mt\"],\n                            library_dirs=[zookeeper_basedir + \"/src/c/.libs/\",\n                                          zookeeper_basedir + \"/build/c/.libs/\",\n                                          zookeeper_basedir + \"/build/test/test-cppunit/.libs\",\n                                          \"/usr/local/lib\"\n                                          ])\n\nsetup( name=\"ZooKeeper\",\n       version = \"0.4\",\n       description = \"ZooKeeper Python bindings\",\n       ext_modules=[zookeepermodule] )\n"
  },
  {
    "path": "src/contrib/zkpython/src/python/zk.py",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, time, threading\n\nf = open(\"out.log\",\"w\")\nzookeeper.set_log_stream(f)\n\nconnected = False\nconn_cv = threading.Condition( )\n\ndef my_connection_watcher(handle,type,state,path):\n    global connected, conn_cv\n    print(\"Connected, handle is \", handle)\n    conn_cv.acquire()\n    connected = True\n    conn_cv.notifyAll()\n    conn_cv.release()\n    \nconn_cv.acquire()\nprint(\"Connecting to localhost:2181 -- \")\nhandle = zookeeper.init(\"localhost:2181\", my_connection_watcher, 10000, 0)\nwhile not connected:\n    conn_cv.wait()\nconn_cv.release()\n\ndef my_getc_watch( handle, type, state, path ):\n    print(\"Watch fired -- \")\n    print(type, state, path)\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"};\n\ntry:\n    zookeeper.create(handle, \"/zk-python\", \"data\", [ZOO_OPEN_ACL_UNSAFE], 0)\n    zookeeper.get_children(handle, \"/zk-python\", my_getc_watch)\n    for i in xrange(5):\n        print(\"Creating sequence node \", i, \" \", zookeeper.create(handle, \"/zk-python/sequencenode\", \"data\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.SEQUENCE ))\nexcept:\n    pass\n\ndef pp_zk(handle,root, indent = 0):\n    \"\"\"Pretty print(a zookeeper tree, starting at root)\"\"\"\n    def make_path(child):\n        if root == \"/\":\n            return \"/\" + child\n        return root + \"/\" + child\n    children = zookeeper.get_children(handle, root, None)\n    out = \"\"\n    for i in xrange(indent):\n        out += \"\\t\"\n    out += \"|---\"+root + \" :: \" + zookeeper.get(handle, root, None)[0]\n    print(out)\n    for child in children:\n        pp_zk(handle,make_path(child),indent+1)\n\nprint(\"ZNode tree -- \")\npp_zk(handle,\"/\")\n\nprint(\"Getting ACL / Stat for /zk-python --\")\n(stat, acl) =  zookeeper.get_acl(handle, \"/zk-python\")\nprint(\"Stat:: \", stat)\nprint(\"Acl:: \", acl)\n\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/acl_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":zookeeper.PERM_ALL, \"scheme\":\"world\", \"id\" :\"anyone\"}\nZOO_ACL_READ = {\"perms\":zookeeper.PERM_READ, \"scheme\": \"world\",\n                \"id\":\"anyone\"}\nclass ACLTest(zktestbase.TestBase):\n    \"\"\"Test whether basic ACL setting and getting work correctly\"\"\"\n    # to do: startup and teardown via scripts?\n    def setUp(self):\n      zktestbase.TestBase.setUp(self)\n      try:\n        zookeeper.delete(self.handle, \"/zk-python-acltest\")\n        zookeeper.delete(self.handle, \"/zk-python-aacltest\")\n      except:\n        pass\n\n    def test_sync_acl(self):\n      self.assertEqual(self.connected, True)\n      ret = zookeeper.create(self.handle, \"/zk-python-acltest\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n      acls = zookeeper.get_acl(self.handle, \"/zk-python-acltest\")\n      self.assertEqual(acls[1], [ZOO_OPEN_ACL_UNSAFE])\n      self.assertRaises(zookeeper.InvalidACLException,zookeeper.set_acl,self.handle, \"/zk-python-acltest\", -1, ZOO_ACL_READ)\n      zookeeper.set_acl(self.handle, \"/zk-python-acltest\", -1, [ZOO_ACL_READ])\n      acls = zookeeper.get_acl(self.handle, \"/zk-python-acltest\")\n      self.assertEqual(acls[1], [ZOO_ACL_READ])\n\n\n    def test_async_acl(self):\n      self.cv = threading.Condition()\n      self.cv = threading.Condition()\n      def aget_callback(handle, rc, acl, stat):\n        self.cv.acquire()\n        self.callback_flag = True\n        self.rc = rc\n        self.acl = acl\n        self.stat = stat\n        self.cv.notify()\n        self.cv.release()\n\n      def aset_callback(handle, rc):\n        self.cv.acquire()\n        self.callback_flag = True\n        self.rc = rc\n        self.cv.notify()\n        self.cv.release()\n\n      self.assertEqual(self.connected, True, \"Not connected!\")\n      ret = zookeeper.create(self.handle, \"/zk-python-aacltest\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n\n      self.cv.acquire()\n      zookeeper.aget_acl(self.handle, \"/zk-python-aacltest\", aget_callback)\n      self.cv.wait(15)\n      self.cv.release()\n\n      self.assertEqual(self.callback_flag, True, \"aget_acl timed out\")\n      self.assertEqual(self.rc, zookeeper.OK, \"aget failed\")\n      self.assertEqual(self.acl, [ZOO_OPEN_ACL_UNSAFE], \"Wrong ACL returned from aget\")\n\n      self.cv.acquire()\n      self.callback_flag = False\n      zookeeper.aset_acl(self.handle, \"/zk-python-aacltest\", -1, [ZOO_ACL_READ], aset_callback)\n      self.cv.wait(15)\n      self.cv.release()\n\n      self.assertEqual(self.callback_flag, True, \"aset_acl timed out\")\n      self.assertEqual(self.rc, zookeeper.OK, \"aset failed\")\n      acls = zookeeper.get_acl(self.handle, \"/zk-python-aacltest\")\n      self.assertEqual(acls[1], [ZOO_ACL_READ], \"Wrong ACL returned from get when aset\")\n\n    def test_invalid_acl(self):\n      self.assertRaises(zookeeper.InvalidACLException,\n                        zookeeper.create,\n                        self.handle,\n                        \"/zk-python-aclverifytest\",\n                        \"\",\n                        None,\n                        zookeeper.EPHEMERAL)\n      \n    def test_invalid_acl2(self):\n      \"\"\"Verify all required keys are present in the ACL.\"\"\"\n      invalid_acl = [{\"schema\": \"digest\", \"id\": \"zebra\"}]\n      self.assertRaises(zookeeper.InvalidACLException,\n                        zookeeper.create,\n                        self.handle,\n                        \"/zk-python-aclverifytest\",\n                        \"\",\n                        invalid_acl,\n                        zookeeper.EPHEMERAL)\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/async_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\n\nclass AsyncTest(zktestbase.TestBase):\n    \"\"\"Test whether async works\"\"\"\n    # to do: startup and teardown via scripts?\n    def setUp( self ):\n        zktestbase.TestBase.setUp(self)\n\n    def test_async(self):\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.async(self.handle, \"/\")\n        self.assertEqual(ret, zookeeper.OK, \"async failed\")\n        \nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/callback_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading, gc\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n\nclass CallbackTest(zktestbase.TestBase):\n    \"\"\"\n    Test whether callbacks (watchers/completions) are correctly invoked\n    \"\"\"\n    # to do: startup and teardown via scripts?\n    def setUp(self):\n        zktestbase.TestBase.setUp(self)\n        self.cv = threading.Condition()\n\n    def create_callback(self, callback):\n        \"\"\"\n        Returns a callable which signals cv and then calls callback\n        \"\"\"\n        def wrapper(*args, **kwargs):\n            self.cv.acquire()\n            callback(*args, **kwargs)\n            self.cv.notify()\n            self.cv.release()\n        return wrapper\n\n    def test_none_callback(self):\n        \"\"\"\n        Test that no errors are raised when None is passed as a callback.\n        \"\"\"\n        self.ensureCreated(\"/zk-python-none-callback-test\",\"test\")\n        # To do this we need to issue two operations, waiting on the second\n        # to ensure that the first completes\n        zookeeper.get(self.handle, \"/zk-python-none-callback-test\", None)\n        (d,s) = zookeeper.get(self.handle, \"/zk-python-none-callback-test\")\n        self.assertEqual(d, \"test\")\n\n    def callback_harness(self, trigger, test):\n        self.callback_flag = False\n        self.cv.acquire()\n        trigger()\n        self.cv.wait(15)\n        test()\n\n    def test_dispatch_types(self):\n        \"\"\"\n        Test all the various dispatch mechanisms internal to the module.\n        \"\"\"\n        def dispatch_callback(*args, **kwargs):\n            self.callback_flag = True\n        self.ensureCreated(\"/zk-python-dispatch-test\")\n        self.callback_harness( lambda: zookeeper.adelete(self.handle,\n                                                            \"/zk-python-dispatch-test\",\n                                                            -1,\n                                                            self.create_callback(dispatch_callback)),\n                                  lambda: self.assertEqual(True, self.callback_flag, \"Void dispatch not fired\"))\n\n\n        self.ensureCreated(\"/zk-python-dispatch-test\")\n        self.callback_harness( lambda: zookeeper.aexists(self.handle,\n                                                         \"/zk-python-dispatch-test\",\n                                                         None,\n                                                         self.create_callback(dispatch_callback)),\n                               lambda: self.assertEqual(True, self.callback_flag, \"Stat dispatch not fired\"))\n\n        self.callback_harness( lambda: zookeeper.aget(self.handle,\n                                                      \"/zk-python-dispatch-test\",\n                                                      None,\n                                                      self.create_callback(dispatch_callback)),\n                               lambda: self.assertEqual(True, self.callback_flag, \"Data dispatch not fired\"))\n\n        self.callback_harness( lambda: zookeeper.aget_children(self.handle,\n                                                               \"/\",\n                                                               None,\n                                                               self.create_callback( dispatch_callback )),\n                               lambda: self.assertEqual(True, self.callback_flag, \"Strings dispatch not fired\"))\n\n        self.callback_harness( lambda: zookeeper.async(self.handle,\n                                                       \"/\",\n                                                       self.create_callback( dispatch_callback )),\n                               lambda: self.assertEqual(True, self.callback_flag, \"String dispatch not fired\"))\n\n        self.callback_harness( lambda: zookeeper.aget_acl(self.handle,\n                                                          \"/\",\n                                                          self.create_callback( dispatch_callback )),\n                               lambda: self.assertEqual(True, self.callback_flag, \"ACL dispatch not fired\"))\n\n    def test_multiple_watchers(self):\n        \"\"\"\n        Test whether multiple watchers are correctly called\n        \"\"\"\n        cv1, cv2 = threading.Condition(), threading.Condition()\n        def watcher1(*args, **kwargs):\n            cv1.acquire()\n            self.watcher1 = True\n            cv1.notify()\n            cv1.release()\n\n        def watcher2(*args, **kwargs):\n            cv2.acquire()\n            self.watcher2 = True\n            cv2.notify()\n            cv2.release()\n\n        nodename = \"/zk-python-multiple-watcher-test\"\n        self.ensureCreated(nodename, \"test\")\n        cv1.acquire()\n        cv2.acquire()\n        zookeeper.get(self.handle, nodename, watcher1)\n        zookeeper.get(self.handle, nodename, watcher2)\n        zookeeper.set(self.handle, nodename, \"test\")\n        cv1.wait(15)\n        cv2.wait(15)\n        self.assertTrue(self.watcher1 and self.watcher2, \"One or more watchers failed to fire\")\n\n    def test_lose_scope(self):\n        \"\"\"\n        The idea is to test that the reference counting doesn't\n        fail when we retain no references outside of the module\n        \"\"\"\n        self.ensureDeleted(\"/zk-python-lose-scope-test\")\n        self.ensureCreated(\"/zk-python-lose-scope-test\")\n        def set_watcher():\n            def fn(): self.callback_flag = True\n            self.callback_flag = False\n            zookeeper.exists(self.handle, \"/zk-python-lose-scope-test\",\n                             self.create_callback( lambda handle, type, state, path: fn() )\n                             )\n\n        set_watcher()\n        gc.collect()\n        self.cv.acquire()\n        zookeeper.set(self.handle, \"/zk-python-lose-scope-test\", \"test\")\n        self.cv.wait(15)\n        self.assertEqual(self.callback_flag, True)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/clientid_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport unittest, threading\n\nimport zookeeper, zktestbase\n\nclass ClientidTest(zktestbase.TestBase):\n    \"\"\"Test whether clientids work\"\"\"\n    def setUp(self):\n        pass\n            \n    def testclientid(self):\n        cv = threading.Condition()\n        self.connected = False\n        def connection_watcher(handle, type, state, path):\n            cv.acquire()\n            self.connected = True\n            cv.notify()\n            cv.release()\n\n        cv.acquire()\n        self.handle = zookeeper.init(self.host, connection_watcher,10000,(123456,\"mypassword\"))\n        self.assertEqual(self.handle, zookeeper.OK)\n        cv.wait(15.0)\n        cv.release()\n        self.assertEqual(self.connected, True, \"Connection timed out to \" + self.host)\n        (cid,passwd) = zookeeper.client_id(self.handle)\n        self.assertEqual(cid,123456)\n        self.assertEqual(passwd,\"mypassword\")   \n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/close_deadlock_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\nimport time\n\n\nclass CloseDeadlockTest(zktestbase.TestBase):\n  \"\"\"\n  This tests for the issue found in\n  https://issues.apache.org/jira/browse/ZOOKEEPER-763\n\n  zookeeper.close blocks on waiting for all completions to\n  finish. Previously it was doing so while holding teh GIL, stopping\n  any completions from actually continuing.\n\n  This test is a failure if it does not exit within a few seconds.\n  \"\"\"\n  def deadlock():\n    cv = threading.Condition()\n\n    def callback(*args):\n        cv.acquire()\n        cv.notifyAll()\n        cv.release()\n        time.sleep(1)\n\n    cv.acquire()\n    zookeeper.aget(handle, \"/\", None, callback)\n    cv.wait()\n    zookeeper.close(handle)\n\n\nif __name__ == '__main__':\n  unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/connection_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport unittest, threading, re, sys\nif sys.version_info < (3,):\n\trange = xrange\n\nimport zookeeper, zktestbase\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n\nclass ConnectionTest(zktestbase.TestBase):\n    \"\"\"Test whether we can make a connection\"\"\"\n    def setUp(self):\n        pass\n\n    def testconnection(self):\n        cv = threading.Condition()\n        self.connected = False\n        def connection_watcher(handle, type, state, path):\n            cv.acquire()\n            self.connected = True\n            self.assertEqual(zookeeper.CONNECTED_STATE, state)\n            self.handle = handle\n            cv.notify()\n            cv.release()\n\n        cv.acquire()\n        ret = zookeeper.init(self.host, connection_watcher)\n        cv.wait(15.0)\n        cv.release()\n        self.assertEqual(self.connected, True, \"Connection timed out to \" + self.host)\n        self.assertEqual(zookeeper.CONNECTED_STATE, zookeeper.state(self.handle))\n\n        self.assertEqual(zookeeper.close(self.handle), zookeeper.OK)\n        # Trying to close the same handle twice is an error, and the C library will segfault on it\n        # so make sure this is caught at the Python module layer\n        self.assertRaises(zookeeper.ZooKeeperException,\n                          zookeeper.close,\n                          self.handle)\n\n        self.assertRaises(zookeeper.ZooKeeperException,\n                          zookeeper.get,\n                          self.handle,\n                          \"/\")\n\n    def testhandlereuse(self):\n        \"\"\"\n        Test a) multiple concurrent connections b) reuse of closed handles\n        \"\"\"\n        cv = threading.Condition()\n        self.connected = False\n        def connection_watcher(handle, type, state, path):\n            cv.acquire()\n            self.connected = True\n            self.assertEqual(zookeeper.CONNECTED_STATE, state)\n            self.handle = handle\n            cv.notify()\n            cv.release()\n\n        cv.acquire()\n        handles = [ zookeeper.init(self.host) for i in range(10) ]\n        ret = zookeeper.init(self.host, connection_watcher)\n        cv.wait(15.0)\n        cv.release()\n        self.assertEqual(self.connected, True, \"Connection timed out to \" + self.host)\n        self.assertEqual(True, self.all( [ zookeeper.state(handle) == zookeeper.CONNECTED_STATE for handle in handles ] ),\n                         \"Not all connections succeeded\")\n        oldhandle = handles[3]\n        zookeeper.close(oldhandle)\n        newhandle = zookeeper.init(self.host)\n\n        # This assertion tests *internal* behaviour; i.e. that the module\n        # correctly reuses closed handles. This is therefore implementation\n        # dependent.\n        self.assertEqual(newhandle, oldhandle, \"Didn't get reused handle\")\n\n    def testmanyhandles(self):\n        \"\"\"\n        Test the ability of the module to support many handles.\n        \"\"\"\n        # We'd like to do more, but currently the C client doesn't\n        # work with > 83 handles (fails to create a pipe) on MacOS 10.5.8\n        handles = [ zookeeper.init(self.host) for i in range(9) ]\n\n        cv = threading.Condition()\n        self.connected = False\n        def connection_watcher(handle, type, state, path):\n            cv.acquire()\n            self.connected = True\n            self.assertEqual(zookeeper.CONNECTED_STATE, state)\n            self.handle = handle\n            cv.notify()\n            cv.release()\n\n        cv.acquire()\n        ret = zookeeper.init(self.host, connection_watcher)\n        cv.wait(15.0)\n        cv.release()\n        self.assertEqual(self.connected, True, \"Connection timed out to \" + self.host)\n\n        for i,h in enumerate(handles):\n            path = \"/zkpython-test-handles-%s\" % str(i)\n            self.assertEqual(path, zookeeper.create(h, path, \"\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL))\n\n        self.assertEqual(True, self.all( zookeeper.close(h) == zookeeper.OK for h in handles ))\n\n    def testversionstringexists(self):\n        self.assertTrue(hasattr(zookeeper, '__version__'))\n        self.assertTrue(re.match(\"\\d.\\d.\\d\", zookeeper.__version__))\n\n\n    def tearDown(self):\n        pass\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/create_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n\nclass CreationTest(zktestbase.TestBase):\n    \"\"\"Test whether we can create znodes\"\"\"\n    # to do: startup and teardown via scripts?\n    def setUp(self):\n        zktestbase.TestBase.setUp(self)\n        try:\n            zookeeper.delete(self.handle, \"/zk-python-createtest\")\n            zookeeper.delete(self.handle, \"/zk-python-acreatetest\")\n        except:\n            pass\n\n    def test_sync_create(self):\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.create(self.handle, \"/zk-python-createtest\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n        self.assertEqual(ret, \"/zk-python-createtest\")\n        self.assertRaises(zookeeper.NoChildrenForEphemeralsException,\n                          zookeeper.create,\n                          self.handle,\n                          \"/zk-python-createtest/invalid-child\",\n                          \"\",\n                          [ZOO_OPEN_ACL_UNSAFE],\n                          zookeeper.EPHEMERAL)\n\n    def test_sync_create_existing(self):\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.create(self.handle, \"/zk-python-createtest-existing\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n        self.assertEqual(ret, \"/zk-python-createtest-existing\")\n\n        self.assertRaises(zookeeper.NodeExistsException,\n                          zookeeper.create,\n                          self.handle,\n                          \"/zk-python-createtest-existing\",\n                          \"nodecontents\",\n                          [ZOO_OPEN_ACL_UNSAFE],\n                          zookeeper.EPHEMERAL)\n\n\n    def test_exception_paths(self):\n        \"\"\"\n        Make sure common exceptions due to API misuse are correctly propogated\n        \"\"\"\n        self.assertRaises(zookeeper.BadArgumentsException,\n                          zookeeper.create,\n                          self.handle,\n                          \"/zk-python-badargs-test\",\n                          \"\",\n                          [ZOO_OPEN_ACL_UNSAFE],\n                          -1)\n        self.assertRaises(zookeeper.InvalidACLException,\n                          zookeeper.create,\n                          self.handle,\n                          \"/zk-python-invalidacl-test\",\n                          \"\",\n                          ZOO_OPEN_ACL_UNSAFE) # Error - not a list\n\n\n    def test_async_create(self):\n        self.cv = threading.Condition()\n        def callback(handle, rc, value):\n            self.cv.acquire()\n            self.callback_flag = True\n            self.rc = rc\n            self.cv.notify()\n            self.cv.release()\n\n        self.assertEqual(self.connected, True, \"Not connected!\")\n        self.cv.acquire()\n\n        ret = zookeeper.acreate(self.handle, \"/zk-python-acreatetest\", \"nodecontents\",\n                                [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL,\n                                callback )\n        self.assertEqual(ret, zookeeper.OK, \"acreate failed\")\n        while not self.callback_flag:\n            self.cv.wait(15)\n        self.cv.release()\n\n        self.assertEqual(self.callback_flag, True, \"acreate timed out\")\n        self.assertEqual(self.rc, zookeeper.OK)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/delete_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\n\nclass DeletionTest(zktestbase.TestBase):\n    \"\"\"Test whether we can delete znodes\"\"\"\n\n    def test_sync_delete(self):\n        ZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.create(self.handle, \"/zk-python-deletetest\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n        self.assertEqual(ret, \"/zk-python-deletetest\")\n        ret = zookeeper.delete(self.handle,\"/zk-python-deletetest\")\n        self.assertEqual(ret, zookeeper.OK)\n        children = zookeeper.get_children(self.handle, \"/\")\n        self.assertEqual(False, \"zk-python-deletetest\" in children)\n\n        # test exception\n        self.assertRaises(zookeeper.NoNodeException,\n                          zookeeper.delete,\n                          self.handle,\n                          \"/zk-python-deletetest\")\n\n    def test_async_delete(self):\n        ZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.create(self.handle, \"/zk-python-adeletetest\", \"nodecontents\", [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n        self.assertEqual(ret, \"/zk-python-adeletetest\")\n\n        self.cv = threading.Condition()\n        self.callback_flag = False\n        self.rc = -1\n        def callback(handle, rc):\n            self.cv.acquire()\n            self.callback_flag = True\n            self.cv.notify()\n            self.rc = rc # don't assert this here, as if the assertion fails, the test will block\n            self.cv.release()\n\n        self.cv.acquire()\n        ret = zookeeper.adelete(self.handle,\"/zk-python-adeletetest\",-1,callback)\n        self.assertEqual(ret, zookeeper.OK, \"adelete failed\")\n        while not self.callback_flag:\n            self.cv.wait(15)\n        self.cv.release()\n\n        self.assertEqual(self.callback_flag, True, \"adelete timed out\")\n        self.assertEqual(self.rc, zookeeper.OK)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/exists_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\nclass ExistsTest(zktestbase.TestBase):\n    def setUp( self ):\n        zktestbase.TestBase.setUp(self)\n        try:\n            zookeeper.create(self.handle, \"/zk-python-existstest\",\"existstest\", [ZOO_OPEN_ACL_UNSAFE],zookeeper.EPHEMERAL)\n            zookeeper.create(self.handle, \"/zk-python-aexiststest\",\"existstest\",[ZOO_OPEN_ACL_UNSAFE],zookeeper.EPHEMERAL)\n        except:\n            pass\n\n    def test_sync_exists(self):\n        self.assertEqual(self.connected, True)\n        ret = zookeeper.exists(self.handle, \"/zk-python-existstest\", None)\n        self.assertNotEqual(ret, None, \"/zk-python-existstest does not exist (possibly means creation failure)\")\n\n    def test_sync_nexists(self):\n        self.assertEqual(None, zookeeper.exists(self.handle, \"/i-dont-exist\", None))\n\n\n    def test_async_exists(self):\n        self.cv = threading.Condition()\n        def callback(handle, rc, stat):\n            self.cv.acquire()\n            self.callback_flag = True\n            self.cv.notify()\n            self.cv.release()\n            self.rc = rc\n\n        self.assertEqual(self.connected, True)\n\n        self.cv.acquire()\n        ret = zookeeper.aexists(self.handle, \"/zk-python-aexiststest\", None,\n                                callback )\n        self.assertEqual(ret, zookeeper.OK)\n        while not self.callback_flag:\n            self.cv.wait(15)\n        self.cv.release()\n\n        self.assertEqual(self.callback_flag, True, \"aexists timed out\")\n        self.assertEqual(self.rc, zookeeper.OK, \"Return code not ok:\" + zookeeper.zerror(self.rc))\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/get_set_test.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport zookeeper, zktestbase, unittest, threading, sys\nif sys.version_info < (3,):\n\trange = xrange\n\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n\nclass GetSetTest(zktestbase.TestBase):\n    def setUp( self ):\n        zktestbase.TestBase.setUp(self)\n        try:\n            zookeeper.create(self.handle, \"/zk-python-getsettest\", \"on\",[ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n            zookeeper.create(self.handle, \"/zk-python-agetsettest\",\n                             \"on\",[ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERAL)\n        except:\n            pass\n\n    def test_empty_node(self):\n        \"\"\"\n        Test for a bug when instead of empty string we can get\n        random data from buffer malloc'ed to hold node contents.\n        See ZOOKEEPER-1906 for details\n        \"\"\"\n        NODE_PATH = \"/zk-python-test-empty-node\"\n        self.ensureDeleted(NODE_PATH)\n        zookeeper.create(self.handle, NODE_PATH, \"\",\n                         [{\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}])\n        (data,stat) = zookeeper.get(self.handle, NODE_PATH, None)\n        self.assertEqual(data, \"\", \"Data is not empty as expected: \" + data)\n\n    def test_sync_getset(self):\n        self.assertEqual(self.connected, True, \"Not connected!\")\n        (data,stat) = zookeeper.get(self.handle, \"/zk-python-getsettest\", None)\n        self.assertEqual(data, \"on\", \"Data is not 'on' as expected: \" + data)\n        ret = zookeeper.set(self.handle, \"/zk-python-getsettest\",\n                            \"off\", stat[\"version\"])\n        (data,stat) = zookeeper.get(self.handle, \"/zk-python-getsettest\", None)\n        self.assertEqual(data, \"off\", \"Data is not 'off' as expected: \" + data)\n        self.assertRaises(zookeeper.BadVersionException,\n                          zookeeper.set,\n                          self.handle,\n                          \"/zk-python-getsettest\",\n                          \"test\",\n                          stat[\"version\"]+1)\n        stat2 = zookeeper.set2(self.handle, \"/zk-python-getsettest\",\n                               \"set2\", stat[\"version\"])\n        self.assertNotEqual(stat2, None, \"set2 call failed, return should not be None\")\n        self.assertEqual(stat2[\"numChildren\"], 0,\n                         \"set2 call failed, numChildren not 0 in set2 call\")\n        (data,stat) = zookeeper.get(self.handle, \"/zk-python-getsettest\", None)\n        self.assertEqual(data, \"set2\", \"Data is not 'set2' as expected: \" + data)\n\n    def test_stat_deleted_node(self):\n        \"\"\"\n        Test for a bug that surfaced when trying to build a\n        stat object from a non-existant node.\n\n        \"\"\"\n        self.ensureDeleted(\"/zk-python-test-deleteme\")\n        self.assertRaises(zookeeper.NoNodeException,\n                          zookeeper.get,\n                          self.handle,\n                          \"/zk-python-test-deleteme\")\n        self.cv = threading.Condition()\n        def callback(handle, rc, value, stat):\n            self.cv.acquire()\n            self.stat = stat\n            self.rc = rc\n            self.value = value\n            self.callback_flag = True\n            self.cv.notify()\n            self.cv.release()\n        self.cv.acquire()\n        zookeeper.aget(self.handle, \"/zk-python-test-deleteme\", None, callback)\n        self.cv.wait(15)\n        self.assertEqual(self.callback_flag, True, \"aget timed out!\")\n        self.assertEqual(self.stat, None, \"Stat should be none!\")\n        self.assertEqual(self.value, None, \"Value should be none!\")\n\n    def test_sync_get_large_datanode(self):\n        \"\"\"\n        Test that we can retrieve datanode sizes up to\n        1Mb with default parameters (depends on ZooKeeper server).\n        \"\"\"\n\n        data = ''.join([\"A\" for x in range(1024*1023)])\n        self.ensureDeleted(\"/zk-python-test-large-datanode\")\n        zookeeper.create(self.handle, \"/zk-python-test-large-datanode\", data,\n                         [{\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}])\n        (ret,stat) = zookeeper.get(self.handle, \"/zk-python-test-large-datanode\")\n        self.assertEqual(len(ret), 1024*1023,\n                         \"Should have got 1Mb returned, instead got %s\" % len(ret))\n        (ret,stat) = zookeeper.get(self.handle, \"/zk-python-test-large-datanode\",None,500)\n        self.assertEqual(len(ret), 500,\n                         \"Should have got 500 bytes returned, instead got %s\" % len(ret))\n\n\n\n    def test_async_getset(self):\n        self.cv = threading.Condition()\n        def get_callback(handle, rc, value, stat):\n            self.cv.acquire()\n            self.callback_flag = True\n            self.rc = rc\n            self.value = (value,stat)\n            self.cv.notify()\n            self.cv.release()\n\n        def set_callback(handle, rc, stat):\n            self.cv.acquire()\n            self.callback_flag = True\n            self.rc = rc\n            self.value = stat\n            self.cv.notify()\n            self.cv.release()\n\n        self.assertEqual(self.connected, True, \"Not connected!\")\n\n        self.cv.acquire()\n        self.callback_flag = False\n        ret = zookeeper.aset(self.handle, \"/zk-python-agetsettest\", \"off\", -1, set_callback)\n        self.assertEqual(ret, zookeeper.OK, \"aset failed\")\n        while not self.callback_flag:\n            self.cv.wait(15)\n        self.cv.release()\n        self.assertEqual(self.callback_flag, True, \"aset timed out\")\n\n        self.cv.acquire()\n        self.callback_flag = False\n        ret = zookeeper.aget(self.handle, \"/zk-python-agetsettest\", None, get_callback)\n        self.assertEqual(ret, zookeeper.OK, \"aget failed\")\n        self.cv.wait(15)\n        self.cv.release()\n        self.assertEqual(self.callback_flag, True, \"aget timed out\")\n        self.assertEqual(self.value[0], \"off\", \"Data is not 'off' as expected: \" + self.value[0])\n\n    def test_sync_getchildren(self):\n        self.ensureCreated(\"/zk-python-getchildrentest\", flags=0)\n        self.ensureCreated(\"/zk-python-getchildrentest/child\")\n        children = zookeeper.get_children(self.handle, \"/zk-python-getchildrentest\")\n        self.assertEqual(len(children), 1, \"Expected to find 1 child, got \" + str(len(children)))\n\n    def test_async_getchildren(self):\n        self.ensureCreated(\"/zk-python-getchildrentest\", flags=0)\n        self.ensureCreated(\"/zk-python-getchildrentest/child\")\n\n        def gc_callback(handle, rc, children):\n            self.cv.acquire()\n            self.rc = rc\n            self.children = children\n            self.callback_flag = True\n            self.cv.notify()\n            self.cv.release()\n\n        self.cv.acquire()\n        self.callback_flag = False\n        zookeeper.aget_children(self.handle, \"/zk-python-getchildrentest\", None, gc_callback)\n        self.cv.wait(15)\n        self.assertEqual(self.callback_flag, True, \"aget_children timed out\")\n        self.assertEqual(self.rc, zookeeper.OK, \"Return code for aget_children was not OK - %s\" % zookeeper.zerror(self.rc))\n        self.assertEqual(len(self.children), 1, \"Expected to find 1 child, got \" + str(len(self.children)))\n\n\n    def test_async_getchildren_with_watcher(self):\n        self.ensureCreated(\"/zk-python-getchildrentest\", flags=0)\n        self.ensureCreated(\"/zk-python-getchildrentest/child\")\n\n        watched = []\n\n        def watcher(*args):\n            self.cv.acquire()\n            watched.append(args)\n            self.cv.notify()\n            self.cv.release()\n\n        def children_callback(*args):\n            self.cv.acquire()\n            self.cv.notify()\n            self.cv.release()\n\n        zookeeper.aget_children(\n            self.handle, \"/zk-python-getchildrentest\", watcher, children_callback)\n\n        self.cv.acquire()\n        self.cv.wait()\n        self.cv.release()\n\n        self.cv.acquire()\n        self.ensureCreated(\"/zk-python-getchildrentest/child2\")\n        self.cv.wait(15)\n        self.assertTrue(watched)\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/run_tests.sh",
    "content": "#!/bin/sh\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Usage: run_tests.sh testdir [logdir]\n# logdir is optional, defaults to cwd\n\n# get the number of command-line arguments given\nARGC=$#\n\n# check to make sure enough arguments were given or exit\nif [ $ARGC -lt 2 ]; then\n    export ZKPY_LOG_DIR=\".\"\nelse\n    export ZKPY_LOG_DIR=$2\nfi\n\n# Find the build directory containing zookeeper.so\nSO_PATH=`find ../../../build/ -name \"zookeeper.so\" | head -1`\nPYTHONPATH=`dirname $SO_PATH`\nLIB_PATH=../../c/.libs/:../../../build/test/test-cppunit/.libs\nfor test in `ls $1/*_test.py`; \ndo\n    echo \"Running $test\"\n    LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH PYTHONPATH=$PYTHONPATH python $test\ndone\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/zkServer.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nif [ \"x$1\" == \"x\" ]\nthen\n    echo \"USAGE: $0 startClean|start|stop hostPorts\"\n    exit 2\nfi\n\nif [ \"x$1\" == \"xstartClean\" ]\nthen\n    if [ \"x${base_dir}\" == \"x\" ]\n    then\n    rm -rf /tmp/zkdata\n    else\n    rm -rf ${base_dir}/build/tmp\n    fi\nfi\n\nif [ \"x${base_dir}\" == \"x\" ]\t\nthen\nzk_base=\"../../../\"\nelse\nzk_base=\"${base_dir}\"\nfi\n\nCLASSPATH=\"$CLASSPATH:${zk_base}/build/classes\"\nCLASSPATH=\"$CLASSPATH:${zk_base}/conf\"\n\nfor i in \"${zk_base}\"/build/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nfor i in \"${zk_base}\"/src/java/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\n# Make sure nothing is left over from before\n#fuser -skn tcp 22182/tcp\n\ncase $1 in\nstart|startClean)\n    if [ \"x${base_dir}\" == \"x\" ]\n        then\n        mkdir -p /tmp/zkdata\n        java -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22182 /tmp/zkdata &> /tmp/zk.log &\n        else\n        mkdir -p ${base_dir}/build/tmp/zkdata\n        java -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22182 ${base_dir}/build/tmp/zkdata &> ${base_dir}/build/tmp/zk.log &\n    fi\n        sleep 5\n    ;;\nstop)\n    # Already killed above\n    ;;\n*)\n    echo \"Unknown command \" + $1\n    exit 2\nesac\n\n"
  },
  {
    "path": "src/contrib/zkpython/src/test/zktestbase.py",
    "content": "#!/usr/bin/python\n#\n#  Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n\n#     http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport unittest, threading, zookeeper\nZOO_OPEN_ACL_UNSAFE = {\"perms\":0x1f, \"scheme\":\"world\", \"id\" :\"anyone\"}\n\nclass TestBase(unittest.TestCase):\n    SERVER_PORT = 22182\n    \n    def __init__(self,methodName='runTest'):\n        unittest.TestCase.__init__(self,methodName)\n        self.host = \"localhost:%d\" % self.SERVER_PORT\n        self.connected = False\n        self.handle = -1\n        logdir = os.environ.get(\"ZKPY_LOG_DIR\")\n        logfile = os.path.join(logdir, self.__class__.__name__ + \".log\")\n        try:\n            f = open(logfile,\"w\")\n            zookeeper.set_log_stream(f)\n        except IOError:\n            print(\"Couldn't open \" + logfile + \" for writing\")\n\n\n    def setUp(self):\n        self.callback_flag = False\n        self.cv = threading.Condition()\n        self.connected = False\n        def connection_watcher(handle, type, state, path):\n            self.cv.acquire()\n            self.connected = True\n            self.cv.notify()\n            self.cv.release()\n\n        self.cv.acquire()\n        self.handle = zookeeper.init(self.host, connection_watcher)\n        self.cv.wait(15.0)\n        self.cv.release()\n\n        if not self.connected:\n            raise Exception(\"Couldn't connect to host -\", self.host)\n\n    def newConnection(self):\n        cv = threading.Condition()\n        self.pending_connection = False\n        def connection_watcher(handle, type, state, path):\n            cv.acquire()\n            self.pending_connection = True\n            cv.notify()\n            cv.release()\n\n        cv.acquire()\n        handle = zookeeper.init(self.host, connection_watcher)\n        cv.wait(15.0)\n        cv.release()\n\n        if not self.pending_connection:\n            raise Exception(\"Couldn't connect to host -\", self.host)\n        return handle\n\n    def ensureDeleted(self,path):\n        self.assertEqual(zookeeper.CONNECTED_STATE, zookeeper.state(self.handle), \"Not connected!\")\n        try:\n            self.assertEqual(zookeeper.OK, zookeeper.delete(self.handle, path))\n        except zookeeper.NoNodeException:\n            pass\n\n    def ensureCreated(self,path,data=\"\",flags=zookeeper.EPHEMERAL):\n        \"\"\"\n        It's possible not to get the flags you want here if the node already exists\n        \"\"\"\n        self.assertEqual(zookeeper.CONNECTED_STATE, zookeeper.state(self.handle), \"Not connected!\")\n        try:\n            self.assertEqual(path, zookeeper.create(self.handle, path, data, [ZOO_OPEN_ACL_UNSAFE], flags))\n        except zookeeper.NodeExistsException:\n            pass\n\n    def tearDown(self):\n        if self.connected:\n            zookeeper.close(self.handle)\n\n    def all(self, iterable):\n        for element in iterable:\n            if not element:\n                return False\n        return True\n"
  },
  {
    "path": "src/contrib/zktreeutil/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in\n\nSUBDIRS = src\n\n"
  },
  {
    "path": "src/contrib/zktreeutil/README.txt",
    "content": "==========================================\nzktreeutil - Zookeeper Tree Data Utility\nAuthor: Anirban Roy\nOrganization: Yahoo Inc.\n==========================================\n\nzktreeutil program is intended to manage and manipulate zk-tree data quickly, effi-\nciently and with ease. The utility operates on free-form ZK-tree and hence can be used\nfor any cluster managed by Zookeeper. Here are the basic functionalities -\n\nEXPORT: The whole/partial ZK-tree is exported into a XML file. This helps in\ncapturing a current snapshot of the data for backup/analysis. For a subtree\nexport, one need to specify the path to the ZK-subtree with proper option.\n\nIMPORT: The ZK-tree can be imported from XML into ZK cluster. This helps in priming\nthe new ZK cluster with static configuration. The import can be non-intrusive by\nmaking only the additions in the existing data. The import of subtree is also\npossible by optionally providing the path to the ZK-subtree.\n\nDIFF: Creates a diff between live ZK data vs data saved in XML file. Diff can ignore\nsome ZK-tree branches (possibly dynamic data) on reading the optional ignore flag\nfrom XML file. Diffing on a ZK-subtree achieved by providing path to ZK-subtree with\ndiff command.\n\nUPDATE: Make the incremental changes into the live ZK-tree from saved XML, essentia-\nlly after running the diff.\n\nDUMP: Dumps the ZK-tree on the standard output device reading either from live ZK\nserver or XML file. Like export, ZK-subtree can be dumped with optionaly\nproviding the path to the ZK-subtree, and till a certain depth of the (sub)tree.\n\nThe exported ZK data into XML file can be shortened by only keeping the static ZK\nnodes which are required to prime a cluster. The dynamic zk nodes (created on-the-\nfly) can be ignored by setting a 'ignore' attribute at the root node of the dynamic\nsubtree (see tests/zk_sample.xml), possibly deleting all inner ZK nodes under that.\nOnce ignored, the whole subtree is ignored during DIFF, UPDATE and WRITE.\n\nPre-requisites\n--------------\n1. Linux system with 2.6.X kernel.\n2. Zookeeper C client library (locally built at ../../c/.libs) >= 3.X.X\n3. Development build libraries (rpm packages):\n  a. boost-devel >= 1.32.0\n  b. libxml2-devel >= 2.7.3\n  c. log4cxx0100-devel >= 0.10.0\n\nBuild instructions\n------------------\n1. cd into this directory\n2. autoreconf -if\n3. ./configure\n4. make\n5. 'zktreeutil' binary created under src directory\n\nLimitations\n-----------\nCurrent version works with text data only, binary data will be supported in future\nversions.\n\nTesting  and usage of zktreeutil\n--------------------------------\n1.  Run Zookeeper server locally on port 2181\n2.  export LD_LIBRARY_PATH=../../c/.libs/:/usr/local/lib/\n3.  ./src/zktreeutil --help # show help\n4.  ./src/zktreeutil --zookeeper=localhost:2181 --import --xmlfile=tests/zk_sample.xml 2>/dev/null                 # import sample ZK tree\n5.  ./src/zktreeutil --zookeeper=localhost:2181 --dump --path=/myapp/version-1.0 2>/dev/null                         # dump Zk subtree \n5.  ./src/zktreeutil --zookeeper=localhost:2181 --dump --depth=3 2>/dev/null                                                 # dump Zk tree till certain depth\n6.  ./src/zktreeutil --xmlfile=zk_sample.xml -D 2>/dev/null                                                                     # dump the xml data\n7.  Change zk_sample.xml with adding/deleting/chaging some nodes \n8.  ./src/zktreeutil -z localhost:2181 -F -x zk_sample.xml -p /myapp/version-1.0/configuration 2>/dev/null          # take a diff of changes\n9.  ./src/zktreeutil -z localhost:2181 -E 2>/dev/null > zk_sample2.xml                                                         # export the mofied ZK tree\n10. ./src/zktreeutil -z localhost:2181 -U -x zk_sample.xml -p /myapp/version-1.0/distributions 2>/dev/null        # update with incr. changes\n11. ./src/zktreeutil --zookeeper=localhost:2181 --import --force --xmlfile=zk_sample2.xml 2>/dev/null             # re-prime the ZK tree\n\n"
  },
  {
    "path": "src/contrib/zktreeutil/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zktreeutil\" default=\"compile\">\n  <import file=\"../build-contrib.xml\"/>\n\n  <target name=\"init\" depends=\"check-contrib\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <antcall target=\"init-contrib\"/>\n  </target>\n\n  <target name=\"compile\" depends=\"init\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${build.dir}\"/>\n    <copy todir=\"${build.dir}\">\n      <fileset dir=\"${basedir}\">\n        <exclude name=\"**/VERSION\"/>\n      </fileset>\n    </copy>\n    <exec executable=\"echo\" output=\"${build.dir}/VERSION\">\n      <arg line=\"${version}\" />\n    </exec>\n  </target>\n\n    <target name=\"jar\" depends=\"compile\" >\n        <echo message=\"No jar target defined for this package\"/>\n    </target>\n\n     <target name=\"test\">\n        <echo message=\"No test target defined for this package\" />\n    </target>\n\n\n  <target name=\"package\" depends=\"compile\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/contrib/${name}\"/>\n    <copy todir=\"${dist.dir}/contrib/${name}\">\n      <fileset dir=\"${build.dir}\"/>\n    </copy>\n  </target>\n\n</project>\n"
  },
  {
    "path": "src/contrib/zktreeutil/configure.ac",
    "content": "#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ(2.59)\n\nAC_INIT([zktreeutil], [1.0.0])\nAM_INIT_AUTOMAKE(foreign)\n\nAC_CONFIG_SRCDIR([src])\nAM_CONFIG_HEADER([config.h])\n\nPACKAGE=zktreeutil\nVERSION=1.0.0\n\nAC_SUBST(PACKAGE)\nAC_SUBST(VERSION)\nBUILD_PATH=\"`pwd`\"\n\n# Checks for programs.\nAC_LANG_CPLUSPLUS\nAC_PROG_CXX\n\n# Checks for libxm2.\nAM_PATH_XML2(2.7.3)\nXML2_INCLUDE=\"/usr/include/libxml2\"\nAC_SUBST(XML2_INCLUDE)\n\n# Zookeeper C client\nZOOKEEPER_PATH=${BUILD_PATH}/../../c\nAC_CHECK_LIB(zookeeper_mt, main, [ZOOKEEPER=\"-L${ZOOKEEPER_PATH}/.libs -lzookeeper_mt\"],,[\"-L${ZOOKEEPER_PATH}/.libs\"])\nif test -z \"${ZOOKEEPER}\"; then\n      AC_ERROR(\"... zookeeper C client not found!\")\nfi\n\nAC_SUBST(ZOOKEEPER)\nAC_SUBST(ZOOKEEPER_PATH)\n\n### log4cxx ###\n\nLOG4CXX_VERSION=\"0.10.0\"\nLOG4CXX_INCLUDE=\"/usr/local/include\"\nLOG4CXX_LIB_PATH=\"/usr/local/lib\"\nAC_CHECK_LIB(log4cxx, main, [LOG4CXX=\"-L${LOG4CXX_LIB_PATH} -llog4cxx\"],,[\"-L${LOG4CXX_LIB_PATH}\"])\nif test -z \"${LOG4CXX}\"; then\n      AC_ERROR(\"... log4cxx not found!\")\nfi\n\nAC_SUBST(LOG4CXX)\nAC_SUBST(LOG4CXX_VERSION)\nAC_SUBST(LOG4CXX_INCLUDE)\n\n# Checks for header files.\nAC_HEADER_DIRENT\nAC_HEADER_STDC\nAC_CHECK_HEADERS([stdlib.h string.h stdio.h unistd.h boost/shared_ptr.hpp boost/algorithm/string.hpp boost/algorithm/string/split.hpp])\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_HEADER_STDBOOL\nAC_C_CONST\nAC_C_INLINE\nAC_TYPE_SIZE_T\nAC_C_VOLATILE\n\nAC_CONFIG_FILES([Makefile])\nAC_CONFIG_FILES([src/Makefile])\nAC_OUTPUT\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/Makefile.am",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nAM_CXXFLAGS = -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated \\\n    -I$(top_srcdir)/include -I${LOG4CXX_INCLUDE} -I/usr/include \\\n      -I${XML2_INCLUDE}\n\nbin_PROGRAMS = zktreeutil\n\nzktreeutil_SOURCES = ZkAdaptor.cc ZkTreeUtil.cc ZkTreeUtilMain.cc\nzktreeutil_LDADD = ${ZOOKEEPER} ${XML_LIBS} ${LOG4CXX}\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/SimpleTree.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __SIMPLE_TREE_H__\n#define __SIMPLE_TREE_H__\n\n#include <vector>\n#include <boost/shared_ptr.hpp>\n\nnamespace zktreeutil\n{\n   using std::vector;\n\n   /**\n    * \\brief A simple tree data-structure template.\n    */\n   template < class KeyType, class DataType > class SimpleTreeNode\n   {\n      private:\n         /**\n          * \\brief The type representing simple-tree node smart-pointer.\n          */\n         typedef boost::shared_ptr< SimpleTreeNode< KeyType, DataType > > SimpleTreeNodeSptr;\n\n      public:\n         /**\n          * \\brief Constructor.\n          * \n          * @param isRoot the flag indicating whether the node is root.\n          */\n         SimpleTreeNode (bool isRoot=false) : isRoot_(isRoot)\n         {\n         }\n\n         /**\n          * \\brief Constructor.\n          * \n          * @param key the key stored at the tree node\n          * @param isRoot the flag indicating whether the node is root\n          */\n         SimpleTreeNode (const KeyType& key, bool isRoot=false) :\n            isRoot_(isRoot), key_(key)\n         {\n         }\n\n         /**\n          * \\brief Constructor.\n          * \n          * @param key the key stored at the tree node\n          * @param val the value stored at the tree node\n          * @param isRoot the flag indicating whether the node is root\n          */\n         SimpleTreeNode (const KeyType& key, const DataType& val, bool isRoot=false) :\n            isRoot_(isRoot), key_(key), val_(val)\n         {\n         }\n\n         /**\n          * \\brief Destructor.\n          */\n         ~SimpleTreeNode () throw() {}\n\n         /**\n          * \\brief Add a child node to this node.\n          *\n          * @param node the child node to be added\n          */\n         void addChild (const SimpleTreeNodeSptr node) { children_.push_back (node); }\n\n         /**\n          * \\brief Sets the key of this node.\n          *\n          * @param key the key to be set\n          */\n         void setKey (const KeyType& key) { key_ = key; }\n\n         /**\n          * \\brief Sets the data of this node.\n          *\n          * @param val the value to be set\n          */\n         void setData (const DataType& val) { val_ = val; }\n\n         /**\n          * \\brief Gets the key of this node.\n          *\n          * @return the key of this node \n          */\n         KeyType getKey () const { return key_; }\n\n         /**\n          * \\brief Gets the data of this node.\n          *\n          * @return the value of this node \n          */\n         DataType getData () const { return val_; }\n\n         /**\n          * \\brief Gets the i'th of this node.\n          *\n          * @param idx the index of the child node\n          * @return the child node\n          */\n         SimpleTreeNodeSptr getChild (unsigned idx) const { return children_[idx]; }\n\n         /**\n          * \\brief Gets the number of children of this node.\n          *\n          * @return the number of children\n          */\n         unsigned numChildren () const { return children_.size(); }\n\n         /**\n          * \\brief Indicates whether this node is root.\n          *\n          * @return 'true' if this node is root, 'false' otherwise\n          */\n         bool isRoot () const { return isRoot_; }\n\n         /**\n          * \\brief Indicates whether this node is leaf node.\n          *\n          * @return 'true' if this node is leaf node, 'false' otherwise\n          */\n         bool isLeaf () const { return !numChildren(); }\n\n      private:\n         bool isRoot_;                                        // Flag indicates if the node is root\n         KeyType key_;                                        // Key of this node\n         DataType val_;                                        // Value of this node\n         vector< SimpleTreeNodeSptr > children_;    // List of children of this node\n   };\n}\n\n#endif // __SIMPLE_TREE_H__\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/ZkAdaptor.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ZkAdaptor.h\"\n#include <string.h>\n#include <sstream>\n#include <iostream>\n#include <algorithm>\n#include <log4cxx/logger.h>\n\n// Logger\nstatic log4cxx::LoggerPtr zkLoggerPtr = log4cxx::Logger::getLogger (\"zookeeper.core\");\n\nnamespace zktreeutil\n{\n    /**\n     * \\brief This class provides logic for checking if a request can be retried.\n     */\n    class RetryHandler\n    {\n        public:\n            RetryHandler(const ZooKeeperConfig &zkConfig) : m_zkConfig(zkConfig)\n            {\n                if (zkConfig.getAutoReconnect())\n                    retries = 2;\n                else\n                    retries = 0;\n            }\n\n            /**\n             * \\brief Attempts to fix a side effect of the given RC.\n             * \n             * @param rc the ZK error code\n             * @return whether the error code has been handled and the caller should \n             *         retry an operation the caused this error\n             */\n            bool handleRC(int rc)\n            {\n                //check if the given error code is recoverable\n                if (!retryOnError(rc))\n                    return false;\n\n                std::cerr << \"[zktreeuti] Number of retries left: \" << retries << std::endl;\n                if (retries-- > 0)\n                    return true;\n                else\n                    return false;\n            }\n\n        private:\n            /**\n             * The ZK config.\n             */\n            const ZooKeeperConfig &m_zkConfig;\n\n            /**\n             * The number of outstanding retries.\n             */\n            int retries;    \n\n            /**\n             * Checks whether the given error entitles this adapter\n             * to retry the previous operation.\n             * \n             * @param zkErrorCode one of the ZK error code\n             */\n            static bool retryOnError(int zkErrorCode)\n            {\n                return (zkErrorCode == ZCONNECTIONLOSS || zkErrorCode == ZOPERATIONTIMEOUT);\n            }\n    };\n\n\n    // =======================================================================\n\n    ZooKeeperAdapter::ZooKeeperAdapter(ZooKeeperConfig config) throw(ZooKeeperException) :\n        m_zkConfig(config),\n        mp_zkHandle(NULL)\n    {\n        // Enforce setting up appropriate ZK log level\n        if (zkLoggerPtr->isDebugEnabled()\n#ifdef LOG4CXX_TRACE\n                || zkLoggerPtr->isTraceEnabled()\n#endif\n            ) \n        {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_DEBUG );\n        } else if (zkLoggerPtr->isInfoEnabled()) {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_INFO );\n        } else if (zkLoggerPtr->isWarnEnabled()) {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_WARN );\n        } else {\n            zoo_set_debug_level( ZOO_LOG_LEVEL_ERROR );\n        }\n\n        // Establish the connection\n        reconnect();\n    }\n\n    ZooKeeperAdapter::~ZooKeeperAdapter()\n    {\n        try\n        {\n            disconnect();\n        }\n        catch (std::exception &e)\n        {\n            std::cerr << \"[zktreeutil] An exception while disconnecting from ZK: \"\n                << e.what()\n                << std::endl;\n        }\n    }\n\n    void ZooKeeperAdapter::validatePath(const string &path) throw(ZooKeeperException)\n    {\n        if (path.find (\"/\") != 0)\n        {\n            std::ostringstream oss;\n            oss << \"Node path must start with '/' but\" \"it was '\"\n                << path\n                << \"'\";\n            throw ZooKeeperException (oss.str());\n        }\n        if (path.length() > 1)\n        {\n            if (path.rfind (\"/\") == path.length() - 1)\n            {\n                std::ostringstream oss;\n                oss << \"Node path must not end with '/' but it was '\"\n                    << path\n                    << \"'\";\n                throw ZooKeeperException (oss.str());\n            }\n            if (path.find( \"//\" ) != string::npos)\n            {\n                std::ostringstream oss;\n                oss << \"Node path must not contain '//' but it was '\"\n                    << path\n                    << \"'\";\n                throw ZooKeeperException (oss.str());\n            }\n        }\n    }\n\n    void ZooKeeperAdapter::disconnect()\n    {\n        if (mp_zkHandle != NULL)\n        {\n            zookeeper_close (mp_zkHandle);\n            mp_zkHandle = NULL;\n        }\n    }\n\n    void ZooKeeperAdapter::reconnect() throw(ZooKeeperException)\n    {\n        // Clear the connection state\n        disconnect();\n\n        // Establish a new connection to ZooKeeper\n        mp_zkHandle = zookeeper_init( m_zkConfig.getHosts().c_str(), \n                NULL, \n                m_zkConfig.getLeaseTimeout(),\n                0,\n                NULL,\n                0);\n        if (mp_zkHandle == NULL)\n        {\n            // Invalid handle returned\n            std::ostringstream oss;\n            oss << \"Unable to connect to ZK running at '\"\n                << m_zkConfig.getHosts()\n                << \"'\";\n            throw ZooKeeperException (oss.str());\n        }\n\n        // Enter into connect loop\n        int64_t connWaitTime = m_zkConfig.getConnectTimeout();\n        while (1)\n        {\n            int state = zoo_state (mp_zkHandle);\n            if (state == ZOO_CONNECTED_STATE)\n            {\n                // connected\n                std::cerr << \"[zktreeutil] Connected! mp_zkHandle: \"\n                    << mp_zkHandle\n                    << std::endl; \n                return;\n            }\n            else if ( state && state != ZOO_CONNECTING_STATE)\n            {\n                // Not connecting any more... some other issue\n                std::ostringstream oss;\n                oss << \"Unable to connect to ZK running at '\"\n                    << m_zkConfig.getHosts()\n                    << \"'; state=\"\n                    << state;\n                throw ZooKeeperException (oss.str());\n            }\n\n            // Still connecting, wait and come back\n            struct timeval now;\n            gettimeofday( &now, NULL );\n            int64_t milliSecs = -(now.tv_sec * 1000LL + now.tv_usec / 1000);\n            std::cerr << \"[zktreeutil] About to wait 1 sec\" << std::endl;\n            sleep (1);\n            gettimeofday( &now, NULL );\n            milliSecs += now.tv_sec * 1000LL + now.tv_usec / 1000;\n            connWaitTime -= milliSecs;\n            // Timed out !!!\n            if (connWaitTime <= 0)\n                break;\n        }\n\n        // Timed out while connecting\n        std::ostringstream oss;\n        oss << \"Timed out while connecting to ZK running at '\"\n            << m_zkConfig.getHosts()\n            << \"'\";\n        throw ZooKeeperException (oss.str());\n    }\n\n    void ZooKeeperAdapter::verifyConnection() throw(ZooKeeperException)\n    {\n        // Check connection state\n        int state = zoo_state (mp_zkHandle);\n        if (state != ZOO_CONNECTED_STATE)\n        {\n            if (m_zkConfig.getAutoReconnect())\n            {\n                // Trying to reconnect\n                std::cerr << \"[zktreeutil] Trying to reconnect...\" << std::endl;\n                reconnect();\n            }\n            else\n            {\n                std::ostringstream oss;\n                oss << \"Disconnected from ZK running at '\"\n                    << m_zkConfig.getHosts()\n                    << \"'; state=\"\n                    << state;\n                throw ZooKeeperException (oss.str());\n            }\n        }\n    }\n\n    bool ZooKeeperAdapter::createNode(const string &path, \n            const string &value, \n            int flags, \n            bool createAncestors) throw(ZooKeeperException) \n    {\n        const int MAX_PATH_LENGTH = 1024;\n        char realPath[MAX_PATH_LENGTH];\n        realPath[0] = 0;\n\n        int rc;\n        RetryHandler rh(m_zkConfig);\n        do\n        {\n            verifyConnection();\n            rc = zoo_create( mp_zkHandle, \n                    path.c_str(), \n                    value.c_str(),\n                    value.length(),\n                    &ZOO_OPEN_ACL_UNSAFE,\n                    flags,\n                    realPath,\n                    MAX_PATH_LENGTH );\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK) // check return status\n        {\n            if (rc == ZNODEEXISTS)\n            {\n                //the node already exists\n                std::cerr << \"[zktreeutil] ZK node \" << path << \" already exists\" << std::endl;\n                return false;\n            }\n            else if (rc == ZNONODE && createAncestors)\n            {\n                std::cerr << \"[zktreeutil] Intermediate ZK node missing in path \" << path << std::endl;\n                //one of the ancestors doesn't exist so lets start from the root \n                //and make sure the whole path exists, creating missing nodes if\n                //necessary\n                for (string::size_type pos = 1; pos != string::npos; )\n                {\n                    pos = path.find( \"/\", pos );\n                    if (pos != string::npos)\n                    {\n                        try\n                        {\n                            createNode( path.substr( 0, pos ), \"\", 0, true );\n                        }\n                        catch (ZooKeeperException &e)\n                        {\n                            throw ZooKeeperException( string(\"Unable to create \" \"node \") + path, rc );\n                        }\n                        pos++;\n                    }\n                    else\n                    {\n                        // No more path components\n                        return createNode( path, value, flags, false );\n                    }\n                }\n            }\n\n            // Unexpected error during create\n            std::cerr << \"[zktreeutil] Error in creating ZK node \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to create node \") + path, rc );\n        }\n\n        // Success\n        std::cerr << \"[zktreeutil] \" << realPath << \" has been created\" << std::endl;\n        return true;\n    }\n\n    bool ZooKeeperAdapter::deleteNode(const string &path,\n            bool recursive,\n            int version) throw(ZooKeeperException)\n    {\n        // Validate the zk path\n        validatePath( path );\n\n        int rc;\n        RetryHandler rh(m_zkConfig);\n        do\n        {\n            verifyConnection();\n            rc = zoo_delete( mp_zkHandle, path.c_str(), version );\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK) //check return status\n        {\n            if (rc == ZNONODE)\n            {\n                std::cerr << \"[zktreeutil] ZK Node \"\n                    << path\n                    << \" does not exist\"\n                    << std::endl;\n                return false;\n            }\n            if (rc == ZNOTEMPTY && recursive)\n            {\n                std::cerr << \"[zktreeutil] ZK Node \"\n                    << path\n                    << \" not empty; deleting...\"\n                    << std::endl;\n                //get all children and delete them recursively...\n                vector<string> nodeList = getNodeChildren (path);\n                for (vector<string>::const_iterator i = nodeList.begin();\n                        i != nodeList.end();\n                        ++i) {\n                    deleteNode( *i, true );\n                }\n                //...and finally attempt to delete the node again\n                return deleteNode( path, false ); \n            }\n\n            // Unexpected return without success\n            std::cerr << \"[zktreeutil] Unable to delete ZK node \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to delete node \") + path, rc );\n        }\n\n        // success\n        std::cerr << \"[zktreeutil] \" << path << \" has been deleted\" << std::endl;\n        return true;\n    }\n\n    vector< string > ZooKeeperAdapter::getNodeChildren (const string &path) throw (ZooKeeperException)\n    {\n        // Validate the zk path\n        validatePath( path );\n\n        String_vector children;\n        memset( &children, 0, sizeof(children) );\n        int rc;\n        RetryHandler rh(m_zkConfig);\n        do\n        {\n            verifyConnection();\n            rc = zoo_get_children( mp_zkHandle,\n                    path.c_str(), \n                    0,\n                    &children );\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK) // check return code\n        {\n            std::cerr << \"[zktreeutil] Error in fetching children of \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to get children of node \") + path, rc );\n        }\n        else\n        {\n            vector< string > nodeList;\n            for (int i = 0; i < children.count; ++i)\n            {\n                //convert each child's path from relative to absolute \n                string absPath(path);\n                if (path != \"/\")\n                {\n                    absPath.append( \"/\" );\n                } \n                absPath.append( children.data[i] ); \n                nodeList.push_back( absPath );\n            }\n\n            //make sure the order is always deterministic\n            sort( nodeList.begin(), nodeList.end() );\n            return nodeList;\n        }\n    }\n\n    bool ZooKeeperAdapter::nodeExists(const string &path) throw(ZooKeeperException)\n    {\n        // Validate the zk path\n        validatePath( path );\n\n        struct Stat tmpStat;\n        struct Stat* stat = &tmpStat;\n        memset( stat, 0, sizeof(Stat) );\n\n        int rc;\n        RetryHandler rh(m_zkConfig);\n        do {\n            verifyConnection();\n            rc = zoo_exists( mp_zkHandle,\n                    path.c_str(),\n                    0,\n                    stat );\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK)\n        {\n            if (rc == ZNONODE)\n                return false;\n            // Some error\n            std::cerr << \"[zktreeutil] Error in checking existence of \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to check existence of node \") + path, rc );\n        } else {\n            return true;        \n        }\n    }\n\n    string ZooKeeperAdapter::getNodeData(const string &path) throw(ZooKeeperException)\n    {\n        // Validate the zk path\n        validatePath( path );\n\n        const int MAX_DATA_LENGTH = 128 * 1024;\n        char buffer[MAX_DATA_LENGTH];\n        memset( buffer, 0, MAX_DATA_LENGTH );\n        struct Stat tmpStat;\n        struct Stat* stat = &tmpStat;\n        memset( stat, 0, sizeof(Stat) );\n\n        int rc;\n        int len;\n        RetryHandler rh(m_zkConfig);\n        do {\n            verifyConnection();\n            len = MAX_DATA_LENGTH - 1;\n            rc = zoo_get( mp_zkHandle,\n                    path.c_str(),\n                    0,\n                    buffer, &len, stat );\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK) // checl return code\n        {\n            std::cerr << \"[zktreeutil] Error in fetching value of \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to get data of node \") + path, rc );\n        }\n\n        // return data\n        return string( buffer, buffer + len );\n    }\n\n    void ZooKeeperAdapter::setNodeData(const string &path,\n            const string &value,\n            int version) throw(ZooKeeperException)\n    {\n        // Validate the zk path\n        validatePath( path );\n\n        int rc;\n        RetryHandler rh(m_zkConfig);\n        do {\n            verifyConnection();\n            rc = zoo_set( mp_zkHandle,\n                    path.c_str(),\n                    value.c_str(),\n                    value.length(),\n                    version);\n        } while (rc != ZOK && rh.handleRC(rc));\n        if (rc != ZOK) // check return code\n        {\n            std::cerr << \"[zktreeutil] Error in setting value of \" << path << std::endl;\n            throw ZooKeeperException( string(\"Unable to set data for node \") + path, rc );\n        }\n        // success\n    }\n\n}   /* end of 'namespace zktreeutil' */\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/ZkAdaptor.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __ZK_ADAPTER_H__\n#define __ZK_ADAPTER_H__\n\n#include <string>\n#include <vector>\n\nextern \"C\" {\n#include \"zookeeper.h\"\n}\n\nnamespace zktreeutil\n{\n    using std::string;\n    using std::vector;\n\n    /**\n     * \\brief A cluster related exception.\n     */\n    class ZooKeeperException : public std::exception\n    {\n        public:\n\n            /**\n             * \\brief Constructor.\n             * \n             * @param msg the detailed message associated with this exception\n             */\n            ZooKeeperException(const string& msg) :\n                m_message(msg),\n                m_zkErrorCode(0) {}\n\n            /**\n             * \\brief Constructor.\n             * \n             * @param msg the detailed message associated with this exception\n             * @param errorCode the ZK error code associated with this exception\n             */\n            ZooKeeperException(const string &msg, int errorCode) : \n                m_zkErrorCode(errorCode) \n            {\n                char tmp[100];\n                sprintf( tmp, \" (ZK error code: %d)\", errorCode );\n                m_message = msg + tmp;\n            }\n\n            /**\n             * \\brief Destructor.\n             */\n            ~ZooKeeperException() throw() {}\n\n            /**\n             * \\brief Returns detailed description of the exception.\n             */\n            const char *what() const throw()\n            {\n                return m_message.c_str();\n            }\n\n            /**\n             * \\brief Returns the ZK error code.\n             */\n            int getZKErrorCode() const\n            {\n                return m_zkErrorCode;\n            }\n\n        private:\n\n            /**\n             * The detailed message associated with this exception.\n             */\n            string m_message;\n\n            /**\n             * The optional error code received from ZK.\n             */\n            int m_zkErrorCode;\n\n    };\n\n    /**\n     * \\brief This class encapsulates configuration of a ZK client.\n     */\n    class ZooKeeperConfig\n    {\n        public:\n\n            /**\n             * \\brief Constructor.\n             * \n             * @param hosts the comma separated list of host and port pairs of ZK nodes\n             * @param leaseTimeout the lease timeout (heartbeat)\n             * @param autoReconnect whether to allow for auto-reconnect\n             * @param connectTimeout the connect timeout, in milliseconds;\n             */\n            ZooKeeperConfig(const string &hosts, \n                    int leaseTimeout, \n                    bool autoReconnect = true, \n                    long long int connectTimeout = 15000)\n                : m_hosts(hosts),\n                m_leaseTimeout(leaseTimeout), \n                m_autoReconnect(autoReconnect),\n                m_connectTimeout(connectTimeout) {}\n\n            /**\n             * \\brief Returns the list of ZK hosts to connect to.\n             */\n            string getHosts() const { return m_hosts; }\n\n            /**\n             * \\brief Returns the lease timeout.\n             */\n            int getLeaseTimeout() const { return m_leaseTimeout; }\n\n            /**\n             * \\brief Returns whether {@link ZooKeeperAdapter} should attempt \n             * \\brief to automatically reconnect in case of a connection failure.\n             */\n            bool getAutoReconnect() const { return m_autoReconnect; }\n\n            /**\n             * \\brief Gets the connect timeout.\n             * \n             * @return the connect timeout\n             */\n            long long int getConnectTimeout() const { return m_connectTimeout; }\n\n        private:\n\n            /**\n             * The host addresses of ZK nodes.\n             */\n            const string m_hosts;\n\n            /**\n             * The ZK lease timeout.\n             */\n            const int m_leaseTimeout;\n\n            /**\n             * True if this adapater should attempt to autoreconnect in case \n             * the current session has been dropped.\n             */\n            const bool m_autoReconnect;\n\n            /**\n             * How long to wait, in milliseconds, before a connection \n             * is established to ZK.\n             */\n            const long long int m_connectTimeout;\n    };\n\n    /**\n     * \\brief This is a wrapper around ZK C synchrounous API.\n     */\n    class ZooKeeperAdapter\n    {\n        public:\n            /**\n             * \\brief Constructor.\n             * Attempts to create a ZK adapter, optionally connecting\n             * to the ZK. Note, that if the connection is to be established\n             * and the given listener is NULL, some events may be lost, \n             * as they may arrive asynchronously before this method finishes.\n             * \n             * @param config the ZK configuration\n             * @throw ZooKeeperException if cannot establish connection to the given ZK\n             */\n            ZooKeeperAdapter(ZooKeeperConfig config) throw(ZooKeeperException);\n\n            /**\n             * \\brief Destructor.\n             */\n            ~ZooKeeperAdapter(); \n\n            /**\n             * \\brief Returns the current config.\n             */\n            const ZooKeeperConfig &getZooKeeperConfig() const { return m_zkConfig; }\n\n            /**\n             * \\brief Restablishes connection to the ZK. \n             * If this adapter is already connected, the current connection \n             * will be dropped and a new connection will be established.\n             * \n             * @throw ZooKeeperException if cannot establish connection to the ZK\n             */\n            void reconnect() throw(ZooKeeperException);\n\n            /**\n             * \\brief Disconnects from the ZK and unregisters {@link #mp_zkHandle}.\n             */\n            void disconnect();\n\n            /**\n             * \\brief Creates a new node identified by the given path. \n             * This method will optionally attempt to create all missing ancestors.\n             * \n             * @param path the absolute path name of the node to be created\n             * @param value the initial value to be associated with the node\n             * @param flags the ZK flags of the node to be created\n             * @param createAncestors if true and there are some missing ancestor nodes, \n             *        this method will attempt to create them\n             * \n             * @return true if the node has been successfully created; false otherwise\n             * @throw ZooKeeperException if the operation has failed\n             */ \n            bool createNode(const string &path, \n                    const string &value = \"\", \n                    int flags = 0, \n                    bool createAncestors = true) throw(ZooKeeperException);\n\n            /**\n             * \\brief Deletes a node identified by the given path.\n             * \n             * @param path the absolute path name of the node to be deleted\n             * @param recursive if true this method will attempt to remove \n             *                  all children of the given node if any exist\n             * @param version the expected version of the node. The function will \n             *                fail if the actual version of the node does not match \n             *                the expected version\n             * \n             * @return true if the node has been deleted; false otherwise\n             * @throw ZooKeeperException if the operation has failed\n             */\n            bool deleteNode(const string &path,\n                    bool recursive = false,\n                    int version = -1) throw(ZooKeeperException);\n\n            /**\n             * \\brief Retrieves list of all children of the given node.\n             * \n             * @param path the absolute path name of the node for which to get children\n             * @return the list of absolute paths of child nodes, possibly empty\n             * @throw ZooKeeperException if the operation has failed\n             */\n            vector<string> getNodeChildren( const string &path) throw(ZooKeeperException);\n\n            /**\n             * \\brief Check the existence of path to a znode.\n             * \n             * @param path the absolute path name of the znode\n             * @return TRUE if the znode exists; FALSE otherwise\n             * @throw ZooKeeperException if the operation has failed\n             */\n            bool nodeExists(const string &path) throw(ZooKeeperException);\n\n            /**\n             * \\brief Gets the given node's data.\n             * \n             * @param path the absolute path name of the node to get data from\n             * \n             * @return the node's data\n             * @throw ZooKeeperException if the operation has failed\n             */\n            string getNodeData(const string &path) throw(ZooKeeperException);\n\n            /**\n             * \\brief Sets the given node's data.\n             * \n             * @param path the absolute path name of the node to get data from\n             * @param value the node's data to be set\n             * @param version the expected version of the node. The function will \n             *                fail if the actual version of the node does not match \n             *                the expected version\n             * \n             * @throw ZooKeeperException if the operation has failed\n             */\n            void setNodeData(const string &path,\n                    const string &value,\n                    int version = -1) throw(ZooKeeperException);\n\n            /**\n             * \\brief Validates the given path to a node in ZK.\n             * \n             * @param the path to be validated\n             * \n             * @throw ZooKeeperException if the given path is not valid\n             *        (for instance it doesn't start with \"/\")\n             */\n            static void validatePath(const string &path) throw(ZooKeeperException);\n\n        private:\n\n            /**\n             * Verifies whether the connection is established,\n             * optionally auto reconnecting.\n             * \n             * @throw ZooKeeperConnection if this client is disconnected\n             *        and auto-reconnect failed or was not allowed\n             */\n            void verifyConnection() throw(ZooKeeperException);\n\n        private:\n\n            /**\n             * The current ZK configuration.\n             */\n            const ZooKeeperConfig m_zkConfig;\n\n            /**\n             * The current ZK session.\n             */\n            zhandle_t *mp_zkHandle;\n    };\n\n}   /* end of 'namespace zktreeutil' */\n\n#endif /* __ZK_ADAPTER_H__ */\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/ZkTreeUtil.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ZkTreeUtil.h\"\n\n#include <map>\n#include <iostream>\n#include <log4cxx/logger.h>\n#include <boost/algorithm/string.hpp>\n#include <boost/algorithm/string/split.hpp>\n\nnamespace zktreeutil\n{\n    using std::map;\n    using std::pair;\n\n    static ZkTreeNodeSptr loadZkTree_ (ZooKeeperAdapterSptr zkHandle,\n            const string& path)\n    {\n        // Extract the node value\n        string value = zkHandle->getNodeData(path);\n\n        // Extract nodename from the path\n        string nodename = \"/\";\n        if (path != \"/\")\n        {\n            vector< string > nodes;\n            boost::split(nodes, path, boost::is_any_of (\"/\") );\n            nodename = nodes[nodes.size()-1];\n        }\n\n        // Create tree-node with name and value\n        ZkTreeNodeSptr nodeSptr = ZkTreeNodeSptr (new ZkTreeNode (nodename, value));\n        std::cerr << \"[zktreeutil] loaded nodename: \"\n            << nodename\n            << \" value: \"\n            << value\n            << std::endl;\n\n        // Load all the children\n        vector< string > cnodes = zkHandle->getNodeChildren (path);\n        for (unsigned i = 0; i < cnodes.size(); i++)\n            nodeSptr->addChild (loadZkTree_ (zkHandle, cnodes[i]));\n\n        // Return the constructed node\n        return nodeSptr;\n    }\n\n    static ZkTreeNodeSptr loadZkTreeXml_ (xmlNode* xmlNodePtr)\n    {\n        // Null check\n        if (xmlNodePtr == NULL)\n        {\n            std::cerr << \"[zktreeutil] empty XML node encountered\" << std::endl;\n            exit (-1);\n        }\n\n        // Get the node name\n        xmlChar* name = xmlGetProp (xmlNodePtr, BAD_CAST \"name\");\n        string nameStr = (const char*)name;\n        std::cerr << \"[zktreeutil] node name: \" << nameStr;\n        xmlFree (name);\n        // Get the node value\n        string valueStr;\n        xmlChar* value = xmlGetProp (xmlNodePtr, BAD_CAST \"value\");\n        if (value)\n        {\n            valueStr = (const char*)value;\n            std::cerr << \" value: \" << valueStr;\n        }\n        xmlFree (value);\n        // Get the ignore flag\n        bool doIgnore = false;\n        xmlChar* ignore = xmlGetProp (xmlNodePtr, BAD_CAST \"ignore\");\n        if (ignore)\n        {\n            string ignoreStr = (const char*) ignore;\n            if (ignoreStr == \"true\" || ignoreStr == \"yes\" || ignoreStr == \"1\")\n            {\n                doIgnore = true;\n                std::cerr << \" <ignore:>\";\n            }\n        }\n        xmlFree (ignore);\n        std::cerr << std::endl;\n\n        // Create the zk node\n        ZkTreeNodeSptr nodeSptr =\n            ZkTreeNodeSptr (new ZkTreeNode (nameStr,\n                        ZkNodeData (valueStr, doIgnore)));\n\n        // Load the children\n        for (xmlNode* chldNode = xmlNodePtr->children;\n                chldNode;\n                chldNode = chldNode->next)\n            if (chldNode->type == XML_ELEMENT_NODE)\n                nodeSptr->addChild (loadZkTreeXml_ (chldNode));\n\n        // Return the loaded node\n        return nodeSptr;\n    }\n\n    static void writeZkTree_ (ZooKeeperAdapterSptr zkHandle,\n            const ZkTreeNodeSptr zkNodeSptr,\n            const string& path)\n    {\n        // Create the path in zk-tree\n        zkHandle->createNode(path.c_str(), \"\", 0, false);\n        std::cerr << \"[zktreeutil] created key: \" << path << std::endl;\n        // Set value for the path\n        string value = zkNodeSptr->getData().value;\n        if (value != \"\")\n        {\n            zkHandle->setNodeData (path.c_str(), value.c_str());\n            std::cerr << \"[zktreeutil] set value: \" << std::endl;\n        }\n\n        // Go deep to write the subtree rooted in the node, if not to be ignored\n        if (!(zkNodeSptr->getData().ignoreUpdate))\n        {\n            for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)\n            {\n                ZkTreeNodeSptr childNodeSptr = zkNodeSptr->getChild (i);\n                // Add the node name into the path and write in zk-tree\n                string cpath = ((path != \"/\")? path : \"\")\n                    + string(\"/\")\n                    + childNodeSptr->getKey();\n                writeZkTree_ (zkHandle, childNodeSptr, cpath);\n            }\n        }\n\n        return;\n    }\n\n    static void addTreeZkAction_ (const ZkTreeNodeSptr zkNodeSptr,\n            const string& path,\n            vector< ZkAction >& actions)\n    {\n        // Create the key\n        actions.push_back (ZkAction (ZkAction::CREATE, path));\n\n        // Set value for the new key\n        if (zkNodeSptr->getData().value != \"\")\n            actions.push_back (ZkAction (ZkAction::VALUE,\n                        path,\n                        zkNodeSptr->getData().value));\n\n        // Add all the children\n        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)\n        {\n            ZkTreeNodeSptr childSptr = zkNodeSptr->getChild (i);\n            string cpath = path + string(\"/\") + childSptr->getKey();\n            addTreeZkAction_ (childSptr, cpath, actions);\n        }\n\n        return;\n    }\n\n    static xmlNodePtr dumpZkTreeXml_ (const ZkTreeNodeSptr zkNodeSptr)\n    {\n        // Create xml node with zknode name and value\n        string nodename = zkNodeSptr->getKey ();\n        string value = zkNodeSptr->getData().value;\n        xmlNodePtr node = xmlNewNode(NULL, BAD_CAST \"zknode\");\n        xmlNewProp (node, BAD_CAST \"name\", BAD_CAST nodename.c_str());\n        if (value.length())\n            xmlNewProp (node, BAD_CAST \"value\", BAD_CAST value.c_str());\n\n        // Add all the children rotted at this node\n        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)\n            xmlAddChild (node, dumpZkTreeXml_ (zkNodeSptr->getChild (i)));\n\n        // Return xml node\n        return node;\n    }\n\n    static void dumpZkTree_ (const ZkTreeNodeSptr zkNodeSptr,\n            int maxLevel,\n            int level,\n            vector< bool >& masks)\n    {\n        // Check the max. dlevel to be dumped\n        if (level > maxLevel)\n            return;\n\n        \n        // Create branch\n        for (int i=0; i < level; i++) \n        {\n            if ( i== level-1) std::cout << \"|   \";\n            else if (masks[i]) std::cout << \"    \";\n            else std::cout << \"|   \";\n        }\n        std::cout << std::endl;\n        for (int i=0; i < level-1; i++)\n        {\n            if (masks[i]) std::cout << \"    \";\n            else std::cout << \"|   \";\n        }\n\n        // Dump the node name and value\n        std::cout << \"|--[\" << zkNodeSptr->getKey();\n        if (zkNodeSptr->getData().value != \"\")\n            std::cout << \" => \" << zkNodeSptr->getData().value;\n        std::cout << \"]\" << std::endl;\n\n        // Dump all the children\n        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)\n        {\n            // Add mask for last child\n            if (i == zkNodeSptr->numChildren()-1)\n                masks.push_back(true);\n            else\n                masks.push_back(false);\n            dumpZkTree_ (zkNodeSptr->getChild (i), maxLevel, level+1, masks);\n        }\n\n        masks.pop_back();\n        return;\n    }\n\n    static ZkTreeNodeSptr traverseBranch_ (const ZkTreeNodeSptr& zkRootSptr,\n            const string& path)\n    {\n        // Check if the tree is loaded into memory\n        if (zkRootSptr == NULL)\n        {\n            string errMsg = \"[zktreeutil] null root passed for traversing\";\n            std::cout << errMsg << std::endl;\n            throw std::logic_error (errMsg);\n        }\n\n        // Split the path and add intermediate znodes\n        vector< string > nodes;\n        boost::split(nodes, path, boost::is_any_of (\"/\") );\n\n        // Start traversing the tree\n        ZkTreeNodeSptr currNodeSptr = zkRootSptr;\n        for (unsigned znode_idx = 1; znode_idx < nodes.size(); znode_idx++)\n        {\n            bool found = false;\n            for (unsigned i=0; i < currNodeSptr->numChildren(); i++)\n            {\n                ZkTreeNodeSptr  childNodeSptr = currNodeSptr->getChild(i);\n                if (childNodeSptr->getKey() == nodes[znode_idx])\n                {\n                    // Found! go to the znode\n                    currNodeSptr = childNodeSptr;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) // No such znode found; return NULL node-ptr\n            {\n                string errMsg = string(\"[zktreeutil] unknown znode during traversal: \")\n                    + nodes[znode_idx];\n                std::cout << errMsg << std::endl;\n                throw std::logic_error (errMsg);\n            }\n        }\n\n        return currNodeSptr;\n    }\n\n    static ZkTreeNodeSptr createAncestors_ (const string& path)\n    {\n        // Create the root znode\n        ZkTreeNodeSptr zkRootSptr = ZkTreeNodeSptr (new ZkTreeNode (\"/\"));\n        ZkTreeNodeSptr currNodeSptr = zkRootSptr;\n        // Split the path and add intermediate znodes\n        vector< string > nodes;\n        boost::split(nodes, path, boost::is_any_of (\"/\") );\n        for (unsigned i=1; i < nodes.size()-1; i++)\n        {\n            ZkTreeNodeSptr childNodeSptr = ZkTreeNodeSptr (new ZkTreeNode (nodes[i]));\n            currNodeSptr->addChild (childNodeSptr);\n            currNodeSptr = childNodeSptr;\n        }\n\n        //Return the root of the branch\n        return zkRootSptr;\n    }\n\n    ZooKeeperAdapterSptr ZkTreeUtil::get_zkHandle (const string& zkHosts)\n    {\n        try\n        {\n            // Create an instance of ZK adapter.\n            ZooKeeperConfig config (zkHosts, 10000);\n            ZooKeeperAdapterSptr zkHandleSptr =\n                ZooKeeperAdapterSptr (new ZooKeeperAdapter (config));\n            return zkHandleSptr;\n        }\n        catch (const ZooKeeperException &e)\n        {\n            std::cerr << \"[zktreeutil] zooKeeper exception caught: \"\n                << e.what()\n                << std::endl;\n            throw;\n        }\n        catch (std::exception &stde)\n        {\n            std::cerr << \"[zktreeutil] standard exception caught: \"\n                << stde.what()\n                << std::endl;\n            throw;\n        }\n        catch (...)\n        {\n            std::cerr\n                << \"[zktreeutil] unknown exception while connecting to zookeeper\"\n                << std::endl;\n            throw;\n        }\n    }\n\n\n    void ZkTreeUtil::loadZkTree (const string& zkHosts,\n            const string& path,\n            bool force)\n    {\n        // Check if already loaded\n        if (loaded_ && !force)\n        {\n            std::cerr << \"[zktreeutil] zk-tree already loaded into memory\"\n                << std::endl;\n            return;\n        }\n\n        // Connect to ZK server\n        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);\n        std::cerr << \"[zktreeutil] connected to ZK serverfor reading\"\n            << std::endl;\n\n        // Check the existence of the path to znode\n        if (!zkHandle->nodeExists (path))\n        {\n            string errMsg = string(\"[zktreeutil] path does not exists : \") + path;\n            std::cout << errMsg << std::endl;\n            throw std::logic_error (errMsg);\n        }\n\n        // Load the rooted (sub)tree\n        ZkTreeNodeSptr zkSubrootSptr = loadZkTree_ (zkHandle, path);\n\n        //  Create the ancestors before loading the rooted subtree\n        if (path != \"/\")\n        {\n            zkRootSptr_ = createAncestors_(path);\n            string ppath = path.substr (0, path.rfind('/'));\n            ZkTreeNodeSptr parentSptr = traverseBranch_( zkRootSptr_, ppath);\n            parentSptr->addChild (zkSubrootSptr);\n        }\n        else // Loaded entire zk-tree\n        {\n            zkRootSptr_ = zkSubrootSptr;\n        }\n\n        // Set load flag\n        loaded_ = true;\n        return;\n    }\n\n    void ZkTreeUtil::loadZkTreeXml (const string& zkXmlConfig,\n            bool force)\n    {\n        // Check if already loaded\n        if (loaded_ && !force)\n        {\n            std::cerr << \"[zktreeutil] zk-tree already loaded into memory\"\n                << std::endl;\n            return;\n        }\n\n        // Parse the file and get the DOM\n        xmlDocPtr docPtr = xmlReadFile(zkXmlConfig.c_str(), NULL, 0);\n        if (docPtr == NULL) {\n            std::cerr << \"[zktreeutil] could not parse XML file \"\n                << zkXmlConfig\n                << std::endl;\n            exit (-1);\n        }\n        std::cerr << \"[zktreeutil] zk-tree XML parsing successful\"\n            << std::endl;\n\n        // Get the root element node\n        xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);\n        // Create the root zk node\n        zkRootSptr_ = ZkTreeNodeSptr (new ZkTreeNode (\"/\"));\n        // Load the rooted XML tree\n        for (xmlNode* chldNode = rootPtr->children;\n                chldNode;\n                chldNode = chldNode->next)\n        {\n            if (chldNode->type == XML_ELEMENT_NODE)\n                zkRootSptr_->addChild (loadZkTreeXml_ (chldNode));\n        }\n\n        // set oad flag\n        loaded_ = true;\n        // Cleanup stuff\n        xmlFreeDoc(docPtr);\n        xmlCleanupParser();\n        return;\n    }\n\n    void ZkTreeUtil::writeZkTree (const string& zkHosts,\n            const string& path,\n            bool force) const\n    {\n        // Connect to ZK server\n        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);\n        std::cerr << \"[zktreeutil] connected to ZK server for writing\"\n            << std::endl;\n\n        // Go to the rooted subtree\n        ZkTreeNodeSptr zkRootSptr = traverseBranch_ (zkRootSptr_, path);\n\n        // Cleanup before write if forceful write enabled\n        if (force)\n        {\n            if (path != \"/\") // remove the subtree rooted at the znode\n            {\n                // Delete the subtree rooted at the znode before write\n                if (zkHandle->nodeExists (path))\n                {\n                    std::cerr << \"[zktreeutil] deleting subtree rooted at \"\n                        << path\n                        << \"...\"\n                        << std::endl;\n                    zkHandle->deleteNode (path, true);\n                }\n            }\n            else // remove the rooted znodes\n            {\n                std::cerr << \"[zktreeutil] deleting rooted zk-tree\"\n                    << \"...\"\n                    << std::endl;\n                // Get the root's children\n                vector< string > cnodes = zkHandle->getNodeChildren (\"/\");\n                for (unsigned i=0; i < cnodes.size(); i++)\n                {\n                    if ( cnodes[i] != \"/zookeeper\") // reserved for zookeeper use\n                        zkHandle->deleteNode(cnodes[i], true);\n                }\n            }\n        }\n\n        // Start tree construction\n        writeZkTree_ (zkHandle, zkRootSptr, path);\n        return;\n    }\n\n    void ZkTreeUtil::dumpZkTree (bool xml, int depth) const\n    {\n        if (xml)\n        {\n            // Creates a new document, a node and set it as a root node\n            xmlDocPtr docPtr = xmlNewDoc(BAD_CAST \"1.0\");\n            xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST \"root\");\n            xmlDocSetRootElement(docPtr, rootNode);\n\n            // Add all the rooted children\n            for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)\n                xmlAddChild (rootNode, dumpZkTreeXml_ (zkRootSptr_->getChild (i)));\n\n            // Dumping document to stdio or file\n            xmlSaveFormatFileEnc(\"-\", docPtr, \"UTF-8\", 1);\n\n            // Cleanup stuff\n            xmlFreeDoc(docPtr);\n            xmlCleanupParser();\n            return;\n        }\n\n        // Dump text\n        std::cout << \"/\" << std::endl;\n        vector< bool > masks;\n        for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)\n        {\n            if (i == zkRootSptr_->numChildren()-1)\n                masks.push_back(true);\n            else\n                masks.push_back(false);\n            dumpZkTree_ (zkRootSptr_->getChild (i), depth, 1, masks);\n        }\n\n        return;\n    }\n\n    vector< ZkAction > ZkTreeUtil::diffZkTree (const string& zkHosts,\n            const string& path) const\n    {\n        // Action container\n        vector< ZkAction > actions;\n\n        if (!loaded_)\n        {\n            std::cout << \"[zktreeutil] zk-tree not loaded for diff\"\n                << std::endl;\n            exit (-1);\n        }\n\n        // Load the rooted subtree from zookeeper\n        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);\n        std::cerr << \"[zktreeutil] connected to ZK server for reading\"\n            << std::endl;\n        ZkTreeNodeSptr zkLiveRootSptr = loadZkTree_ (zkHandle, path);\n\n        // Go to the saved rooted subtree\n        ZkTreeNodeSptr zkLoadedRootSptr =\n            traverseBranch_ (zkRootSptr_, path);\n\n        // Check the root value first\n        if (zkLoadedRootSptr->getData().value\n                != zkLiveRootSptr->getData().value)\n        {\n            actions.push_back (ZkAction (ZkAction::VALUE,\n                        path,\n                        zkLoadedRootSptr->getData().value,\n                        zkLiveRootSptr->getData().value));\n        }\n\n        // Start traversal from root\n        vector< string > ppaths;\n        vector< pair< ZkTreeNodeSptr, ZkTreeNodeSptr > > commonNodes;\n        ppaths.push_back ((path != \"/\")? path : \"\");\n        commonNodes.push_back (pair< ZkTreeNodeSptr, ZkTreeNodeSptr >\n                (zkLoadedRootSptr, zkLiveRootSptr));\n\n        for (unsigned j=0; j < commonNodes.size(); j++)\n        {\n            // Get children of loaded tree\n            map< string, ZkTreeNodeSptr > loadedChildren;\n            for (unsigned i=0; i < commonNodes[j].first->numChildren(); i++)\n            {\n                ZkTreeNodeSptr childSptr = commonNodes[j].first->getChild (i);\n                loadedChildren[childSptr->getKey()] = childSptr;\n            }\n            // Get children of live tree\n            map< string, ZkTreeNodeSptr > liveChildren;\n            for (unsigned i=0; i < commonNodes[j].second->numChildren(); i++)\n            {\n                ZkTreeNodeSptr childSptr = commonNodes[j].second->getChild (i);\n                liveChildren[childSptr->getKey()] = childSptr;\n            }\n\n            // Start comparing the children\n            for (map< string, ZkTreeNodeSptr >::const_iterator it =\n                    loadedChildren.begin();\n                    it != loadedChildren.end();\n                    it++)\n            {\n                bool ignoreKey = it->second->getData().ignoreUpdate;\n                string loadedVal = it->second->getData().value;\n                // Path to this node\n                string path = ppaths[j] + string(\"/\") + it->first;\n\n                map< string, ZkTreeNodeSptr >::const_iterator jt =\n                    liveChildren.find (it->first);\n                if (jt != liveChildren.end())\n                {\n                    // Key is present in live zk-tree\n                    string liveVal = jt->second->getData().value;\n                    // Check value for the key, if not ignored\n                    if (!ignoreKey)\n                    {\n                        if (loadedVal != liveVal)\n                        {\n                            // Value differs, set the new value for the key\n                            actions.push_back (ZkAction (ZkAction::VALUE,\n                                        path,\n                                        loadedVal,\n                                        liveVal));\n                        }\n\n                        // Add node to common nodes\n                        ppaths.push_back (path);\n                        commonNodes.push_back (pair< ZkTreeNodeSptr, ZkTreeNodeSptr >\n                                (it->second, jt->second));\n                    }\n\n                    // Remove the live zk node\n                    liveChildren.erase (it->first);\n                }\n                else\n                {\n                    // Add the subtree rooted to this node, if not ignored\n                    if (!ignoreKey)\n                        addTreeZkAction_ (it->second, path, actions);\n                }\n            }\n\n            // Remaining live zk nodes to be deleted\n            for (map< string, ZkTreeNodeSptr >::const_iterator it = liveChildren.begin();\n                    it != liveChildren.end(); it++)\n            {\n                string path = ppaths[j] + string(\"/\") + it->first;\n                actions.push_back (ZkAction (ZkAction::DELETE, path));\n            }\n        }\n        // return the diff actions\n        return actions;\n    }\n\n    void ZkTreeUtil::executeZkActions (const string& zkHosts,\n            const vector< ZkAction >& zkActions,\n            int execFlags) const\n    {\n        // Execute the diff zk actions\n        if (zkActions.size())\n        {\n            // Connect to Zookeeper for writing\n            ZooKeeperAdapterSptr zkHandleSptr;\n            if ((execFlags & EXECUTE)\n                    || (execFlags & INTERACTIVE))\n            {\n                zkHandleSptr = get_zkHandle (zkHosts);\n                std::cerr << \"[zktreeutil] connected to ZK server for writing\"\n                    << std::endl;\n            }\n\n            for (unsigned i=0; i < zkActions.size(); i++)\n            {\n                if (zkActions[i].action == ZkAction::CREATE)\n                {\n                    if (execFlags & PRINT)\n                        std::cout << \"CREAT- key:\" << zkActions[i].key << std::endl;\n                    if (execFlags & EXECUTE)\n                    {\n                        if (execFlags & INTERACTIVE)\n                        {\n                            string resp;\n                            std::cout << \"Execute this action?[yes/no]: \";\n                            std::getline(std::cin, resp);\n                            if (resp != \"yes\")\n                                continue;\n                        }\n                        zkHandleSptr->createNode(zkActions[i].key.c_str(), \"\", 0, false);\n                    }\n                }\n                else if (zkActions[i].action == ZkAction::DELETE)\n                {\n                    if (execFlags & PRINT)\n                        std::cout << \"DELET- key:\" << zkActions[i].key << std::endl;\n                    if (execFlags & EXECUTE)\n                    {\n                        if (execFlags & INTERACTIVE)\n                        {\n                            string resp;\n                            std::cout << \"Execute this action?[yes/no]: \";\n                            std::getline(std::cin, resp);\n                            if (resp != \"yes\")\n                                continue;\n                        }\n                        zkHandleSptr->deleteNode(zkActions[i].key.c_str(), true);\n                    }\n                }\n                else if (zkActions[i].action == ZkAction::VALUE)\n                {\n                    if (execFlags & PRINT)\n                    {\n                        std::cout << \"VALUE- key:\"\n                            << zkActions[i].key\n                            << \" value:\" << zkActions[i].newval;\n                        if (zkActions[i].oldval != \"\")\n                            std::cout << \" old_value:\" << zkActions[i].oldval;\n                        std::cout << std::endl;\n                    }\n                    if (execFlags & EXECUTE)\n                    {\n                        if (execFlags & INTERACTIVE)\n                        {\n                            string resp;\n                            std::cout << \"Execute this action?[yes/no]: \";\n                            std::getline(std::cin, resp);\n                            if (resp != \"yes\")\n                                continue;\n                        }\n                        zkHandleSptr->setNodeData (zkActions[i].key, zkActions[i].newval);\n                    }\n                }\n            }\n        }\n\n        return;\n    }\n\n}\n\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/ZkTreeUtil.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __ZK_TREE_UTIL_H__\n#define __ZK_TREE_UTIL_H__\n\n#include <libxml/parser.h>\n#include <libxml/tree.h>\n#include \"SimpleTree.h\"\n#include \"ZkAdaptor.h\"\n\nnamespace zktreeutil\n{\n\n#define ZKTREEUTIL_INF 1000000000\n    /**\n     * \\brief A structure containing ZK node data.\n     */\n    struct ZkNodeData\n    {\n        /**\n         * \\brief The value string of the ZK node.\n         */\n        string value;\n\n        /**\n         * \\brief The flag indicating whether children of the\n         * \\brief node shduld be ignored during create/diff/update\n         */\n        bool ignoreUpdate;\n\n        /**\n         * \\brief Constructor.\n         *\n         * @param val the value string\n         * @param ignore the flag indicating ignore any update/diff\n         */\n        ZkNodeData (const string& val, bool ignore=false)\n            : value (val), ignoreUpdate (ignore) {}\n\n        /**\n         * \\brief Constructor.\n         *\n         * @param ignore the flag indicating ignore any update/diff\n         */\n        ZkNodeData (bool ignore=false)\n            : ignoreUpdate (ignore) {}\n    };\n\n    /**\n     * \\brief The type representing a ZK Treenode\n     */\n    typedef SimpleTreeNode< string, ZkNodeData > ZkTreeNode;\n\n    /**\n     * \\brief The type representing a ZK Treenode smart-pointer\n     */\n    typedef boost::shared_ptr< ZkTreeNode > ZkTreeNodeSptr;\n\n    /**\n     * \\brief The type representing a ZK Adapter smart-pointer\n     */\n    typedef boost::shared_ptr< ZooKeeperAdapter > ZooKeeperAdapterSptr;\n\n    /**\n     * \\brief A structure defining a particular action on ZK node;\n     * \\brief the action can be any of -\n     * \\brief        CREAT- <zknode>                : creates <zknode> recussively\n     * \\brief        DELET- <zknode>              : deletes <zknode> recursively\n     * \\brief        VALUE- <zknode> <value>     : sets <value> to <zknode>\n     */\n    struct ZkAction\n    {\n        /**\n         * \\brief The action type; any of create/delete/setvalue.\n         */\n        enum ZkActionType\n        {\n            NONE,\n            CREATE,\n            DELETE,\n            VALUE,\n        };\n\n        /**\n         * \\brief action of this instance\n         */\n        ZkActionType action;\n\n        /**\n         * \\brief ZK node key\n         */\n        string key;\n\n        /**\n         * \\brief value to be set, if action is setvalue\n         */\n        string newval;\n\n        /**\n         * \\brief existing value of the ZK node key\n         */\n        string oldval;\n\n        /**\n         * \\brief Constructor.\n         */\n        ZkAction ()\n            : action (ZkAction::NONE) {}\n\n        /**\n         * \\brief Constructor.\n         *\n         * @param act the action to be taken\n         * @param k the key on which action to be taken\n         */\n        ZkAction (ZkActionType act, const string& k)\n            : action(act),\n            key(k) {}\n\n        /**\n         * \\brief Constructor.\n         *\n         * @param act the action to be taken\n         * @param k the key on which action to be taken\n         * @param v the value of the ZK node key\n         */\n        ZkAction (ZkActionType act, const string& k, const string& v)\n            : action(act),\n            key(k),\n            newval(v) {}\n\n        /**\n         * \\brief Constructor.\n         *\n         * @param act the action to be taken\n         * @param k the key on which action to be taken\n         * @param nv the new value of the ZK node key\n         * @param ov the old value of the ZK node key\n         */\n        ZkAction (ZkActionType act, const string& k, const string& nv, const string& ov)\n            : action (act),\n            key(k),\n            newval(nv),\n            oldval(ov) {}\n    };\n\n    /**\n     * \\brief The ZK tree utility class; supports loading ZK tree from ZK server OR\n     * \\brief from saved XML file, saving ZK tree into XML file, dumping the ZK tree\n     * \\brief on standard output, creting a diff between saved ZK tree and live ZK\n     * \\brief tree and incremental update of the live ZK tree.\n     */\n    class ZkTreeUtil\n    {\n        public:\n            /**\n             * \\brief Execution flag on ZkAction\n             */\n            enum ZkActionExecuteFlag\n            {\n                NONE = 0,\n                PRINT = 1,\n                EXECUTE = 2,\n                INTERACTIVE = 5,\n            };\n\n        public:\n            /**\n             * \\brief Connects to zookeeper and returns a valid ZK handle\n             *\n             * @param zkHosts comma separated list of host:port forming ZK quorum\n             * @param a valid ZK handle\n             */\n            static ZooKeeperAdapterSptr get_zkHandle (const string& zkHosts);\n\n\n        public:\n            /**\n             * \\brief Constructor.\n             */\n            ZkTreeUtil () : loaded_(false) {}\n\n            /**\n             * \\brief loads the ZK tree from ZK server into memory\n             *\n             * @param zkHosts comma separated list of host:port forming ZK quorum\n             * @param path path to the subtree to be loaded into memory\n             * @param force forces reloading in case tree already loaded into memory\n             */\n            void loadZkTree (const string& zkHosts, const string& path=\"/\", bool force=false);\n\n            /**\n             * \\brief loads the ZK tree from XML file into memory\n             *\n             * @param zkXmlConfig ZK tree XML file\n             * @param force forces reloading in case tree already loaded into memory\n             */\n            void loadZkTreeXml (const string& zkXmlConfig, bool force=false);\n\n            /**\n             * \\brief writes the in-memory ZK tree on to ZK server\n             *\n             * @param zkHosts comma separated list of host:port forming ZK quorum\n             * @param path path to the subtree to be written to ZK tree\n             * @param force forces cleanup of the ZK tree on the ZK server before writing\n             */\n            void writeZkTree (const string& zkHosts, const string& path=\"/\", bool force=false) const;\n\n            /**\n             * \\brief dupms the in-memory ZK tree on the standard output device;\n             *\n             * @param xml flag indicates whether tree should be dumped in XML format\n             * @param depth the depth of the tree to be dumped for non-xml dump\n             */\n            void dumpZkTree (bool xml=false, int depth=ZKTREEUTIL_INF) const;\n\n            /** \n             * \\brief returns a list of actions after taking a diff of in-memory\n             * \\brief ZK tree and live ZK tree.\n             *\n             * @param zkHosts comma separated list of host:port forming ZK quorum\n             * @param path path to the subtree in consideration while taking diff with ZK tree\n             * @return a list of ZKAction instances to be performed on live ZK tree\n             */\n            vector< ZkAction > diffZkTree (const string& zkHosts, const string& path=\"/\") const;\n\n            /**\n             * \\brief performs create/delete/setvalue by executing a set of\n             * ZkActions on a live ZK tree.\n             *\n             * @param zkHosts comma separated list of host:port forming ZK quorum\n             * @param zkActions set of ZkActions\n             * @param execFlags flags indicating print/execute/interactive etc\n             */\n            void executeZkActions (const string& zkHosts,\n                    const vector< ZkAction >& zkActions,\n                    int execFlags) const;\n\n        private:\n\n            ZkTreeNodeSptr zkRootSptr_;     // ZK tree root node\n            bool loaded_;                        // Falg indicating whether ZK tree loaded into memory\n    };\n}\n\n#endif // __ZK_TREE_UTIL_H__\n"
  },
  {
    "path": "src/contrib/zktreeutil/src/ZkTreeUtilMain.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#endif\n\n#include <unistd.h>\n#ifndef _GNU_SOURCE\n#define _GNU_SOURCE\n#endif\n#include <getopt.h>\n#include <iostream>\n#include \"ZkTreeUtil.h\"\n\nusing namespace zktreeutil;\n\n// The set of \"long\" options accepted by this program.\nstatic struct option long_options[] = {\n    {\"help\",         no_argument,             0, 'h'},\n    {\"import\",        no_argument,             0, 'I'},\n    {\"export\",     no_argument,             0, 'E'},\n    {\"update\",     no_argument,             0, 'U'},\n    {\"diff\",         no_argument,             0, 'F'},\n    {\"dump\",         no_argument,             0, 'D'},\n    {\"force\",         no_argument,             0, 'f'},\n    {\"xmlfile\",     required_argument,     0, 'x'},\n    {\"path\",         required_argument,     0, 'p'},\n    {\"depth\",         required_argument,     0, 'd'},\n    {\"zookeeper\", required_argument,     0, 'z'},\n    {0, 0, 0, 0}\n};\nstatic char *short_options = \"IEUFDfx:p:d:hz:\";\n\nstatic void usage(int argc, char *argv[])\n{\n    std::cout << \"ZK-tree utility for managing ZK-tree with XML import/export,\" << std::endl;\n    std::cout << \"viewing diff between live and saved ZK-tree and performing\" << std::endl;\n    std::cout << \"incremental update of the same.\" << std::endl;\n    std::cout << \"Usage: \" << argv[0] << \" [args-and-values]+\" << std::endl;\n    std::cout \n        << \"\\t--import or -I: \" \n        << std::endl\n        << \"\\t  Imports the zookeeper tree from XML file. Must be specified with\"\n        << std::endl\n        << \"\\t  --zookeeper AND --xmlfile options. Optionally takes --path for\"\n        << std::endl\n        << \"\\t  importing subtree\"\n        << std::endl;\n    std::cout \n        << \"\\t--export or -E: \" \n        << std::endl\n        << \"\\t  Exports the zookeeper tree to XML file. Must be specified with\"\n        << std::endl\n        << \"\\t  --zookeeper option. Optionally takes --path for exporting subtree\"\n        << std::endl;\n    std::cout\n        << \"\\t--update or -U: \"\n        << std::endl\n        << \"\\t  Updates zookeeper tree with changes from XML file. Update operation\"\n        << std::endl\n        << \"\\t  is interactive unless specified with --force option. Must be speci-\"\n        << std::endl\n        << \"\\t  fied with --zookeeper AND --xmlfile options. Optionally takes --path\"\n        << std::endl\n        << \"\\t  for updating subtree.\"\n        << std::endl;\n    std::cout\n        << \"\\t--diff or -F: \"\n        << std::endl\n        << \"\\t  Creates a list of diff actions on ZK tree based on XML data. Must\"\n        << std::endl\n        << \"\\t  be specified with --zookeeper OR --xmlfile options. Optionally takes\"\n        << std::endl\n        << \"\\t  --path for subtree diff\"\n        << std::endl;\n    std::cout\n        << \"\\t--dump or -D: \"\n        << std::endl\n        << \"\\t  Dumps the entire ZK (sub)tree to standard output. Must be specified\"\n        << std::endl\n        << \"\\t  with --zookeeper OR --xmlfile options. Optionally takes --path and\"\n        << std::endl\n        << \"\\t  --depth for dumping subtree.\"\n        << std::endl;\n    std::cout\n        << \"\\t--xmlfile=<filename> or -x <filename>: \"\n        << std::endl\n        << \"\\t  Zookeeper tree-data XML file.\"\n        << std::endl;\n    std::cout\n        << \"\\t--path=<znodepath> or -p <znodepath>: \"\n        << std::endl\n        << \"\\t  Path to the zookeeper subtree rootnode.\"\n        << std::endl;\n    std::cout\n        << \"\\t--depth=<tree-depth> or -d <tree-depth>: \"\n        << std::endl\n        << \"\\t  Depth of the ZK tree to be dumped (ignored for XML dump).\"\n        << std::endl;\n    std::cout\n        << \"\\t--force or -f: Forces cleanup before import; also used for forceful\"\n        << std::endl\n        << \"\\t  update. Optionally be specified with --import and --update.\"\n        << std::endl;\n    std::cout\n        << \"\\t--help or -h: \"\n        << std::endl\n        << \"\\t  prints this message\"\n        << std::endl;\n    std::cout\n        << \"\\t--zookeeper=<zkhosts> or -z <zkhosts>: \"\n        << std::endl\n        << \"\\t  specifies information to connect to zookeeper.\"\n        << std::endl;\n}\n\nint main(int argc, char **argv)\n{\n    if (argc == 1) {\n        usage(argc, argv);\n        exit(0);\n    }\n\n    // Parse the arguments.\n     int op = 0;\n     bool force = false;\n     string zkHosts;\n     string xmlFile;\n     string path = \"/\";\n     int depth = 0;\n     while (1)\n     {\n         int c = getopt_long(argc, argv, short_options, long_options, 0);\n         if (c == -1)\n             break;\n\n         switch (c) {\n             case 'I': op = c;\n                          break;\n             case 'E': op = c;\n                          break;\n             case 'U': op = c;\n                          break;\n             case 'F': op = c;\n                          break;\n             case 'D': op = c;\n                          break;\n             case 'f': force = true;\n                          break;\n             case 'x': xmlFile = optarg;\n                          break;\n             case 'p': path = optarg;\n                          break;\n             case 'd': depth = atoi (optarg);\n                          break;\n             case 'z': zkHosts = optarg;\n                          break;\n             case 'h': usage (argc, argv);\n                          exit(0);\n         }\n     }\n\n     ZkTreeUtil zkTreeUtil;\n     switch (op)\n     {\n         case 'I':    {\n                            if (zkHosts == \"\" || xmlFile == \"\")\n                            {\n                                std::cout << \"[zktreeutil] missing params; please see usage\" << std::endl;\n                                exit (-1);\n                            }\n                            zkTreeUtil.loadZkTreeXml (xmlFile);\n                            zkTreeUtil.writeZkTree (zkHosts, path, force);\n                            std::cout << \"[zktreeutil] import successful!\" << std::endl;\n                            break;\n                        }\n         case 'E':    {\n                            if (zkHosts == \"\")\n                            {\n                                std::cout << \"[zktreeutil] missing params; please see usage\" << std::endl;\n                                exit (-1);\n                            }\n                            zkTreeUtil.loadZkTree (zkHosts, path);\n                            zkTreeUtil.dumpZkTree (true);\n                            break;\n                        }\n         case 'U':    {\n                            if (zkHosts == \"\" || xmlFile == \"\")\n                            {\n                                std::cout << \"[zktreeutil] missing params; please see usage\" << std::endl;\n                                exit (-1);\n                            }\n                            zkTreeUtil.loadZkTreeXml (xmlFile);\n                            vector< ZkAction > zkActions = zkTreeUtil.diffZkTree (zkHosts, path);\n                            int flags = ZkTreeUtil::EXECUTE;\n                            if (!force) flags |= ZkTreeUtil::INTERACTIVE;\n                            zkTreeUtil.executeZkActions (zkHosts, zkActions, flags);\n                            std::cout << \"[zktreeutil] update successful!\" << std::endl;\n                            break;\n                        }\n         case 'F':    {\n                            if (zkHosts == \"\" || xmlFile == \"\")\n                            {\n                                std::cout << \"[zktreeutil] missing params; please see usage\" << std::endl;\n                                exit (-1);\n                            }\n                            zkTreeUtil.loadZkTreeXml (xmlFile);\n                            vector< ZkAction > zkActions = zkTreeUtil.diffZkTree (zkHosts, path);\n                            zkTreeUtil.executeZkActions (zkHosts, zkActions, ZkTreeUtil::PRINT);\n                            break;\n                        }\n         case 'D':    {\n                            if (zkHosts != \"\")\n                                zkTreeUtil.loadZkTree (zkHosts, path);\n                            else if (xmlFile != \"\")\n                                zkTreeUtil.loadZkTreeXml (xmlFile);\n                            else\n                            {\n                                std::cout << \"[zktreeutil] missing params; please see usage\" << std::endl;\n                                exit (-1);\n                            }\n                            // Dump the ZK tree\n                            if (depth) zkTreeUtil.dumpZkTree (false, depth);\n                            else zkTreeUtil.dumpZkTree (false);\n                            break;\n                        }\n     }\n\n     exit(0);\n}\n\n"
  },
  {
    "path": "src/contrib/zktreeutil/tests/zk_sample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<root>\n  <zknode name=\"myapp\">\n    <zknode name=\"version-1.0\">\n      <zknode name=\"clientConfig\">\n        <zknode name=\"testClient\" value=\"cluster.id=local;server.host=localhost;server.port=4080\"/>\n      </zknode>\n      <zknode name=\"configuration\" value=\"v4.0\">\n        <zknode name=\"cacheControl\" value=\"on\"/>\n        <zknode name=\"healthCheck\" value=\"on\"/>\n      </zknode>\n      <zknode name=\"distributions\">\n        <zknode name=\"http\">\n          <zknode name=\"goldenShards\" value=\"0,4294967296,server,localhost:8085;\"/>\n          <zknode name=\"versionedShards\" value=\"33;0,4294967296,server,localhost:8086;\"/>\n          <zknode name=\"shards\" value=\"0,4294967296,server,localhost:8086;\"/>\n        </zknode>\n      </zknode>\n      <zknode name=\"tmp\" ignore=\"yes\">\n        <zknode name=\"alerts\" value=\"test\"/>\n        <zknode name=\"locks\"/>\n        <zknode name=\"transactions\"/>\n      </zknode>\n    </zknode>\n  </zknode>\n  <zknode name=\"zookeeper\" ignore=\"true\"/>\n</root>\n"
  },
  {
    "path": "src/contrib/zooinspector/NOTICE.txt",
    "content": "This contrib module includes icons available under the Eclipse Public Licence Version 1.0\n. from the Eclipse Java Devlopment Platform. \nThe lib sub-directory includes a binary only jar library developed at http://sourceforge.net/projects/jtoaster/"
  },
  {
    "path": "src/contrib/zooinspector/README.txt",
    "content": "﻿==========================================\nZooInspector - Browser and Editor for ZooKeeper Instances\nAuthor: Colin Goodheart-Smithe\nDate: February 2010\n==========================================\n\nZooInspector is a Java Swing based application for browsing and editing ZooKeeper instances.\n\nContents\n--------\n\t- Features\n\t- Pre-requisites\n\t- Build Instructions\n\t- Using ZooInspector\n\t- Creating and Using Plugins\n\t\nFeatures\n--------\n\tBelow is a list of features in the current release of ZooInspector.\n\t- Load connection settings from a zookeeper properties file\n\t- Plugable DataEncryptionManagers to specify how data should be encrypted and decrypted in the Zookeeper instance\n\t- Browseable tree view of the ZooKeeper instance\n\t- View the data in a node\n\t- View the ACL's currently applied to a node\n\t- View the metadata for a node (Version, Number of Children, Last modified Tiem, etc.)\n\t- Plugable NodeViewers interface\n\t- Ability to save/load and set default Node Viewers\n\t\nPre-requisites\n--------------\n\t- The main zookeeper build script must have been run before building this module\n\t\nBuild Instructions\n------------------\n\t1. Open a command line.\n\t2. cd into this directory\n\t3. Run command: ant\n\t4. ZooInspector will be built to ../../../build/contrib/ZooInspector\n\t5. Copy zookeeper-3.x.x.jar into the lib sub-directory (if you are using zookeeper-3.3.0.jar it will have been\n       copied to this directory during the build\n\t6. By default the zookeeper.cmd and zookeeper.sh files expect zookeeper-3.3.0.jar.  If you are using another version\n\t   you will need to change these files to point to the zookeeper-3.x.x.jar you copied to the lib directory\n\t7. To run ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux).  If you are using \n\t   zookeeper-3.3.0.jar and do not require any classpath changes you can run the zookeeper-dev-ZooInspector.jar\n\t   directly\n\nUsing ZooInspector\n------------------\n\tTo start ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux).  If you are using \n\tzookeeper-3.3.0.jar and do not require any classpath changes you can run the zookeeper-dev-ZooInspector.jar\n\tdirectly.\n\t\n\tClick the play button on the toolbar to bring up the connection dialog.  From here you can enter connection \n\tinformation for your zookeeper instance.  You can also load the connection properties from a file.  This file can \n\thave the format as a normal zookeeper properties file (i.e. hosts and timeout key-value pairs) and van optional have\n\tan encryptionManager key-value pair to specify the DataEncryptionManager to use for this connection \n\t(DataEncryptionManagers are explained in further detail in the 'Creating and Using Plugins' section below).  You can\n\talso set the entered information as the defaults so that when you first start ZooInspector these settings are \n\tautomatically loaded into this dialog.  Pressing the OK button with connect to your ZooKeeper instance and show the\n\tcurrent node tree on the left of the main panel.\n\t\n\tClicking a node in the node tree will load the data for that node into the node viewers.  Three node viewers are \n\tcurrently distributed with ZooInspector:\n\t\t1. Node Data - This enables you to see the data current stored on that node.  This data can be modified and \n\t\t   saved.  The data is decrypted and encrypted using the DataEncryptionManager specified on the connection \n\t\t   dialog.\n\t\t2. Node Metadata - This enables you to see the metadata associiated with this node.  This is Essentially the data\n\t\t   obtained from the Stat object for this node.\n\t\t3. Node ACLs - This allows you to see the ACLs currently applied to this node.  Currently there is no ability\n\t\t   to change the ACLs on a node, but it is a feature I would like to add.\n\tOther custom Node Viewers can be added, this is explained in the 'Creating and Using Plugins' section below.\n\t\n\nCreating and Using Plugins\n--------------------------\n\tThere are two types of plugin which can be used with ZooInspector:\n\t\t1. DataEncryptionManager - This specifies how data should be encrypted and decrypted when working with a \n\t\t   zookeeper instance.\n\t\t2. ZooInspectorNodeViewer - This is a GUI panel which provides a view of visualisation on a node.\n\tMore information on these interfaces can be found in the javadocs for this module.\n\t\n\tTo use a plugin in ZooInspector, build the plugin to a jar and copy the jar to the lib sub-directory.  Edit the \n\tzooInspector.cmd and/or zooInspector.sh files to include your new jar on the classpath and run ZooInspector.\n\t\n\tFor DataEncryptionManagers, click the play button to open the connection dialog and enter the full class name of \n\tyour DataEncryptionManager in the 'Data Encryption Manager' field.  You can make this Data Encryption Manager the \n\tdefault by clicking 'Set As Default'.  Click the 'OK' button to instantiate and use your plugin.\n\t\n\tFor ZooInspectorNodeViewers, Click the 'Change Node Viewers' button on the toolbar (looks like a tree with a pencil)\n\tand enter the full classname for your Node Viewer in the field left of the 'Add' button, then click the 'Add' \n\tbutton.  The Node Viewer will be instantiated and should appear in the list.  You can change the order of the Node \n\tviewers by clicking the up and dpwn buttons and delete a Node Viewer by clicking the delete button.  You can save \n\tto configuration to a file or set it as the default if necessary. Then click the 'OK' button and your Node Viewer \n\tshould appear in the tabs on the right of the main panel."
  },
  {
    "path": "src/contrib/zooinspector/build.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"ZooInspector\" default=\"jar\">\n\t<import file=\"../build-contrib.xml\" />\n\n\n\t<target name=\"setjarname\">\n\t\t<property name=\"jarname\" value=\"${build.dir}/zookeeper-${version}-${name}.jar\" />\n\t</target>\n\n\t<target name=\"init\" depends=\"checkMainCompiled, zookeeperbuildcontrib.init\">\n\t\t<mkdir dir=\"${build.dir}/licences\" />\n\t\t<copy todir=\"${build.dir}/licences\">\n\t\t\t<fileset dir=\"${basedir}/licences\" />\n\t\t</copy>\n\t\t<mkdir dir=\"${build.dir}/icons\" />\n\t\t<copy todir=\"${build.dir}/icons\">\n\t\t\t<fileset dir=\"${basedir}/icons\" />\n\t\t</copy>\n\t\t<mkdir dir=\"${build.dir}/config\" />\n\t\t<copy todir=\"${build.dir}/config\">\n\t\t\t<fileset dir=\"${basedir}/config\" />\n\t\t</copy>\n\t\t<copy todir=\"${build.dir}/lib\">\n\t\t\t<fileset file=\"${basedir}/lib/jtoaster-1.0.4.jar\" />\n\t\t\t<fileset file=\"${basedir}/lib/log4j.properties\" />\n\t\t</copy>\n\t\t<copy todir=\"${build.dir}/lib\">\n\t\t\t<fileset file=\"../../../build/zookeeper-3.3.0.jar\" />\n\t\t</copy>\n\t\t<copy todir=\"${build.dir}\">\n\t\t\t<fileset dir=\"${basedir}\" includes=\"*.*\" excludes=\"build.xml,ivy.xml\" />\n\t\t</copy>\n\t</target>\n\n\t<!-- Override jar target to specify main class -->\n\t<target name=\"jar\" depends=\"setjarname, compile\">\n\t\t<echo message=\"contrib: ${name}\" />\n\n\t\t<jar jarfile=\"${jarname}\">\n\t\t\t<manifest>\n\t\t\t\t<attribute name=\"Main-Class\" value=\"org.apache.zookeeper.inspector.ZooInspector\" />\n\t\t\t\t<attribute name=\"Class-Path\" value=\"lib/log4j-1.2.15.jar lib/TableLayout-20050920.jar lib/zookeeper-3.3.0.jar lib/jToaster-1.0.4.jar lib\" />\n\t\t\t\t<attribute name=\"Built-By\" value=\"${user.name}\" />\n\t\t\t\t<attribute name=\"Built-At\" value=\"${build.time}\" />\n\t\t\t\t<attribute name=\"Built-On\" value=\"${host.name}\" />\n\t\t\t\t<attribute name=\"Implementation-Title\" value=\"org.apache.zookeeper\" />\n\t\t\t\t<attribute name=\"Implementation-Version\" value=\"${revision}\" />\n\t\t\t\t<attribute name=\"Implementation-Vendor\" value=\"The Apache Software Foundation\" />\n\t\t\t</manifest>\n\t\t\t<fileset file=\"${zk.root}/LICENSE.txt\" />\n\t\t\t<fileset dir=\"${build.classes}\" />\n\t\t\t<fileset dir=\"${basedir}/src/java\" excludes=\"**/*.jar, **/*.java\"/>\n\t\t</jar>\n\t</target>\n\n\t<target name=\"compile\" depends=\"ivy-retrieve,zookeeperbuildcontrib.compile\" />\n\n\t<target name=\"test\" depends=\"checkMainTestCompiled,compile-test,test-init,test-category,junit.run\" />\n\n\t<target name=\"compile-test\" depends=\"ivy-retrieve-test,compile\">\n\t\t<property name=\"target.jdk\" value=\"${ant.java.version}\" />\n\t\t<property name=\"src.test.local\" location=\"${basedir}/test\" />\n\t\t<mkdir dir=\"${build.test}\" />\n\t\t<javac srcdir=\"${src.test.local}\" destdir=\"${build.test}\" target=\"${target.jdk}\" debug=\"on\">\n\t\t\t<classpath refid=\"classpath\" />\n\t\t\t<classpath>\n\t\t\t\t<pathelement location=\"${zk.root}/build/test/classes\" />\n\t\t\t</classpath>\n\t\t</javac>\n\t</target>\n\n\t<target name=\"test-init\" depends=\"jar,compile-test\">\n\t\t<delete dir=\"${test.log.dir}\" />\n\t\t<delete dir=\"${test.tmp.dir}\" />\n\t\t<delete dir=\"${test.data.dir}\" />\n\t\t<mkdir dir=\"${test.log.dir}\" />\n\t\t<mkdir dir=\"${test.tmp.dir}\" />\n\t\t<mkdir dir=\"${test.data.dir}\" />\n\t</target>\n\n\t<target name=\"test-category\">\n\t\t<property name=\"test.category\" value=\"\" />\n\t</target>\n\n\t<target name=\"junit.run\">\n\t\t<echo message=\"${test.src.dir}\" />\n\t\t<junit showoutput=\"${test.output}\" printsummary=\"${test.junit.printsummary}\" haltonfailure=\"${test.junit.haltonfailure}\" fork=\"yes\" forkmode=\"${test.junit.fork.mode}\" maxmemory=\"${test.junit.maxmem}\" dir=\"${basedir}\" timeout=\"${test.timeout}\" errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n\t\t\t<sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n\t\t\t<sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n\t\t\t<sysproperty key=\"log4j.configuration\" value=\"file:${basedir}/conf/log4j.properties\" />\n\t\t\t<classpath refid=\"classpath\" />\n\t\t\t<classpath>\n\t\t\t\t<pathelement path=\"${build.test}\" />\n\t\t\t\t<pathelement location=\"${zk.root}/build/test/classes\" />\n\t\t\t</classpath>\n\t\t\t<formatter type=\"${test.junit.output.format}\" />\n\t\t\t<batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n\t\t\t\t<fileset dir=\"${test.src.dir}\" includes=\"**/*${test.category}Test.java\" />\n\t\t\t</batchtest>\n\t\t\t<batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n\t\t\t\t<fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\" />\n\t\t\t</batchtest>\n\t\t</junit>\n\t\t<fail if=\"tests.failed\">Tests failed!</fail>\n\t</target>\n\n\t<target name=\"package\" depends=\"jar, zookeeperbuildcontrib.package\" unless=\"skip.contrib\">\n\n\t\t<copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}/contrib/${name}\" />\n\n\t\t<mkdir dir=\"${dist.dir}/contrib/${name}/src\" />\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/src\">\n\t\t\t<fileset dir=\"${basedir}/src\" />\n\t\t</copy>\n\t\t<mkdir dir=\"${dist.dir}/contrib/${name}/licences\" />\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/licences\">\n\t\t\t<fileset dir=\"${basedir}/licences\" />\n\t\t</copy>\n\t\t<mkdir dir=\"${dist.dir}/contrib/${name}/icons\" />\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/icons\">\n\t\t\t<fileset dir=\"${basedir}/icons\" />\n\t\t</copy>\n\t\t<mkdir dir=\"${dist.dir}/contrib/${name}/config\" />\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/config\">\n\t\t\t<fileset dir=\"${basedir}/config\" />\n\t\t</copy>\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/lib\">\n\t\t\t<fileset file=\"${basedir}/lib/jtoaster-1.0.4.jar\" />\n\t\t</copy>\n\t\t<copy todir=\"${dist.dir}/contrib/${name}/lib\">\n\t\t\t<fileset file=\"../../../build/zookeeper-3.3.0.jar\" />\n\t\t</copy>\n\t</target>\n\n</project>\n\n"
  },
  {
    "path": "src/contrib/zooinspector/config/defaultConnectionSettings.cfg",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n#Default connection for ZooInspector\nhosts=localhost\\:2181\nencryptionManager=org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager\ntimeout=5000\nauthScheme=\nauthData=\n"
  },
  {
    "path": "src/contrib/zooinspector/config/defaultNodeVeiwers.cfg",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\norg.apache.zookeeper.inspector.gui.nodeviewer.NodeViewerData\norg.apache.zookeeper.inspector.gui.nodeviewer.NodeViewerMetaData\norg.apache.zookeeper.inspector.gui.nodeviewer.NodeViewerACL\n"
  },
  {
    "path": "src/contrib/zooinspector/ivy.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<ivy-module version=\"2.0\"\n            xmlns:e=\"http://ant.apache.org/ivy/extra\">\n\n  <info organisation=\"org.apache.zookeeper\"\n        module=\"${name}\" revision=\"${version}\">\n    <license name=\"Apache 2.0\"/>\n    <ivyauthor name=\"Apache Hadoop\" url=\"http://hadoop.apache.org\"/>\n    <description>ZooInspector</description>\n  </info>\n\n  <configurations defaultconfmapping=\"default\">\n    <conf name=\"default\"/>\n    <conf name=\"test\"/>\n    <conf name=\"releaseaudit\" visibility=\"private\" description=\"Artifacts required for releaseaudit target\"/>\n  </configurations>\n\n  <dependencies>\n    <dependency org=\"org.slf4j\" name=\"slf4j-api\" rev=\"1.6.1\"/>\n    <dependency org=\"org.slf4j\" name=\"slf4j-log4j12\" rev=\"1.6.1\" transitive=\"false\"/>\n            \n    <dependency org=\"log4j\" name=\"log4j\" rev=\"1.2.15\" transitive=\"false\"/>\n    <dependency org=\"junit\" name=\"junit\" rev=\"4.7\" conf=\"test->default\"/>\n        <dependency org=\"org.apache.rat\" name=\"apache-rat-tasks\" \n                rev=\"0.6\" conf=\"releaseaudit->default\"/>\n    <dependency org=\"commons-lang\" name=\"commons-lang\" \n                rev=\"2.4\" conf=\"releaseaudit->default\"/>\n    <dependency org=\"commons-collections\" name=\"commons-collections\" \n                rev=\"3.2.2\" conf=\"releaseaudit->default\"/>\n  </dependencies>\n\n</ivy-module>\n"
  },
  {
    "path": "src/contrib/zooinspector/lib/log4j.properties",
    "content": "# ***** Set root logger level to INFO and it appender to stdout.\nlog4j.rootLogger=info, stdout\n\n# ***** stdout is set to be a ConsoleAppender.\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\n# ***** stdout uses PatternLayout.\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\n# ***** Pattern to output the caller's file name and line number.\nlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n"
  },
  {
    "path": "src/contrib/zooinspector/licences/Apache Software Licence v2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/contrib/zooinspector/licences/epl-v10.html",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>&quot;Contribution&quot; means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>&quot;Contributor&quot; means any person or entity that distributes\nthe Program.</p>\n\n<p>&quot;Licensed Patents&quot; mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>&quot;Program&quot; means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>&quot;Recipient&quot; means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(&quot;Commercial Contributor&quot;) hereby agrees to defend and\nindemnify every other Contributor (&quot;Indemnified Contributor&quot;)\nagainst any losses, damages and costs (collectively &quot;Losses&quot;)\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/ZooInspector.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector;\n\nimport java.awt.event.WindowAdapter;\nimport java.awt.event.WindowEvent;\n\nimport javax.swing.JFrame;\nimport javax.swing.JOptionPane;\nimport javax.swing.UIManager;\n\nimport org.apache.zookeeper.inspector.gui.ZooInspectorPanel;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorManagerImpl;\n\n/**\n * \n */\npublic class ZooInspector {\n    /**\n     * @param args\n     *            - not used. The value of these parameters will have no effect\n     *            on the application\n     */\n    public static void main(String[] args) {\n        try {\n            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\n            JFrame frame = new JFrame(\"ZooInspector\");\n            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n            final ZooInspectorPanel zooInspectorPanel = new ZooInspectorPanel(\n                    new ZooInspectorManagerImpl());\n            frame.addWindowListener(new WindowAdapter() {\n                @Override\n                public void windowClosed(WindowEvent e) {\n                    super.windowClosed(e);\n                    zooInspectorPanel.disconnect(true);\n                }\n            });\n\n            frame.setContentPane(zooInspectorPanel);\n            frame.setSize(1024, 768);\n            frame.setVisible(true);\n        } catch (Exception e) {\n            LoggerFactory.getLogger().error(\n                    \"Error occurred loading ZooInspector\", e);\n            JOptionPane.showMessageDialog(null,\n                    \"ZooInspector failed to start: \" + e.getMessage(), \"Error\",\n                    JOptionPane.ERROR_MESSAGE);\n        }\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/encryption/BasicDataEncryptionManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.encryption;\n\n/**\n *\n */\npublic class BasicDataEncryptionManager implements DataEncryptionManager {\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#decryptData\n     * (byte[])\n     */\n    public String decryptData(byte[] encrypted) throws Exception {\n        return new String(encrypted);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#encryptData\n     * (java.lang.String)\n     */\n    public byte[] encryptData(String data) throws Exception {\n        if (data == null) {\n            return new byte[0];\n        }\n        return data.getBytes();\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/encryption/DataEncryptionManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.encryption;\n\n/**\n * A class which describes how data should be encrypted and decrypted\n */\npublic interface DataEncryptionManager {\n    /**\n     * @param data\n     *            - the data to be encrypted\n     * @return the encrypted data\n     * @throws Exception\n     */\n    public byte[] encryptData(String data) throws Exception;\n\n    /**\n     * @param encrypted\n     *            - the data to be decrypted\n     * @return the decrypted data\n     * @throws Exception\n     */\n    public String decryptData(byte[] encrypted) throws Exception;\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/NodeViewersChangeListener.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.util.List;\n\nimport org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;\n\n/**\n * A Listener for changes to the configuration of which node viewers are shown\n */\npublic interface NodeViewersChangeListener {\n    /**\n     * Called when the node viewers configuration is changed (i.e node viewers\n     * are added, removed or the order of the node viewers is changed)\n     * \n     * @param newViewers\n     *            - a {@link List} of {@link ZooInspectorNodeViewer}s which are\n     *            to be shown\n     */\n    public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers);\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorAboutDialog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.awt.Dimension;\nimport java.awt.FlowLayout;\nimport java.awt.Frame;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.io.IOException;\n\nimport javax.swing.JButton;\nimport javax.swing.JDialog;\nimport javax.swing.JEditorPane;\nimport javax.swing.JPanel;\n\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\n\n/**\n * The About Dialog for the application\n */\npublic class ZooInspectorAboutDialog extends JDialog {\n    /**\n     * @param frame\n     *            - the Frame from which the dialog is displayed\n     */\n    public ZooInspectorAboutDialog(Frame frame) {\n        super(frame);\n        this.setLayout(new BorderLayout());\n        this.setIconImage(ZooInspectorIconResources.getInformationIcon()\n                .getImage());\n        this.setTitle(\"About ZooInspector\");\n        this.setModal(true);\n        this.setAlwaysOnTop(true);\n        this.setResizable(false);\n        JPanel panel = new JPanel();\n        panel.setLayout(new BorderLayout());\n        JEditorPane aboutPane = new JEditorPane();\n        aboutPane.setEditable(false);\n        aboutPane.setOpaque(false);\n        java.net.URL aboutURL = ZooInspectorAboutDialog.class\n                .getResource(\"about.html\");\n        try {\n            aboutPane.setPage(aboutURL);\n        } catch (IOException e) {\n            LoggerFactory.getLogger().error(\n                    \"Error loading about.html, file may be corrupt\", e);\n        }\n        panel.add(aboutPane, BorderLayout.CENTER);\n        panel.setPreferredSize(new Dimension(600, 200));\n        JPanel buttonsPanel = new JPanel();\n        buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));\n        JButton okButton = new JButton(\"OK\");\n        okButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorAboutDialog.this.dispose();\n            }\n        });\n        buttonsPanel.add(okButton);\n        this.add(panel, BorderLayout.CENTER);\n        this.add(buttonsPanel, BorderLayout.SOUTH);\n        this.pack();\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorConnectionPropertiesDialog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.awt.GridBagConstraints;\nimport java.awt.GridBagLayout;\nimport java.awt.Insets;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Map.Entry;\n\nimport javax.swing.JButton;\nimport javax.swing.JComboBox;\nimport javax.swing.JComponent;\nimport javax.swing.JDialog;\nimport javax.swing.JFileChooser;\nimport javax.swing.JLabel;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPanel;\nimport javax.swing.JTextField;\n\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.Pair;\n\n/**\n * The connection properties dialog. This is used to determine the settings for\n * connecting to a zookeeper instance\n */\npublic class ZooInspectorConnectionPropertiesDialog extends JDialog {\n\n    private final HashMap<String, JComponent> components;\n\n    /**\n     * @param lastConnectionProps\n     *            - the last connection properties used. if this is the first\n     *            conneciton since starting the applications this will be the\n     *            default settings\n     * @param connectionPropertiesTemplateAndLabels\n     *            - the connection properties and labels to show in this dialog\n     * @param zooInspectorPanel\n     *            - the {@link ZooInspectorPanel} linked to this dialog\n     */\n    public ZooInspectorConnectionPropertiesDialog(\n            Properties lastConnectionProps,\n            Pair<Map<String, List<String>>, Map<String, String>> connectionPropertiesTemplateAndLabels,\n            final ZooInspectorPanel zooInspectorPanel) {\n        final Map<String, List<String>> connectionPropertiesTemplate = connectionPropertiesTemplateAndLabels\n                .getKey();\n        final Map<String, String> connectionPropertiesLabels = connectionPropertiesTemplateAndLabels\n                .getValue();\n        this.setLayout(new BorderLayout());\n        this.setTitle(\"Connection Settings\");\n        this.setModal(true);\n        this.setAlwaysOnTop(true);\n        this.setResizable(false);\n        final JPanel options = new JPanel();\n        final JFileChooser fileChooser = new JFileChooser();\n        options.setLayout(new GridBagLayout());\n        int i = 0;\n        components = new HashMap<String, JComponent>();\n        for (Entry<String, List<String>> entry : connectionPropertiesTemplate\n                .entrySet()) {\n            int rowPos = 2 * i + 1;\n            JLabel label = new JLabel(connectionPropertiesLabels.get(entry\n                    .getKey()));\n            GridBagConstraints c1 = new GridBagConstraints();\n            c1.gridx = 0;\n            c1.gridy = rowPos;\n            c1.gridwidth = 1;\n            c1.gridheight = 1;\n            c1.weightx = 0;\n            c1.weighty = 0;\n            c1.anchor = GridBagConstraints.WEST;\n            c1.fill = GridBagConstraints.HORIZONTAL;\n            c1.insets = new Insets(5, 5, 5, 5);\n            c1.ipadx = 0;\n            c1.ipady = 0;\n            options.add(label, c1);\n            if (entry.getValue().size() == 0) {\n                JTextField text = new JTextField();\n                GridBagConstraints c2 = new GridBagConstraints();\n                c2.gridx = 2;\n                c2.gridy = rowPos;\n                c2.gridwidth = 1;\n                c2.gridheight = 1;\n                c2.weightx = 0;\n                c2.weighty = 0;\n                c2.anchor = GridBagConstraints.WEST;\n                c2.fill = GridBagConstraints.HORIZONTAL;\n                c2.insets = new Insets(5, 5, 5, 5);\n                c2.ipadx = 0;\n                c2.ipady = 0;\n                options.add(text, c2);\n                components.put(entry.getKey(), text);\n            } else if (entry.getValue().size() == 1) {\n                JTextField text = new JTextField(entry.getValue().get(0));\n                GridBagConstraints c2 = new GridBagConstraints();\n                c2.gridx = 2;\n                c2.gridy = rowPos;\n                c2.gridwidth = 1;\n                c2.gridheight = 1;\n                c2.weightx = 0;\n                c2.weighty = 0;\n                c2.anchor = GridBagConstraints.WEST;\n                c2.fill = GridBagConstraints.HORIZONTAL;\n                c2.insets = new Insets(5, 5, 5, 5);\n                c2.ipadx = 0;\n                c2.ipady = 0;\n                options.add(text, c2);\n                components.put(entry.getKey(), text);\n            } else {\n                List<String> list = entry.getValue();\n                JComboBox combo = new JComboBox(list.toArray(new String[list\n                        .size()]));\n                combo.setSelectedItem(list.get(0));\n                GridBagConstraints c2 = new GridBagConstraints();\n                c2.gridx = 2;\n                c2.gridy = rowPos;\n                c2.gridwidth = 1;\n                c2.gridheight = 1;\n                c2.weightx = 0;\n                c2.weighty = 0;\n                c2.anchor = GridBagConstraints.WEST;\n                c2.fill = GridBagConstraints.HORIZONTAL;\n                c2.insets = new Insets(5, 5, 5, 5);\n                c2.ipadx = 0;\n                c2.ipady = 0;\n                options.add(combo, c2);\n                components.put(entry.getKey(), combo);\n            }\n            i++;\n        }\n        loadConnectionProps(lastConnectionProps);\n        JPanel buttonsPanel = new JPanel();\n        buttonsPanel.setLayout(new GridBagLayout());\n        JButton loadPropsFileButton = new JButton(\"Load from file\");\n        loadPropsFileButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                int result = fileChooser\n                        .showOpenDialog(ZooInspectorConnectionPropertiesDialog.this);\n                if (result == JFileChooser.APPROVE_OPTION) {\n                    File propsFilePath = fileChooser.getSelectedFile();\n                    Properties props = new Properties();\n                    try {\n                        FileReader reader = new FileReader(propsFilePath);\n                        try {\n                            props.load(reader);\n                            loadConnectionProps(props);\n                        } finally {\n                            reader.close();\n                        }\n                    } catch (IOException ex) {\n                        LoggerFactory\n                                .getLogger()\n                                .error(\n                                        \"An Error occurred loading connection properties from file\",\n                                        ex);\n                        JOptionPane\n                                .showMessageDialog(\n                                        ZooInspectorConnectionPropertiesDialog.this,\n                                        \"An Error occurred loading connection properties from file\",\n                                        \"Error\", JOptionPane.ERROR_MESSAGE);\n                    }\n                    options.revalidate();\n                    options.repaint();\n                }\n\n            }\n        });\n        GridBagConstraints c3 = new GridBagConstraints();\n        c3.gridx = 0;\n        c3.gridy = 0;\n        c3.gridwidth = 1;\n        c3.gridheight = 1;\n        c3.weightx = 0;\n        c3.weighty = 1;\n        c3.anchor = GridBagConstraints.SOUTHWEST;\n        c3.fill = GridBagConstraints.NONE;\n        c3.insets = new Insets(5, 5, 5, 5);\n        c3.ipadx = 0;\n        c3.ipady = 0;\n        buttonsPanel.add(loadPropsFileButton, c3);\n        JButton saveDefaultPropsFileButton = new JButton(\"Set As Default\");\n        saveDefaultPropsFileButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n\n                Properties connectionProps = getConnectionProps();\n                try {\n                    zooInspectorPanel\n                            .setdefaultConnectionProps(connectionProps);\n                } catch (IOException ex) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"An Error occurred saving the default connection properties file\",\n                                    ex);\n                    JOptionPane\n                            .showMessageDialog(\n                                    ZooInspectorConnectionPropertiesDialog.this,\n                                    \"An Error occurred saving the default connection properties file\",\n                                    \"Error\", JOptionPane.ERROR_MESSAGE);\n                }\n            }\n        });\n        GridBagConstraints c6 = new GridBagConstraints();\n        c6.gridx = 1;\n        c6.gridy = 0;\n        c6.gridwidth = 1;\n        c6.gridheight = 1;\n        c6.weightx = 1;\n        c6.weighty = 1;\n        c6.anchor = GridBagConstraints.SOUTHWEST;\n        c6.fill = GridBagConstraints.NONE;\n        c6.insets = new Insets(5, 5, 5, 5);\n        c6.ipadx = 0;\n        c6.ipady = 0;\n        buttonsPanel.add(saveDefaultPropsFileButton, c6);\n        JButton okButton = new JButton(\"OK\");\n        okButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorConnectionPropertiesDialog.this.dispose();\n                Properties connectionProps = getConnectionProps();\n                zooInspectorPanel.connect(connectionProps);\n            }\n        });\n        GridBagConstraints c4 = new GridBagConstraints();\n        c4.gridx = 2;\n        c4.gridy = 0;\n        c4.gridwidth = 1;\n        c4.gridheight = 1;\n        c4.weightx = 0;\n        c4.weighty = 1;\n        c4.anchor = GridBagConstraints.SOUTH;\n        c4.fill = GridBagConstraints.HORIZONTAL;\n        c4.insets = new Insets(5, 5, 5, 5);\n        c4.ipadx = 0;\n        c4.ipady = 0;\n        buttonsPanel.add(okButton, c4);\n        JButton cancelButton = new JButton(\"Cancel\");\n        cancelButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorConnectionPropertiesDialog.this.dispose();\n            }\n        });\n        GridBagConstraints c5 = new GridBagConstraints();\n        c5.gridx = 3;\n        c5.gridy = 0;\n        c5.gridwidth = 1;\n        c5.gridheight = 1;\n        c5.weightx = 0;\n        c5.weighty = 1;\n        c5.anchor = GridBagConstraints.SOUTH;\n        c5.fill = GridBagConstraints.HORIZONTAL;\n        c5.insets = new Insets(5, 5, 5, 5);\n        c5.ipadx = 0;\n        c5.ipady = 0;\n        buttonsPanel.add(cancelButton, c5);\n        this.add(options, BorderLayout.CENTER);\n        this.add(buttonsPanel, BorderLayout.SOUTH);\n        this.pack();\n    }\n\n    private void loadConnectionProps(Properties props) {\n        if (props != null) {\n            for (Object key : props.keySet()) {\n                String propsKey = (String) key;\n                if (components.containsKey(propsKey)) {\n                    JComponent component = components.get(propsKey);\n                    String value = props.getProperty(propsKey);\n                    if (component instanceof JTextField) {\n                        ((JTextField) component).setText(value);\n                    } else if (component instanceof JComboBox) {\n                        ((JComboBox) component).setSelectedItem(value);\n                    }\n                }\n            }\n        }\n    }\n\n    private Properties getConnectionProps() {\n        Properties connectionProps = new Properties();\n        for (Entry<String, JComponent> entry : components.entrySet()) {\n            String value = null;\n            JComponent component = entry.getValue();\n            if (component instanceof JTextField) {\n                value = ((JTextField) component).getText();\n            } else if (component instanceof JComboBox) {\n                value = ((JComboBox) component).getSelectedItem().toString();\n            }\n            connectionProps.put(entry.getKey(), value);\n        }\n        return connectionProps;\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorIconResources.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport javax.swing.ImageIcon;\n\n/**\n * A class containing static methods for retrieving {@link ImageIcon}s used in\n * the application\n */\npublic class ZooInspectorIconResources {\n\n    /**\n     * @return file icon\n     */\n    public static ImageIcon getTreeLeafIcon() {\n        return new ImageIcon(\"icons/file_obj.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return folder open icon\n     */\n    public static ImageIcon getTreeOpenIcon() {\n        return new ImageIcon(\"icons/fldr_obj.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return folder closed icon\n     */\n    public static ImageIcon getTreeClosedIcon() {\n        return new ImageIcon(\"icons/fldr_obj.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return connect icon\n     */\n    public static ImageIcon getConnectIcon() {\n        return new ImageIcon(\"icons/launch_run.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return disconnect icon\n     */\n    public static ImageIcon getDisconnectIcon() {\n        return new ImageIcon(\"icons/launch_stop.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return save icon\n     */\n    public static ImageIcon getSaveIcon() {\n        return new ImageIcon(\"icons/save_edit.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return add icon\n     */\n    public static ImageIcon getAddNodeIcon() {\n        return new ImageIcon(\"icons/new_con.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return delete icon\n     */\n    public static ImageIcon getDeleteNodeIcon() {\n        return new ImageIcon(\"icons/trash.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return refresh icon\n     */\n    public static ImageIcon getRefreshIcon() {\n        return new ImageIcon(\"icons/refresh.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return information icon\n     */\n    public static ImageIcon getInformationIcon() {\n        return new ImageIcon(\"icons/info_obj.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return node viewers icon\n     */\n    public static ImageIcon getChangeNodeViewersIcon() {\n        return new ImageIcon(\"icons/edtsrclkup_co.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return up icon\n     */\n    public static ImageIcon getUpIcon() {\n        return new ImageIcon(\"icons/search_prev.gif\"); //$NON-NLS-1$\n    }\n\n    /**\n     * @return down icon\n     */\n    public static ImageIcon getDownIcon() {\n        return new ImageIcon(\"icons/search_next.gif\"); //$NON-NLS-1$\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorNodeViewersDialog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.awt.Component;\nimport java.awt.FlowLayout;\nimport java.awt.Frame;\nimport java.awt.GridBagConstraints;\nimport java.awt.GridBagLayout;\nimport java.awt.Insets;\nimport java.awt.datatransfer.Transferable;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport javax.swing.DefaultListCellRenderer;\nimport javax.swing.DefaultListModel;\nimport javax.swing.DropMode;\nimport javax.swing.JButton;\nimport javax.swing.JComponent;\nimport javax.swing.JDialog;\nimport javax.swing.JFileChooser;\nimport javax.swing.JLabel;\nimport javax.swing.JList;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextField;\nimport javax.swing.ListSelectionModel;\nimport javax.swing.TransferHandler;\nimport javax.swing.event.ListSelectionEvent;\nimport javax.swing.event.ListSelectionListener;\n\nimport org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorManager;\n\n/**\n * A {@link JDialog} for configuring which {@link ZooInspectorNodeViewer}s to\n * show in the application\n */\npublic class ZooInspectorNodeViewersDialog extends JDialog implements\n        ListSelectionListener {\n\n    private final JButton upButton;\n    private final JButton downButton;\n    private final JButton removeButton;\n    private final JButton addButton;\n    private final JList viewersList;\n    private final JButton saveFileButton;\n    private final JButton loadFileButton;\n    private final JButton setDefaultsButton;\n    private final JFileChooser fileChooser = new JFileChooser(new File(\".\"));\n\n    /**\n     * @param frame\n     *            - the Frame from which the dialog is displayed\n     * @param currentViewers\n     *            - the {@link ZooInspectorNodeViewer}s to show\n     * @param listeners\n     *            - the {@link NodeViewersChangeListener}s which need to be\n     *            notified of changes to the node viewers configuration\n     * @param manager\n     *            - the {@link ZooInspectorManager} for the application\n     * \n     */\n    public ZooInspectorNodeViewersDialog(Frame frame,\n            final List<ZooInspectorNodeViewer> currentViewers,\n            final Collection<NodeViewersChangeListener> listeners,\n            final ZooInspectorManager manager) {\n        super(frame);\n        final List<ZooInspectorNodeViewer> newViewers = new ArrayList<ZooInspectorNodeViewer>(\n                currentViewers);\n        this.setLayout(new BorderLayout());\n        this.setIconImage(ZooInspectorIconResources.getChangeNodeViewersIcon()\n                .getImage());\n        this.setTitle(\"About ZooInspector\");\n        this.setModal(true);\n        this.setAlwaysOnTop(true);\n        this.setResizable(true);\n        final JPanel panel = new JPanel();\n        panel.setLayout(new GridBagLayout());\n        viewersList = new JList();\n        DefaultListModel model = new DefaultListModel();\n        for (ZooInspectorNodeViewer viewer : newViewers) {\n            model.addElement(viewer);\n        }\n        viewersList.setModel(model);\n        viewersList.setCellRenderer(new DefaultListCellRenderer() {\n            @Override\n            public Component getListCellRendererComponent(JList list,\n                    Object value, int index, boolean isSelected,\n                    boolean cellHasFocus) {\n                ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) value;\n                JLabel label = (JLabel) super.getListCellRendererComponent(\n                        list, value, index, isSelected, cellHasFocus);\n                label.setText(viewer.getTitle());\n                return label;\n            }\n        });\n        viewersList.setDropMode(DropMode.INSERT);\n        viewersList.enableInputMethods(true);\n        viewersList.setDragEnabled(true);\n        viewersList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\n        viewersList.getSelectionModel().addListSelectionListener(this);\n        viewersList.setTransferHandler(new TransferHandler() {\n\n            @Override\n            public boolean canImport(TransferHandler.TransferSupport info) {\n                // we only import NodeViewers\n                if (!info\n                        .isDataFlavorSupported(ZooInspectorNodeViewer.nodeViewerDataFlavor)) {\n                    return false;\n                }\n\n                JList.DropLocation dl = (JList.DropLocation) info\n                        .getDropLocation();\n                if (dl.getIndex() == -1) {\n                    return false;\n                }\n                return true;\n            }\n\n            @Override\n            public boolean importData(TransferHandler.TransferSupport info) {\n                JList.DropLocation dl = (JList.DropLocation) info\n                        .getDropLocation();\n                DefaultListModel listModel = (DefaultListModel) viewersList\n                        .getModel();\n                int index = dl.getIndex();\n                boolean insert = dl.isInsert();\n                // Get the string that is being dropped.\n                Transferable t = info.getTransferable();\n                String data;\n                try {\n                    data = (String) t\n                            .getTransferData(ZooInspectorNodeViewer.nodeViewerDataFlavor);\n                } catch (Exception e) {\n                    return false;\n                }\n                try {\n                    ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) Class\n                            .forName(data).newInstance();\n                    if (listModel.contains(viewer)) {\n                        listModel.removeElement(viewer);\n                    }\n                    if (insert) {\n                        listModel.add(index, viewer);\n                    } else {\n                        listModel.set(index, viewer);\n                    }\n                    return true;\n                } catch (Exception e) {\n                    LoggerFactory.getLogger().error(\n                            \"Error instantiating class: \" + data, e);\n                    return false;\n                }\n\n            }\n\n            @Override\n            public int getSourceActions(JComponent c) {\n                return MOVE;\n            }\n\n            @Override\n            protected Transferable createTransferable(JComponent c) {\n                JList list = (JList) c;\n                ZooInspectorNodeViewer value = (ZooInspectorNodeViewer) list\n                        .getSelectedValue();\n                return value;\n            }\n        });\n        JScrollPane scroller = new JScrollPane(viewersList);\n        GridBagConstraints c1 = new GridBagConstraints();\n        c1.gridx = 0;\n        c1.gridy = 0;\n        c1.gridwidth = 3;\n        c1.gridheight = 3;\n        c1.weightx = 0;\n        c1.weighty = 1;\n        c1.anchor = GridBagConstraints.CENTER;\n        c1.fill = GridBagConstraints.BOTH;\n        c1.insets = new Insets(5, 5, 5, 5);\n        c1.ipadx = 0;\n        c1.ipady = 0;\n        panel.add(scroller, c1);\n        upButton = new JButton(ZooInspectorIconResources.getUpIcon());\n        downButton = new JButton(ZooInspectorIconResources.getDownIcon());\n        removeButton = new JButton(ZooInspectorIconResources\n                .getDeleteNodeIcon());\n        addButton = new JButton(ZooInspectorIconResources.getAddNodeIcon());\n        upButton.setEnabled(false);\n        downButton.setEnabled(false);\n        removeButton.setEnabled(false);\n        addButton.setEnabled(true);\n        upButton.setToolTipText(\"Move currently selected node viewer up\");\n        downButton.setToolTipText(\"Move currently selected node viewer down\");\n        removeButton.setToolTipText(\"Remove currently selected node viewer\");\n        addButton.setToolTipText(\"Add node viewer\");\n        final JTextField newViewerTextField = new JTextField();\n        GridBagConstraints c2 = new GridBagConstraints();\n        c2.gridx = 3;\n        c2.gridy = 0;\n        c2.gridwidth = 1;\n        c2.gridheight = 1;\n        c2.weightx = 0;\n        c2.weighty = 0;\n        c2.anchor = GridBagConstraints.NORTH;\n        c2.fill = GridBagConstraints.HORIZONTAL;\n        c2.insets = new Insets(5, 5, 5, 5);\n        c2.ipadx = 0;\n        c2.ipady = 0;\n        panel.add(upButton, c2);\n        GridBagConstraints c3 = new GridBagConstraints();\n        c3.gridx = 3;\n        c3.gridy = 2;\n        c3.gridwidth = 1;\n        c3.gridheight = 1;\n        c3.weightx = 0;\n        c3.weighty = 0;\n        c3.anchor = GridBagConstraints.NORTH;\n        c3.fill = GridBagConstraints.HORIZONTAL;\n        c3.insets = new Insets(5, 5, 5, 5);\n        c3.ipadx = 0;\n        c3.ipady = 0;\n        panel.add(downButton, c3);\n        GridBagConstraints c4 = new GridBagConstraints();\n        c4.gridx = 3;\n        c4.gridy = 1;\n        c4.gridwidth = 1;\n        c4.gridheight = 1;\n        c4.weightx = 0;\n        c4.weighty = 0;\n        c4.anchor = GridBagConstraints.NORTH;\n        c4.fill = GridBagConstraints.HORIZONTAL;\n        c4.insets = new Insets(5, 5, 5, 5);\n        c4.ipadx = 0;\n        c4.ipady = 0;\n        panel.add(removeButton, c4);\n        GridBagConstraints c5 = new GridBagConstraints();\n        c5.gridx = 0;\n        c5.gridy = 3;\n        c5.gridwidth = 3;\n        c5.gridheight = 1;\n        c5.weightx = 0;\n        c5.weighty = 0;\n        c5.anchor = GridBagConstraints.CENTER;\n        c5.fill = GridBagConstraints.BOTH;\n        c5.insets = new Insets(5, 5, 5, 5);\n        c5.ipadx = 0;\n        c5.ipady = 0;\n        panel.add(newViewerTextField, c5);\n        GridBagConstraints c6 = new GridBagConstraints();\n        c6.gridx = 3;\n        c6.gridy = 3;\n        c6.gridwidth = 1;\n        c6.gridheight = 1;\n        c6.weightx = 0;\n        c6.weighty = 0;\n        c6.anchor = GridBagConstraints.CENTER;\n        c6.fill = GridBagConstraints.BOTH;\n        c6.insets = new Insets(5, 5, 5, 5);\n        c6.ipadx = 0;\n        c6.ipady = 0;\n        panel.add(addButton, c6);\n        upButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                DefaultListModel listModel = (DefaultListModel) viewersList\n                        .getModel();\n                ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) viewersList\n                        .getSelectedValue();\n                int index = viewersList.getSelectedIndex();\n                if (listModel.contains(viewer)) {\n                    listModel.removeElementAt(index);\n                    listModel.insertElementAt(viewer, index - 1);\n                    viewersList.setSelectedValue(viewer, true);\n                }\n            }\n        });\n        downButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                DefaultListModel listModel = (DefaultListModel) viewersList\n                        .getModel();\n                ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) viewersList\n                        .getSelectedValue();\n                int index = viewersList.getSelectedIndex();\n                if (listModel.contains(viewer)) {\n                    listModel.removeElementAt(index);\n                    listModel.insertElementAt(viewer, index + 1);\n                    viewersList.setSelectedValue(viewer, true);\n                }\n            }\n        });\n        removeButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                DefaultListModel listModel = (DefaultListModel) viewersList\n                        .getModel();\n                ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) viewersList\n                        .getSelectedValue();\n                int index = viewersList.getSelectedIndex();\n                if (listModel.contains(viewer)) {\n                    listModel.removeElement(viewer);\n                    viewersList\n                            .setSelectedIndex(index == listModel.size() ? index - 1\n                                    : index);\n                }\n            }\n        });\n        addButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                String className = newViewerTextField.getText();\n                if (className == null || className.length() == 0) {\n                    JOptionPane\n                            .showMessageDialog(\n                                    ZooInspectorNodeViewersDialog.this,\n                                    \"Please enter the full class name for a Node Viewer and click the add button\",\n                                    \"Input Error\", JOptionPane.ERROR_MESSAGE);\n                } else {\n                    try {\n                        DefaultListModel listModel = (DefaultListModel) viewersList\n                                .getModel();\n                        ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) Class\n                                .forName(className).newInstance();\n                        if (listModel.contains(viewer)) {\n                            JOptionPane\n                                    .showMessageDialog(\n                                            ZooInspectorNodeViewersDialog.this,\n                                            \"Node viewer already exists.  Each node viewer can only be added once.\",\n                                            \"Input Error\",\n                                            JOptionPane.ERROR_MESSAGE);\n                        } else {\n                            listModel.addElement(viewer);\n                        }\n                    } catch (Exception ex) {\n                        LoggerFactory\n                                .getLogger()\n                                .error(\n                                        \"An error occurred while instaniating the node viewer. \",\n                                        ex);\n                        JOptionPane.showMessageDialog(\n                                ZooInspectorNodeViewersDialog.this,\n                                \"An error occurred while instaniating the node viewer: \"\n                                        + ex.getMessage(), \"Error\",\n                                JOptionPane.ERROR_MESSAGE);\n                    }\n                }\n            }\n        });\n        saveFileButton = new JButton(\"Save\");\n        loadFileButton = new JButton(\"Load\");\n        setDefaultsButton = new JButton(\"Set As Defaults\");\n        saveFileButton\n                .setToolTipText(\"Save current node viewer configuration to file\");\n        loadFileButton\n                .setToolTipText(\"Load node viewer configuration frm file\");\n        setDefaultsButton\n                .setToolTipText(\"Set current configuration asd defaults\");\n        GridBagConstraints c7 = new GridBagConstraints();\n        c7.gridx = 0;\n        c7.gridy = 4;\n        c7.gridwidth = 1;\n        c7.gridheight = 1;\n        c7.weightx = 1;\n        c7.weighty = 0;\n        c7.anchor = GridBagConstraints.WEST;\n        c7.fill = GridBagConstraints.VERTICAL;\n        c7.insets = new Insets(5, 5, 5, 5);\n        c7.ipadx = 0;\n        c7.ipady = 0;\n        panel.add(saveFileButton, c7);\n        GridBagConstraints c8 = new GridBagConstraints();\n        c8.gridx = 1;\n        c8.gridy = 4;\n        c8.gridwidth = 1;\n        c8.gridheight = 1;\n        c8.weightx = 0;\n        c8.weighty = 0;\n        c8.anchor = GridBagConstraints.WEST;\n        c8.fill = GridBagConstraints.VERTICAL;\n        c8.insets = new Insets(5, 5, 5, 5);\n        c8.ipadx = 0;\n        c8.ipady = 0;\n        panel.add(loadFileButton, c8);\n        GridBagConstraints c9 = new GridBagConstraints();\n        c9.gridx = 2;\n        c9.gridy = 4;\n        c9.gridwidth = 1;\n        c9.gridheight = 1;\n        c9.weightx = 0;\n        c9.weighty = 0;\n        c9.anchor = GridBagConstraints.WEST;\n        c9.fill = GridBagConstraints.VERTICAL;\n        c9.insets = new Insets(5, 5, 5, 5);\n        c9.ipadx = 0;\n        c9.ipady = 0;\n        panel.add(setDefaultsButton, c9);\n        saveFileButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                int result = fileChooser\n                        .showSaveDialog(ZooInspectorNodeViewersDialog.this);\n                if (result == JFileChooser.APPROVE_OPTION) {\n                    File selectedFile = fileChooser.getSelectedFile();\n                    int answer = JOptionPane.YES_OPTION;\n                    if (selectedFile.exists()) {\n                        answer = JOptionPane\n                                .showConfirmDialog(\n                                        ZooInspectorNodeViewersDialog.this,\n                                        \"The specified file already exists.  do you want to overwrite it?\",\n                                        \"Confirm Overwrite\",\n                                        JOptionPane.YES_NO_OPTION,\n                                        JOptionPane.WARNING_MESSAGE);\n                    }\n                    if (answer == JOptionPane.YES_OPTION) {\n                        DefaultListModel listModel = (DefaultListModel) viewersList\n                                .getModel();\n                        List<String> nodeViewersClassNames = new ArrayList<String>();\n                        Object[] modelContents = listModel.toArray();\n                        for (Object o : modelContents) {\n                            nodeViewersClassNames\n                                    .add(((ZooInspectorNodeViewer) o)\n                                            .getClass().getCanonicalName());\n                        }\n                        try {\n                            manager.saveNodeViewersFile(selectedFile,\n                                    nodeViewersClassNames);\n                        } catch (IOException ex) {\n                            LoggerFactory\n                                    .getLogger()\n                                    .error(\n                                            \"Error saving node veiwer configuration from file.\",\n                                            ex);\n                            JOptionPane.showMessageDialog(\n                                    ZooInspectorNodeViewersDialog.this,\n                                    \"Error saving node veiwer configuration from file: \"\n                                            + ex.getMessage(), \"Error\",\n                                    JOptionPane.ERROR_MESSAGE);\n                        }\n                    }\n                }\n            }\n        });\n        loadFileButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                int result = fileChooser\n                        .showOpenDialog(ZooInspectorNodeViewersDialog.this);\n                if (result == JFileChooser.APPROVE_OPTION) {\n                    try {\n                        List<String> nodeViewersClassNames = manager\n                                .loadNodeViewersFile(fileChooser\n                                        .getSelectedFile());\n                        List<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();\n                        for (String nodeViewersClassName : nodeViewersClassNames) {\n                            ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) Class\n                                    .forName(nodeViewersClassName)\n                                    .newInstance();\n                            nodeViewers.add(viewer);\n                        }\n                        DefaultListModel model = new DefaultListModel();\n                        for (ZooInspectorNodeViewer viewer : nodeViewers) {\n                            model.addElement(viewer);\n                        }\n                        viewersList.setModel(model);\n                        panel.revalidate();\n                        panel.repaint();\n                    } catch (Exception ex) {\n                        LoggerFactory\n                                .getLogger()\n                                .error(\n                                        \"Error loading node veiwer configuration from file.\",\n                                        ex);\n                        JOptionPane.showMessageDialog(\n                                ZooInspectorNodeViewersDialog.this,\n                                \"Error loading node veiwer configuration from file: \"\n                                        + ex.getMessage(), \"Error\",\n                                JOptionPane.ERROR_MESSAGE);\n                    }\n                }\n            }\n        });\n        setDefaultsButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                int answer = JOptionPane\n                        .showConfirmDialog(\n                                ZooInspectorNodeViewersDialog.this,\n                                \"Are you sure you want to save this configuration as the default?\",\n                                \"Confirm Set Defaults\",\n                                JOptionPane.YES_NO_OPTION,\n                                JOptionPane.WARNING_MESSAGE);\n                if (answer == JOptionPane.YES_OPTION) {\n                    DefaultListModel listModel = (DefaultListModel) viewersList\n                            .getModel();\n                    List<String> nodeViewersClassNames = new ArrayList<String>();\n                    Object[] modelContents = listModel.toArray();\n                    for (Object o : modelContents) {\n                        nodeViewersClassNames.add(((ZooInspectorNodeViewer) o)\n                                .getClass().getCanonicalName());\n                    }\n                    try {\n                        manager\n                                .setDefaultNodeViewerConfiguration(nodeViewersClassNames);\n                    } catch (IOException ex) {\n                        LoggerFactory\n                                .getLogger()\n                                .error(\n                                        \"Error setting default node veiwer configuration.\",\n                                        ex);\n                        JOptionPane.showMessageDialog(\n                                ZooInspectorNodeViewersDialog.this,\n                                \"Error setting default node veiwer configuration: \"\n                                        + ex.getMessage(), \"Error\",\n                                JOptionPane.ERROR_MESSAGE);\n                    }\n                }\n            }\n        });\n\n        JPanel buttonsPanel = new JPanel();\n        buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));\n        JButton okButton = new JButton(\"OK\");\n        okButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorNodeViewersDialog.this.dispose();\n                DefaultListModel listModel = (DefaultListModel) viewersList\n                        .getModel();\n                newViewers.clear();\n                Object[] modelContents = listModel.toArray();\n                for (Object o : modelContents) {\n                    newViewers.add((ZooInspectorNodeViewer) o);\n                }\n                currentViewers.clear();\n                currentViewers.addAll(newViewers);\n                for (NodeViewersChangeListener listener : listeners) {\n                    listener.nodeViewersChanged(currentViewers);\n                }\n            }\n        });\n        buttonsPanel.add(okButton);\n        JButton cancelButton = new JButton(\"Cancel\");\n        cancelButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorNodeViewersDialog.this.dispose();\n            }\n        });\n        buttonsPanel.add(cancelButton);\n        this.add(panel, BorderLayout.CENTER);\n        this.add(buttonsPanel, BorderLayout.SOUTH);\n        this.pack();\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event\n     * .ListSelectionEvent)\n     */\n    public void valueChanged(ListSelectionEvent e) {\n        int index = viewersList.getSelectedIndex();\n        if (index == -1) {\n            removeButton.setEnabled(false);\n            upButton.setEnabled(false);\n            downButton.setEnabled(false);\n        } else {\n            removeButton.setEnabled(true);\n            if (index == 0) {\n                upButton.setEnabled(false);\n            } else {\n                upButton.setEnabled(true);\n            }\n            if (index == ((DefaultListModel) viewersList.getModel()).getSize()) {\n                downButton.setEnabled(false);\n            } else {\n                downButton.setEnabled(true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorNodeViewersPanel.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.swing.JPanel;\nimport javax.swing.JTabbedPane;\nimport javax.swing.event.ChangeEvent;\nimport javax.swing.event.ChangeListener;\nimport javax.swing.event.TreeSelectionEvent;\nimport javax.swing.event.TreeSelectionListener;\nimport javax.swing.tree.TreePath;\n\nimport org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorManager;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;\n\n/**\n * This is the {@link JPanel} which contains the {@link ZooInspectorNodeViewer}s\n */\npublic class ZooInspectorNodeViewersPanel extends JPanel implements\n        TreeSelectionListener, ChangeListener {\n\n    private final List<ZooInspectorNodeViewer> nodeVeiwers = new ArrayList<ZooInspectorNodeViewer>();\n    private final List<Boolean> needsReload = new ArrayList<Boolean>();\n    private final JTabbedPane tabbedPane;\n    private final List<String> selectedNodes = new ArrayList<String>();\n    private final ZooInspectorNodeManager zooInspectorManager;\n\n    /**\n     * @param zooInspectorManager\n     *            - the {@link ZooInspectorManager} for the application\n     * @param nodeVeiwers\n     *            - the {@link ZooInspectorNodeViewer}s to show\n     */\n    public ZooInspectorNodeViewersPanel(\n            ZooInspectorNodeManager zooInspectorManager,\n            List<ZooInspectorNodeViewer> nodeVeiwers) {\n        this.zooInspectorManager = zooInspectorManager;\n        this.setLayout(new BorderLayout());\n        tabbedPane = new JTabbedPane(JTabbedPane.TOP,\n                JTabbedPane.WRAP_TAB_LAYOUT);\n        setNodeViewers(nodeVeiwers);\n        tabbedPane.addChangeListener(this);\n        this.add(tabbedPane, BorderLayout.CENTER);\n        reloadSelectedViewer();\n    }\n\n    /**\n     * @param nodeViewers\n     *            - the {@link ZooInspectorNodeViewer}s to show\n     */\n    public void setNodeViewers(List<ZooInspectorNodeViewer> nodeViewers) {\n        this.nodeVeiwers.clear();\n        this.nodeVeiwers.addAll(nodeViewers);\n        needsReload.clear();\n        tabbedPane.removeAll();\n        for (ZooInspectorNodeViewer nodeViewer : nodeVeiwers) {\n            nodeViewer.setZooInspectorManager(zooInspectorManager);\n            needsReload.add(true);\n            tabbedPane.add(nodeViewer.getTitle(), nodeViewer);\n        }\n        this.revalidate();\n        this.repaint();\n    }\n\n    private void reloadSelectedViewer() {\n        int index = this.tabbedPane.getSelectedIndex();\n        if (index != -1 && this.needsReload.get(index)) {\n            ZooInspectorNodeViewer viewer = this.nodeVeiwers.get(index);\n            viewer.nodeSelectionChanged(selectedNodes);\n            this.needsReload.set(index, false);\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event\n     * .TreeSelectionEvent)\n     */\n    public void valueChanged(TreeSelectionEvent e) {\n        TreePath[] paths = e.getPaths();\n        selectedNodes.clear();\n        for (TreePath path : paths) {\n            boolean appended = false;\n            StringBuilder sb = new StringBuilder();\n            Object[] pathArray = path.getPath();\n            for (Object o : pathArray) {\n                if (o != null) {\n                    String nodeName = o.toString();\n                    if (nodeName != null) {\n                        if (nodeName.length() > 0) {\n                            appended = true;\n                            sb.append(\"/\"); //$NON-NLS-1$\n                            sb.append(o.toString());\n                        }\n                    }\n                }\n            }\n            if (appended) {\n                selectedNodes.add(sb.toString());\n            }\n        }\n        for (int i = 0; i < needsReload.size(); i++) {\n            this.needsReload.set(i, true);\n        }\n        reloadSelectedViewer();\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent\n     * )\n     */\n    public void stateChanged(ChangeEvent e) {\n        reloadSelectedViewer();\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorPanel.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.ExecutionException;\n\nimport javax.swing.JButton;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JSplitPane;\nimport javax.swing.JToolBar;\nimport javax.swing.SwingWorker;\n\nimport org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorManager;\n\n/**\n * The parent {@link JPanel} for the whole application\n */\npublic class ZooInspectorPanel extends JPanel implements\n        NodeViewersChangeListener {\n    private final JButton refreshButton;\n    private final JButton disconnectButton;\n    private final JButton connectButton;\n    private final ZooInspectorNodeViewersPanel nodeViewersPanel;\n    private final ZooInspectorTreeViewer treeViewer;\n    private final ZooInspectorManager zooInspectorManager;\n    private final JButton addNodeButton;\n    private final JButton deleteNodeButton;\n    private final JButton nodeViewersButton;\n    private final JButton aboutButton;\n    private final List<NodeViewersChangeListener> listeners = new ArrayList<NodeViewersChangeListener>();\n    {\n        listeners.add(this);\n    }\n\n    /**\n     * @param zooInspectorManager\n     *            - the {@link ZooInspectorManager} for the application\n     */\n    public ZooInspectorPanel(final ZooInspectorManager zooInspectorManager) {\n        this.zooInspectorManager = zooInspectorManager;\n        final ArrayList<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();\n        try {\n            List<String> defaultNodeViewersClassNames = this.zooInspectorManager\n                    .getDefaultNodeViewerConfiguration();\n            for (String className : defaultNodeViewersClassNames) {\n                nodeViewers.add((ZooInspectorNodeViewer) Class.forName(\n                        className).newInstance());\n            }\n        } catch (Exception ex) {\n            LoggerFactory.getLogger().error(\n                    \"Error loading default node viewers.\", ex);\n            JOptionPane.showMessageDialog(ZooInspectorPanel.this,\n                    \"Error loading default node viewers: \" + ex.getMessage(),\n                    \"Error\", JOptionPane.ERROR_MESSAGE);\n        }\n        nodeViewersPanel = new ZooInspectorNodeViewersPanel(\n                zooInspectorManager, nodeViewers);\n        treeViewer = new ZooInspectorTreeViewer(zooInspectorManager,\n                nodeViewersPanel);\n        this.setLayout(new BorderLayout());\n        JToolBar toolbar = new JToolBar();\n        toolbar.setFloatable(false);\n        connectButton = new JButton(ZooInspectorIconResources.getConnectIcon());\n        disconnectButton = new JButton(ZooInspectorIconResources\n                .getDisconnectIcon());\n        refreshButton = new JButton(ZooInspectorIconResources.getRefreshIcon());\n        addNodeButton = new JButton(ZooInspectorIconResources.getAddNodeIcon());\n        deleteNodeButton = new JButton(ZooInspectorIconResources\n                .getDeleteNodeIcon());\n        nodeViewersButton = new JButton(ZooInspectorIconResources\n                .getChangeNodeViewersIcon());\n        aboutButton = new JButton(ZooInspectorIconResources\n                .getInformationIcon());\n        toolbar.add(connectButton);\n        toolbar.add(disconnectButton);\n        toolbar.add(refreshButton);\n        toolbar.add(addNodeButton);\n        toolbar.add(deleteNodeButton);\n        toolbar.add(nodeViewersButton);\n        toolbar.add(aboutButton);\n        aboutButton.setEnabled(true);\n        connectButton.setEnabled(true);\n        disconnectButton.setEnabled(false);\n        refreshButton.setEnabled(false);\n        addNodeButton.setEnabled(false);\n        deleteNodeButton.setEnabled(false);\n        nodeViewersButton.setEnabled(true);\n        nodeViewersButton.setToolTipText(\"Change Node Viewers\");\n        aboutButton.setToolTipText(\"About ZooInspector\");\n        connectButton.setToolTipText(\"Connect\");\n        disconnectButton.setToolTipText(\"Disconnect\");\n        refreshButton.setToolTipText(\"Refresh\");\n        addNodeButton.setToolTipText(\"Add Node\");\n        deleteNodeButton.setToolTipText(\"Delete Node\");\n        connectButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorConnectionPropertiesDialog zicpd = new ZooInspectorConnectionPropertiesDialog(\n                        zooInspectorManager.getLastConnectionProps(),\n                        zooInspectorManager.getConnectionPropertiesTemplate(),\n                        ZooInspectorPanel.this);\n                zicpd.setVisible(true);\n            }\n        });\n        disconnectButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                disconnect();\n            }\n        });\n        refreshButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                treeViewer.refreshView();\n            }\n        });\n        addNodeButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                final List<String> selectedNodes = treeViewer\n                        .getSelectedNodes();\n                if (selectedNodes.size() == 1) {\n                    final String nodeName = JOptionPane.showInputDialog(\n                            ZooInspectorPanel.this,\n                            \"Please Enter a name for the new node\",\n                            \"Create Node\", JOptionPane.INFORMATION_MESSAGE);\n                    if (nodeName != null && nodeName.length() > 0) {\n                        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {\n\n                            @Override\n                            protected Boolean doInBackground() throws Exception {\n                                return ZooInspectorPanel.this.zooInspectorManager\n                                        .createNode(selectedNodes.get(0),\n                                                nodeName);\n                            }\n\n                            @Override\n                            protected void done() {\n                                treeViewer.refreshView();\n                            }\n                        };\n                        worker.execute();\n                    }\n                } else {\n                    JOptionPane.showMessageDialog(ZooInspectorPanel.this,\n                            \"Please select 1 parent node for the new node.\");\n                }\n            }\n        });\n        deleteNodeButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                final List<String> selectedNodes = treeViewer\n                        .getSelectedNodes();\n                if (selectedNodes.size() == 0) {\n                    JOptionPane.showMessageDialog(ZooInspectorPanel.this,\n                            \"Please select at least 1 node to be deleted\");\n                } else {\n                    int answer = JOptionPane.showConfirmDialog(\n                            ZooInspectorPanel.this,\n                            \"Are you sure you want to delete the selected nodes?\"\n                                    + \"(This action cannot be reverted)\",\n                            \"Confirm Delete\", JOptionPane.YES_NO_OPTION,\n                            JOptionPane.WARNING_MESSAGE);\n                    if (answer == JOptionPane.YES_OPTION) {\n                        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {\n\n                            @Override\n                            protected Boolean doInBackground() throws Exception {\n                                for (String nodePath : selectedNodes) {\n                                    ZooInspectorPanel.this.zooInspectorManager\n                                            .deleteNode(nodePath);\n                                }\n                                return true;\n                            }\n\n                            @Override\n                            protected void done() {\n                                treeViewer.refreshView();\n                            }\n                        };\n                        worker.execute();\n                    }\n                }\n            }\n        });\n        nodeViewersButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorNodeViewersDialog nvd = new ZooInspectorNodeViewersDialog(\n                        JOptionPane.getRootFrame(), nodeViewers, listeners,\n                        zooInspectorManager);\n                nvd.setVisible(true);\n            }\n        });\n        aboutButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                ZooInspectorAboutDialog zicpd = new ZooInspectorAboutDialog(\n                        JOptionPane.getRootFrame());\n                zicpd.setVisible(true);\n            }\n        });\n        JScrollPane treeScroller = new JScrollPane(treeViewer);\n        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,\n                treeScroller, nodeViewersPanel);\n        splitPane.setResizeWeight(0.25);\n        this.add(splitPane, BorderLayout.CENTER);\n        this.add(toolbar, BorderLayout.NORTH);\n    }\n\n    /**\n     * @param connectionProps\n     *            the {@link Properties} for connecting to the zookeeper\n     *            instance\n     */\n    public void connect(final Properties connectionProps) {\n        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {\n\n            @Override\n            protected Boolean doInBackground() throws Exception {\n                zooInspectorManager.setLastConnectionProps(connectionProps);\n                return zooInspectorManager.connect(connectionProps);\n            }\n\n            @Override\n            protected void done() {\n                try {\n                    if (get()) {\n                        treeViewer.refreshView();\n                        connectButton.setEnabled(false);\n                        disconnectButton.setEnabled(true);\n                        refreshButton.setEnabled(true);\n                        addNodeButton.setEnabled(true);\n                        deleteNodeButton.setEnabled(true);\n                    } else {\n                        JOptionPane.showMessageDialog(ZooInspectorPanel.this,\n                                \"Unable to connect to zookeeper\", \"Error\",\n                                JOptionPane.ERROR_MESSAGE);\n                    }\n                } catch (InterruptedException e) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"Error occurred while connecting to ZooKeeper server\",\n                                    e);\n                } catch (ExecutionException e) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"Error occurred while connecting to ZooKeeper server\",\n                                    e);\n                }\n            }\n\n        };\n        worker.execute();\n    }\n\n    /**\n\t * \n\t */\n    public void disconnect() {\n        disconnect(false);\n    }\n\n    /**\n     * @param wait\n     *            - set this to true if the method should only return once the\n     *            application has successfully disconnected\n     */\n    public void disconnect(boolean wait) {\n        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {\n\n            @Override\n            protected Boolean doInBackground() throws Exception {\n                return ZooInspectorPanel.this.zooInspectorManager.disconnect();\n            }\n\n            @Override\n            protected void done() {\n                try {\n                    if (get()) {\n                        treeViewer.clearView();\n                        connectButton.setEnabled(true);\n                        disconnectButton.setEnabled(false);\n                        refreshButton.setEnabled(false);\n                        addNodeButton.setEnabled(false);\n                        deleteNodeButton.setEnabled(false);\n                    }\n                } catch (InterruptedException e) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"Error occurred while disconnecting from ZooKeeper server\",\n                                    e);\n                } catch (ExecutionException e) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"Error occurred while disconnecting from ZooKeeper server\",\n                                    e);\n                }\n            }\n\n        };\n        worker.execute();\n        if (wait) {\n            while (!worker.isDone()) {\n                try {\n                    Thread.sleep(100);\n                } catch (InterruptedException e) {\n                    LoggerFactory\n                            .getLogger()\n                            .error(\n                                    \"Error occurred while disconnecting from ZooKeeper server\",\n                                    e);\n                }\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.gui.NodeViewersChangeListener#\n     * nodeViewersChanged(java.util.List)\n     */\n    public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers) {\n        this.nodeViewersPanel.setNodeViewers(newViewers);\n    }\n\n    /**\n     * @param connectionProps\n     * @throws IOException\n     */\n    public void setdefaultConnectionProps(Properties connectionProps)\n            throws IOException {\n        this.zooInspectorManager.saveDefaultConnectionFile(connectionProps);\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/ZooInspectorTreeViewer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.awt.event.MouseAdapter;\nimport java.awt.event.MouseEvent;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.swing.JMenuItem;\nimport javax.swing.JPanel;\nimport javax.swing.JPopupMenu;\nimport javax.swing.JTree;\nimport javax.swing.SwingWorker;\nimport javax.swing.event.TreeSelectionListener;\nimport javax.swing.tree.DefaultMutableTreeNode;\nimport javax.swing.tree.DefaultTreeCellRenderer;\nimport javax.swing.tree.DefaultTreeModel;\nimport javax.swing.tree.TreeNode;\nimport javax.swing.tree.TreePath;\n\nimport org.apache.zookeeper.inspector.manager.NodeListener;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorManager;\n\nimport com.nitido.utils.toaster.Toaster;\n\n/**\n * A {@link JPanel} for showing the tree view of all the nodes in the zookeeper\n * instance\n */\npublic class ZooInspectorTreeViewer extends JPanel implements NodeListener {\n    private final ZooInspectorManager zooInspectorManager;\n    private final JTree tree;\n    private final Toaster toasterManager;\n\n    /**\n     * @param zooInspectorManager\n     *            - the {@link ZooInspectorManager} for the application\n     * @param listener\n     *            - the {@link TreeSelectionListener} to listen for changes in\n     *            the selected node on the node tree\n     */\n    public ZooInspectorTreeViewer(\n            final ZooInspectorManager zooInspectorManager,\n            TreeSelectionListener listener) {\n        this.zooInspectorManager = zooInspectorManager;\n        this.setLayout(new BorderLayout());\n        final JPopupMenu popupMenu = new JPopupMenu();\n        final JMenuItem addNotify = new JMenuItem(\"Add Change Notification\");\n        this.toasterManager = new Toaster();\n        this.toasterManager.setBorderColor(Color.BLACK);\n        this.toasterManager.setMessageColor(Color.BLACK);\n        this.toasterManager.setToasterColor(Color.WHITE);\n        addNotify.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                List<String> selectedNodes = getSelectedNodes();\n                zooInspectorManager.addWatchers(selectedNodes,\n                        ZooInspectorTreeViewer.this);\n            }\n        });\n        final JMenuItem removeNotify = new JMenuItem(\n                \"Remove Change Notification\");\n        removeNotify.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                List<String> selectedNodes = getSelectedNodes();\n                zooInspectorManager.removeWatchers(selectedNodes);\n            }\n        });\n        tree = new JTree(new DefaultMutableTreeNode());\n        tree.setCellRenderer(new ZooInspectorTreeCellRenderer());\n        tree.setEditable(false);\n        tree.getSelectionModel().addTreeSelectionListener(listener);\n        tree.addMouseListener(new MouseAdapter() {\n            @Override\n            public void mouseClicked(MouseEvent e) {\n                if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {\n                    // TODO only show add if a selected node isn't being\n                    // watched, and only show remove if a selected node is being\n                    // watched\n                    popupMenu.removeAll();\n                    popupMenu.add(addNotify);\n                    popupMenu.add(removeNotify);\n                    popupMenu.show(ZooInspectorTreeViewer.this, e.getX(), e\n                            .getY());\n                }\n            }\n        });\n        this.add(tree, BorderLayout.CENTER);\n    }\n\n    /**\n     * Refresh the tree view\n     */\n    public void refreshView() {\n        final Set<TreePath> expandedNodes = new LinkedHashSet<TreePath>();\n        int rowCount = tree.getRowCount();\n        for (int i = 0; i < rowCount; i++) {\n            TreePath path = tree.getPathForRow(i);\n            if (tree.isExpanded(path)) {\n                expandedNodes.add(path);\n            }\n        }\n        final TreePath[] selectedNodes = tree.getSelectionPaths();\n        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {\n\n            @Override\n            protected Boolean doInBackground() throws Exception {\n                tree.setModel(new DefaultTreeModel(new ZooInspectorTreeNode(\n                        \"/\", null)));\n                return true;\n            }\n\n            @Override\n            protected void done() {\n                for (TreePath path : expandedNodes) {\n                    tree.expandPath(path);\n                }\n                tree.getSelectionModel().setSelectionPaths(selectedNodes);\n            }\n        };\n        worker.execute();\n    }\n\n    /**\n     * clear the tree view of all nodes\n     */\n    public void clearView() {\n        tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));\n    }\n\n    /**\n     * @author Colin\n     * \n     */\n    private static class ZooInspectorTreeCellRenderer extends\n            DefaultTreeCellRenderer {\n        public ZooInspectorTreeCellRenderer() {\n            setLeafIcon(ZooInspectorIconResources.getTreeLeafIcon());\n            setOpenIcon(ZooInspectorIconResources.getTreeOpenIcon());\n            setClosedIcon(ZooInspectorIconResources.getTreeClosedIcon());\n        }\n    }\n\n    /**\n     * @author Colin\n     * \n     */\n    private class ZooInspectorTreeNode implements TreeNode {\n        private final String nodePath;\n        private final String nodeName;\n        private final ZooInspectorTreeNode parent;\n\n        public ZooInspectorTreeNode(String nodePath, ZooInspectorTreeNode parent) {\n            this.parent = parent;\n            this.nodePath = nodePath;\n            int index = nodePath.lastIndexOf(\"/\");\n            if (index == -1) {\n                throw new IllegalArgumentException(\"Invalid node path\"\n                        + nodePath);\n            }\n            this.nodeName = nodePath.substring(index + 1);\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#children()\n         */\n        public Enumeration<TreeNode> children() {\n            List<String> children = zooInspectorManager\n                    .getChildren(this.nodePath);\n            Collections.sort(children);\n            List<TreeNode> returnChildren = new ArrayList<TreeNode>();\n            for (String child : children) {\n                returnChildren.add(new ZooInspectorTreeNode((this.nodePath\n                        .equals(\"/\") ? \"\" : this.nodePath)\n                        + \"/\" + child, this));\n            }\n            return Collections.enumeration(returnChildren);\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#getAllowsChildren()\n         */\n        public boolean getAllowsChildren() {\n            return zooInspectorManager.isAllowsChildren(this.nodePath);\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#getChildAt(int)\n         */\n        public TreeNode getChildAt(int childIndex) {\n            String child = zooInspectorManager.getNodeChild(this.nodePath,\n                    childIndex);\n            if (child != null) {\n                return new ZooInspectorTreeNode((this.nodePath.equals(\"/\") ? \"\"\n                        : this.nodePath)\n                        + \"/\" + child, this);\n            }\n            return null;\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#getChildCount()\n         */\n        public int getChildCount() {\n            return zooInspectorManager.getNumChildren(this.nodePath);\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#getIndex(javax.swing.tree.TreeNode)\n         */\n        public int getIndex(TreeNode node) {\n            return zooInspectorManager.getNodeIndex(this.nodePath);\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#getParent()\n         */\n        public TreeNode getParent() {\n            return this.parent;\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see javax.swing.tree.TreeNode#isLeaf()\n         */\n        public boolean isLeaf() {\n            return !zooInspectorManager.hasChildren(this.nodePath);\n        }\n\n        @Override\n        public String toString() {\n            return this.nodeName;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + getOuterType().hashCode();\n            result = prime * result\n                    + ((nodePath == null) ? 0 : nodePath.hashCode());\n            result = prime * result\n                    + ((parent == null) ? 0 : parent.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj)\n                return true;\n            if (obj == null)\n                return false;\n            if (getClass() != obj.getClass())\n                return false;\n            ZooInspectorTreeNode other = (ZooInspectorTreeNode) obj;\n            if (!getOuterType().equals(other.getOuterType()))\n                return false;\n            if (nodePath == null) {\n                if (other.nodePath != null)\n                    return false;\n            } else if (!nodePath.equals(other.nodePath))\n                return false;\n            if (parent == null) {\n                if (other.parent != null)\n                    return false;\n            } else if (!parent.equals(other.parent))\n                return false;\n            return true;\n        }\n\n        private ZooInspectorTreeViewer getOuterType() {\n            return ZooInspectorTreeViewer.this;\n        }\n\n    }\n\n    /**\n     * @return {@link List} of the currently selected nodes\n     */\n    public List<String> getSelectedNodes() {\n        TreePath[] paths = tree.getSelectionPaths();\n        List<String> selectedNodes = new ArrayList<String>();\n        if (paths != null) {\n            for (TreePath path : paths) {\n                StringBuilder sb = new StringBuilder();\n                Object[] pathArray = path.getPath();\n                for (Object o : pathArray) {\n                    String nodeName = o.toString();\n                    if (nodeName.length() > 0) {\n                        sb.append(\"/\");\n                        sb.append(o.toString());\n                    }\n                }\n                selectedNodes.add(sb.toString());\n            }\n        }\n        return selectedNodes;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.NodeListener#processEvent(java\n     * .lang.String, java.lang.String, java.util.Map)\n     */\n    public void processEvent(String nodePath, String eventType,\n            Map<String, String> eventInfo) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Node: \");\n        sb.append(nodePath);\n        sb.append(\"\\nEvent: \");\n        sb.append(eventType);\n        if (eventInfo != null) {\n            for (Map.Entry<String, String> entry : eventInfo.entrySet()) {\n                sb.append(\"\\n\");\n                sb.append(entry.getKey());\n                sb.append(\": \");\n                sb.append(entry.getValue());\n            }\n        }\n        this.toasterManager.showToaster(ZooInspectorIconResources\n                .getInformationIcon(), sb.toString());\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>ZooInspector v0.1</title>\n</head>\n<body>\n<p>ZooInspector was developed by Colin Goodheart-Smithe and is\navailable under the Apache Software Licence v2.0.</p>\n<p>The Icons used were sourced from the Eclipse project (<a\n\thref=\"http://www.eclipse.org\">http://www.eclipse.org</a>) and licensed\nunder the Eclipse Public Licence v1.0. [<a\n\thref=\"http://www.eclipse.org/org/documents/epl-v10.php\">http://www.eclipse.org/org/documents/epl-v10.php</a>]\n</p>\n<p>ZooKeeper is available from <a\n\thref=\"http://zookeeper.apache.org/\">http://zookeeper.apache.org/</a>\nand is licensed under an Apache Software Licence v2.0</p>\n<p>The ApacheSoftware Licence v2.0 can be found at <a\n\thref=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</a></p>\n</body>\n</html>\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/nodeviewer/NodeViewerACL.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui.nodeviewer;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.GridBagConstraints;\nimport java.awt.GridBagLayout;\nimport java.awt.Insets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\n\nimport javax.swing.BorderFactory;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextField;\nimport javax.swing.SwingWorker;\n\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;\n\n/**\n * A node viewer for displaying the ACLs currently applied to the selected node\n */\npublic class NodeViewerACL extends ZooInspectorNodeViewer {\n    private ZooInspectorNodeManager zooInspectorManager;\n    private final JPanel aclDataPanel;\n    private String selectedNode;\n\n    /**\n\t * \n\t */\n    public NodeViewerACL() {\n        this.setLayout(new BorderLayout());\n        this.aclDataPanel = new JPanel();\n        this.aclDataPanel.setBackground(Color.WHITE);\n        JScrollPane scroller = new JScrollPane(this.aclDataPanel);\n        this.add(scroller, BorderLayout.CENTER);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * getTitle()\n     */\n    @Override\n    public String getTitle() {\n        return \"Node ACLs\";\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * nodeSelectionChanged(java.util.Set)\n     */\n    @Override\n    public void nodeSelectionChanged(List<String> selectedNodes) {\n        this.aclDataPanel.removeAll();\n        if (selectedNodes.size() > 0) {\n            this.selectedNode = selectedNodes.get(0);\n            SwingWorker<List<Map<String, String>>, Void> worker = new SwingWorker<List<Map<String, String>>, Void>() {\n\n                @Override\n                protected List<Map<String, String>> doInBackground()\n                        throws Exception {\n                    return NodeViewerACL.this.zooInspectorManager\n                            .getACLs(NodeViewerACL.this.selectedNode);\n                }\n\n                @Override\n                protected void done() {\n                    List<Map<String, String>> acls = null;\n                    try {\n                        acls = get();\n                    } catch (InterruptedException e) {\n                        acls = new ArrayList<Map<String, String>>();\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving ACL Information for node: \"\n                                        + NodeViewerACL.this.selectedNode, e);\n                    } catch (ExecutionException e) {\n                        acls = new ArrayList<Map<String, String>>();\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving ACL Information for node: \"\n                                        + NodeViewerACL.this.selectedNode, e);\n                    }\n                    aclDataPanel.setLayout(new GridBagLayout());\n                    int j = 0;\n                    for (Map<String, String> data : acls) {\n                        int rowPos = 2 * j + 1;\n                        JPanel aclPanel = new JPanel();\n                        aclPanel.setBorder(BorderFactory\n                                .createLineBorder(Color.BLACK));\n                        aclPanel.setBackground(Color.WHITE);\n                        aclPanel.setLayout(new GridBagLayout());\n                        int i = 0;\n                        for (Map.Entry<String, String> entry : data.entrySet()) {\n                            int rowPosACL = 2 * i + 1;\n                            JLabel label = new JLabel(entry.getKey());\n                            JTextField text = new JTextField(entry.getValue());\n                            text.setEditable(false);\n                            GridBagConstraints c1 = new GridBagConstraints();\n                            c1.gridx = 1;\n                            c1.gridy = rowPosACL;\n                            c1.gridwidth = 1;\n                            c1.gridheight = 1;\n                            c1.weightx = 0;\n                            c1.weighty = 0;\n                            c1.anchor = GridBagConstraints.NORTHWEST;\n                            c1.fill = GridBagConstraints.BOTH;\n                            c1.insets = new Insets(5, 5, 5, 5);\n                            c1.ipadx = 0;\n                            c1.ipady = 0;\n                            aclPanel.add(label, c1);\n                            GridBagConstraints c2 = new GridBagConstraints();\n                            c2.gridx = 3;\n                            c2.gridy = rowPosACL;\n                            c2.gridwidth = 1;\n                            c2.gridheight = 1;\n                            c2.weightx = 0;\n                            c2.weighty = 0;\n                            c2.anchor = GridBagConstraints.NORTHWEST;\n                            c2.fill = GridBagConstraints.BOTH;\n                            c2.insets = new Insets(5, 5, 5, 5);\n                            c2.ipadx = 0;\n                            c2.ipady = 0;\n                            aclPanel.add(text, c2);\n                            i++;\n                        }\n                        GridBagConstraints c = new GridBagConstraints();\n                        c.gridx = 1;\n                        c.gridy = rowPos;\n                        c.gridwidth = 1;\n                        c.gridheight = 1;\n                        c.weightx = 1;\n                        c.weighty = 1;\n                        c.anchor = GridBagConstraints.NORTHWEST;\n                        c.fill = GridBagConstraints.NONE;\n                        c.insets = new Insets(5, 5, 5, 5);\n                        c.ipadx = 0;\n                        c.ipady = 0;\n                        aclDataPanel.add(aclPanel, c);\n                    }\n                    NodeViewerACL.this.aclDataPanel.revalidate();\n                    NodeViewerACL.this.aclDataPanel.repaint();\n                }\n            };\n            worker.execute();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * setZooInspectorManager\n     * (org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager)\n     */\n    @Override\n    public void setZooInspectorManager(\n            ZooInspectorNodeManager zooInspectorManager) {\n        this.zooInspectorManager = zooInspectorManager;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/nodeviewer/NodeViewerData.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui.nodeviewer;\n\nimport java.awt.BorderLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\nimport javax.swing.JButton;\nimport javax.swing.JOptionPane;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextPane;\nimport javax.swing.JToolBar;\nimport javax.swing.SwingWorker;\n\nimport org.apache.zookeeper.inspector.gui.ZooInspectorIconResources;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;\n\n/**\n * A node viewer for displaying the data for the currently selected node\n */\npublic class NodeViewerData extends ZooInspectorNodeViewer {\n    private ZooInspectorNodeManager zooInspectorManager;\n    private final JTextPane dataArea;\n    private final JToolBar toolbar;\n    private String selectedNode;\n\n    /**\n\t * \n\t */\n    public NodeViewerData() {\n        this.setLayout(new BorderLayout());\n        this.dataArea = new JTextPane();\n        this.toolbar = new JToolBar();\n        this.toolbar.setFloatable(false);\n        JScrollPane scroller = new JScrollPane(this.dataArea);\n        scroller\n                .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);\n        this.add(scroller, BorderLayout.CENTER);\n        this.add(this.toolbar, BorderLayout.NORTH);\n        JButton saveButton = new JButton(ZooInspectorIconResources\n                .getSaveIcon());\n        saveButton.addActionListener(new ActionListener() {\n\n            public void actionPerformed(ActionEvent e) {\n                if (selectedNode != null) {\n                    if (JOptionPane.showConfirmDialog(NodeViewerData.this,\n                            \"Are you sure you want to save this node?\"\n                                    + \" (this action cannot be reverted)\",\n                            \"Confirm Save\", JOptionPane.YES_NO_OPTION,\n                            JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {\n                        zooInspectorManager.setData(selectedNode, dataArea\n                                .getText());\n                    }\n                }\n            }\n        });\n        this.toolbar.add(saveButton);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * getTitle()\n     */\n    @Override\n    public String getTitle() {\n        return \"Node Data\";\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * nodeSelectionChanged(java.util.Set)\n     */\n    @Override\n    public void nodeSelectionChanged(List<String> selectedNodes) {\n        if (selectedNodes.size() > 0) {\n            this.selectedNode = selectedNodes.get(0);\n            SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {\n\n                @Override\n                protected String doInBackground() throws Exception {\n                    return NodeViewerData.this.zooInspectorManager\n                            .getData(NodeViewerData.this.selectedNode);\n                }\n\n                @Override\n                protected void done() {\n                    String data = \"\";\n                    try {\n                        data = get();\n                    } catch (InterruptedException e) {\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving data for node: \"\n                                        + NodeViewerData.this.selectedNode, e);\n                    } catch (ExecutionException e) {\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving data for node: \"\n                                        + NodeViewerData.this.selectedNode, e);\n                    }\n                    NodeViewerData.this.dataArea.setText(data);\n                }\n            };\n            worker.execute();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * setZooInspectorManager\n     * (org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager)\n     */\n    @Override\n    public void setZooInspectorManager(\n            ZooInspectorNodeManager zooInspectorManager) {\n        this.zooInspectorManager = zooInspectorManager;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/nodeviewer/NodeViewerMetaData.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui.nodeviewer;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.GridBagConstraints;\nimport java.awt.GridBagLayout;\nimport java.awt.Insets;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\n\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextField;\nimport javax.swing.SwingWorker;\n\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;\n\n/**\n * A node viewer for displaying the meta data for the currently selected node.\n * The meta data is essentially the information from the {@link Stat} for the\n * node\n */\npublic class NodeViewerMetaData extends ZooInspectorNodeViewer {\n    private ZooInspectorNodeManager zooInspectorManager;\n    private final JPanel metaDataPanel;\n    private String selectedNode;\n\n    /**\n\t * \n\t */\n    public NodeViewerMetaData() {\n        this.setLayout(new BorderLayout());\n        this.metaDataPanel = new JPanel();\n        this.metaDataPanel.setBackground(Color.WHITE);\n        JScrollPane scroller = new JScrollPane(this.metaDataPanel);\n        this.add(scroller, BorderLayout.CENTER);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * getTitle()\n     */\n    @Override\n    public String getTitle() {\n        return \"Node Metadata\";\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * nodeSelectionChanged(java.util.Set)\n     */\n    @Override\n    public void nodeSelectionChanged(List<String> selectedNodes) {\n        this.metaDataPanel.removeAll();\n        if (selectedNodes.size() > 0) {\n            this.selectedNode = selectedNodes.get(0);\n            SwingWorker<Map<String, String>, Void> worker = new SwingWorker<Map<String, String>, Void>() {\n\n                @Override\n                protected Map<String, String> doInBackground() throws Exception {\n                    return NodeViewerMetaData.this.zooInspectorManager\n                            .getNodeMeta(NodeViewerMetaData.this.selectedNode);\n                }\n\n                @Override\n                protected void done() {\n                    Map<String, String> data = null;\n                    try {\n                        data = get();\n                    } catch (InterruptedException e) {\n                        data = new HashMap<String, String>();\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving meta data for node: \"\n                                        + NodeViewerMetaData.this.selectedNode,\n                                e);\n                    } catch (ExecutionException e) {\n                        data = new HashMap<String, String>();\n                        LoggerFactory.getLogger().error(\n                                \"Error retrieving meta data for node: \"\n                                        + NodeViewerMetaData.this.selectedNode,\n                                e);\n                    }\n                    NodeViewerMetaData.this.metaDataPanel\n                            .setLayout(new GridBagLayout());\n                    JPanel infoPanel = new JPanel();\n                    infoPanel.setBackground(Color.WHITE);\n                    infoPanel.setLayout(new GridBagLayout());\n                    int i = 0;\n                    int rowPos = 0;\n                    for (Map.Entry<String, String> entry : data.entrySet()) {\n                        rowPos = 2 * i + 1;\n                        JLabel label = new JLabel(entry.getKey());\n                        JTextField text = new JTextField(entry.getValue());\n                        text.setEditable(false);\n                        GridBagConstraints c1 = new GridBagConstraints();\n                        c1.gridx = 0;\n                        c1.gridy = rowPos;\n                        c1.gridwidth = 1;\n                        c1.gridheight = 1;\n                        c1.weightx = 0;\n                        c1.weighty = 0;\n                        c1.anchor = GridBagConstraints.WEST;\n                        c1.fill = GridBagConstraints.HORIZONTAL;\n                        c1.insets = new Insets(5, 5, 5, 5);\n                        c1.ipadx = 0;\n                        c1.ipady = 0;\n                        infoPanel.add(label, c1);\n                        GridBagConstraints c2 = new GridBagConstraints();\n                        c2.gridx = 2;\n                        c2.gridy = rowPos;\n                        c2.gridwidth = 1;\n                        c2.gridheight = 1;\n                        c2.weightx = 0;\n                        c2.weighty = 0;\n                        c2.anchor = GridBagConstraints.WEST;\n                        c2.fill = GridBagConstraints.HORIZONTAL;\n                        c2.insets = new Insets(5, 5, 5, 5);\n                        c2.ipadx = 0;\n                        c2.ipady = 0;\n                        infoPanel.add(text, c2);\n                        i++;\n                    }\n                    GridBagConstraints c = new GridBagConstraints();\n                    c.gridx = 1;\n                    c.gridy = rowPos;\n                    c.gridwidth = 1;\n                    c.gridheight = 1;\n                    c.weightx = 1;\n                    c.weighty = 1;\n                    c.anchor = GridBagConstraints.NORTHWEST;\n                    c.fill = GridBagConstraints.NONE;\n                    c.insets = new Insets(5, 5, 5, 5);\n                    c.ipadx = 0;\n                    c.ipady = 0;\n                    NodeViewerMetaData.this.metaDataPanel.add(infoPanel, c);\n                    NodeViewerMetaData.this.metaDataPanel.revalidate();\n                    NodeViewerMetaData.this.metaDataPanel.repaint();\n                }\n            };\n            worker.execute();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#\n     * setZooInspectorManager\n     * (org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager)\n     */\n    @Override\n    public void setZooInspectorManager(\n            ZooInspectorNodeManager zooInspectorManager) {\n        this.zooInspectorManager = zooInspectorManager;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/gui/nodeviewer/ZooInspectorNodeViewer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.gui.nodeviewer;\n\nimport java.awt.datatransfer.DataFlavor;\nimport java.awt.datatransfer.Transferable;\nimport java.awt.datatransfer.UnsupportedFlavorException;\nimport java.io.IOException;\nimport java.util.List;\n\nimport javax.swing.JPanel;\n\nimport org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;\n\n/**\n * A {@link JPanel} for displaying information about the currently selected\n * node(s)\n */\npublic abstract class ZooInspectorNodeViewer extends JPanel implements\n        Transferable {\n    /**\n     * The {@link DataFlavor} used for DnD in the node viewer configuration\n     * dialog\n     */\n    public static final DataFlavor nodeViewerDataFlavor = new DataFlavor(\n            ZooInspectorNodeViewer.class, \"nodeviewer\");\n\n    /**\n     * @param zooInspectorManager\n     */\n    public abstract void setZooInspectorManager(\n            ZooInspectorNodeManager zooInspectorManager);\n\n    /**\n     * Called whenever the selected nodes in the tree view changes.\n     * \n     * @param selectedNodes\n     *            - the nodes currently selected in the tree view\n     * \n     */\n    public abstract void nodeSelectionChanged(List<String> selectedNodes);\n\n    /**\n     * @return the title of the node viewer. this will be shown on the tab for\n     *         this node viewer.\n     */\n    public abstract String getTitle();\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer\n     * .DataFlavor)\n     */\n    public Object getTransferData(DataFlavor flavor)\n            throws UnsupportedFlavorException, IOException {\n        if (flavor.equals(nodeViewerDataFlavor)) {\n            return this.getClass().getCanonicalName();\n        } else {\n            return null;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.awt.datatransfer.Transferable#getTransferDataFlavors()\n     */\n    public DataFlavor[] getTransferDataFlavors() {\n        return new DataFlavor[] { nodeViewerDataFlavor };\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seejava.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.\n     * datatransfer.DataFlavor)\n     */\n    public boolean isDataFlavorSupported(DataFlavor flavor) {\n        return flavor.equals(nodeViewerDataFlavor);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#hashCode()\n     */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result\n                + ((getTitle() == null) ? 0 : getTitle().hashCode());\n        return result;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#equals(java.lang.Object)\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        ZooInspectorNodeViewer other = (ZooInspectorNodeViewer) obj;\n        if (getClass().getCanonicalName() != other.getClass()\n                .getCanonicalName()) {\n            return false;\n        }\n        if (getTitle() == null) {\n            if (other.getTitle() != null)\n                return false;\n        } else if (!getTitle().equals(other.getTitle()))\n            return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/logger/LoggerFactory.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.logger;\n\n/**\n * Provides a {@link Logger} for use across the entire application\n * \n */\npublic class LoggerFactory\n{\n\tprivate static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(\"org.apache.zookeeper.inspector\"); //$NON-NLS-1$\n\n\t/**\n\t * @return {@link Logger} for ZooInspector\n\t */\n\tpublic static org.slf4j.Logger getLogger()\n\t{\n\t\treturn logger;\n\t}\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/NodeListener.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\nimport java.util.Map;\n\n/**\n * A Listener for Events on zookeeper nodes\n */\npublic interface NodeListener {\n    /**\n     * @param nodePath\n     *            - the path of the node\n     * @param eventType\n     *            - the event type\n     * @param eventInfo\n     *            - a {@link Map} containing any other information about this\n     *            event\n     */\n    public void processEvent(String nodePath, String eventType,\n            Map<String, String> eventInfo);\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/Pair.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\n/**\n * A utility class for storing a pair of objects\n * \n * @param <K>\n * @param <V>\n */\npublic class Pair<K, V> {\n    private K key;\n    private V value;\n\n    /**\n     * @param key\n     * @param value\n     */\n    public Pair(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    /**\n\t * \n\t */\n    public Pair() {\n        // Do Nothing\n    }\n\n    /**\n     * @return key\n     */\n    public K getKey() {\n        return key;\n    }\n\n    /**\n     * @param key\n     */\n    public void setKey(K key) {\n        this.key = key;\n    }\n\n    /**\n     * @return value\n     */\n    public V getValue() {\n        return value;\n    }\n\n    /**\n     * @param value\n     */\n    public void setValue(V value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return \"Pair [\" + key + \", \" + value + \"]\";\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#hashCode()\n     */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((key == null) ? 0 : key.hashCode());\n        result = prime * result + ((value == null) ? 0 : value.hashCode());\n        return result;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#equals(java.lang.Object)\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        Pair<?, ?> other = (Pair<?, ?>) obj;\n        if (key == null) {\n            if (other.key != null)\n                return false;\n        } else if (!key.equals(other.key))\n            return false;\n        if (value == null) {\n            if (other.value != null)\n                return false;\n        } else if (!value.equals(other.value))\n            return false;\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/ZooInspectorManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.swing.JComboBox;\nimport javax.swing.JTextField;\n\n/**\n * A Manager for all interactions between the application and the Zookeeper\n * instance\n */\npublic interface ZooInspectorManager extends ZooInspectorNodeManager,\n        ZooInspectorNodeTreeManager {\n\n    /**\n     * @param connectionProps\n     * @return true if successfully connected\n     */\n    public boolean connect(Properties connectionProps);\n\n    /**\n     * @return true if successfully disconnected\n     */\n    public boolean disconnect();\n\n    /**\n     * @return a {@link Pair} containing the following:\n     *         <ul>\n     *         <li>a {@link Map} of property keys to list of possible values. If\n     *         the list size is 1 the value is taken to be the default value for\n     *         a {@link JTextField}. If the list size is greater than 1, the\n     *         values are taken to be the possible options to show in a\n     *         {@link JComboBox} with the first selected as default.</li>\n     *         <li>a {@link Map} of property keys to the label to show on the UI\n     *         </li>\n     *         <ul>\n     * \n     */\n    public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate();\n\n    /**\n     * @param selectedNodes\n     *            - the nodes to add the watcher to\n     * @param nodeListener\n     *            - the node listener for this watcher\n     */\n    public void addWatchers(Collection<String> selectedNodes,\n            NodeListener nodeListener);\n\n    /**\n     * @param selectedNodes\n     *            - the nodes to remove the watchers from\n     */\n    public void removeWatchers(Collection<String> selectedNodes);\n\n    /**\n     * @param selectedFile\n     *            - the file to load which contains the node viewers\n     *            configuration\n     * @return nodeViewers - the class names of the node viewers from the\n     *         configuration\n     * @throws IOException\n     *             - if the configuration file cannot be loaded\n     */\n    public List<String> loadNodeViewersFile(File selectedFile)\n            throws IOException;\n\n    /**\n     * @param selectedFile\n     *            - the file to save the configuration to\n     * @param nodeViewersClassNames\n     *            - the class names of the node viewers\n     * @throws IOException\n     *             - if the configuration file cannot be saved\n     */\n    public void saveNodeViewersFile(File selectedFile,\n            List<String> nodeViewersClassNames) throws IOException;\n\n    /**\n     * @param nodeViewersClassNames\n     *            - the class names of the node viewers\n     * @throws IOException\n     *             - if the default configuration file cannot be loaded\n     */\n    public void setDefaultNodeViewerConfiguration(\n            List<String> nodeViewersClassNames) throws IOException;\n\n    /**\n     * @return nodeViewers - the class names of the node viewers from the\n     *         configuration\n     * @throws IOException\n     *             - if the default configuration file cannot be loaded\n     */\n    List<String> getDefaultNodeViewerConfiguration() throws IOException;\n\n    /**\n     * @param connectionProps\n     *            - the connection properties last used to connect to the\n     *            zookeeeper instance\n     */\n    public void setLastConnectionProps(Properties connectionProps);\n\n    /**\n     * @return last connection Properties - the connection properties last used\n     *         to connect to the zookeeeper instance\n     */\n    public Properties getLastConnectionProps();\n\n    /**\n     * @param props\n     *            - the properties to use as the default connection settings\n     * @throws IOException\n     *             - if the default configuration file cannot be saved\n     */\n    public void saveDefaultConnectionFile(Properties props) throws IOException;\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/ZooInspectorManagerImpl.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooDefs.Perms;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager;\nimport org.apache.zookeeper.inspector.encryption.DataEncryptionManager;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\nimport org.apache.zookeeper.retry.ZooKeeperRetry;\n\n/**\n * A default implementation of {@link ZooInspectorManager} for connecting to\n * zookeeper instances\n */\npublic class ZooInspectorManagerImpl implements ZooInspectorManager {\n    private static final String A_VERSION = \"ACL Version\";\n    private static final String C_TIME = \"Creation Time\";\n    private static final String C_VERSION = \"Children Version\";\n    private static final String CZXID = \"Creation ID\";\n    private static final String DATA_LENGTH = \"Data Length\";\n    private static final String EPHEMERAL_OWNER = \"Ephemeral Owner\";\n    private static final String M_TIME = \"Last Modified Time\";\n    private static final String MZXID = \"Modified ID\";\n    private static final String NUM_CHILDREN = \"Number of Children\";\n    private static final String PZXID = \"Node ID\";\n    private static final String VERSION = \"Data Version\";\n    private static final String ACL_PERMS = \"Permissions\";\n    private static final String ACL_SCHEME = \"Scheme\";\n    private static final String ACL_ID = \"Id\";\n    private static final String SESSION_STATE = \"Session State\";\n    private static final String SESSION_ID = \"Session ID\";\n    /**\n     * The key used for the connect string in the connection properties file\n     */\n    public static final String CONNECT_STRING = \"hosts\";\n    /**\n     * The key used for the session timeout in the connection properties file\n     */\n    public static final String SESSION_TIMEOUT = \"timeout\";\n    /**\n     * The key used for the data encryption manager in the connection properties\n     * file\n     */\n    public static final String DATA_ENCRYPTION_MANAGER = \"encryptionManager\";\n    /**\n     * The key used for the authentication scheme in the connection properties file\n     */\n    public static final String AUTH_SCHEME_KEY = \"authScheme\";\n    /**\n     * The key used for the authentication data in the connection properties file\n     */\n    public static final String AUTH_DATA_KEY = \"authData\";\n\n    private static final File defaultNodeViewersFile = new File(\n            \"./config/defaultNodeVeiwers.cfg\");\n    private static final File defaultConnectionFile = new File(\n            \"./config/defaultConnectionSettings.cfg\");\n\n    private DataEncryptionManager encryptionManager;\n    private String connectString;\n    private int sessionTimeout;\n    private ZooKeeper zooKeeper;\n    private final Map<String, NodeWatcher> watchers = new HashMap<String, NodeWatcher>();\n    protected boolean connected = true;\n    private Properties lastConnectionProps;\n    private String defaultEncryptionManager;\n    private String defaultTimeout;\n    private String defaultHosts;\n    private String defaultAuthScheme;\n    private String defaultAuthValue;\n\n    /**\n     * @throws IOException\n     *             - thrown if the default connection settings cannot be loaded\n     * \n     */\n    public ZooInspectorManagerImpl() throws IOException {\n        loadDefaultConnectionFile();\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorManager#connect(java\n     * .util.Properties)\n     */\n    public boolean connect(Properties connectionProps) {\n        try {\n            if (this.zooKeeper == null) {\n                String connectString = connectionProps\n                        .getProperty(CONNECT_STRING);\n                String sessionTimeout = connectionProps\n                        .getProperty(SESSION_TIMEOUT);\n                String encryptionManager = connectionProps\n                        .getProperty(DATA_ENCRYPTION_MANAGER);\n                String authScheme = connectionProps\n                        .getProperty(AUTH_SCHEME_KEY);\n                String authData = connectionProps\n                        .getProperty(AUTH_DATA_KEY);\n\n                if (connectString == null || sessionTimeout == null) {\n                    throw new IllegalArgumentException(\n                            \"Both connect string and session timeout are required.\");\n                }\n                if (encryptionManager == null) {\n                    this.encryptionManager = new BasicDataEncryptionManager();\n                } else {\n                    Class<?> clazz = Class.forName(encryptionManager);\n\n                    if (Arrays.asList(clazz.getInterfaces()).contains(\n                            DataEncryptionManager.class)) {\n                        this.encryptionManager = (DataEncryptionManager) Class\n                                .forName(encryptionManager).newInstance();\n                    } else {\n                        throw new IllegalArgumentException(\n                                \"Data encryption manager must implement DataEncryptionManager interface\");\n                    }\n                }\n                this.connectString = connectString;\n                this.sessionTimeout = Integer.valueOf(sessionTimeout);\n                this.zooKeeper = new ZooKeeperRetry(connectString, Integer\n                        .valueOf(sessionTimeout), new Watcher() {\n\n                    public void process(WatchedEvent event) {\n                        if (event.getState() == KeeperState.Expired) {\n                            connected = false;\n                        }\n                    }\n                });\n                if (authData != null && authData.length() > 0){\n                    this.zooKeeper.addAuthInfo(authScheme, authData.getBytes());\n                }\n                ((ZooKeeperRetry) this.zooKeeper).setRetryLimit(10);\n                connected = ((ZooKeeperRetry) this.zooKeeper).testConnection();\n            }\n        } catch (Exception e) {\n            connected = false;\n            e.printStackTrace();\n        }\n        if (!connected){\n        \tdisconnect();\n        }\n        return connected;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorManager#disconnect()\n     */\n    public boolean disconnect() {\n        try {\n            if (this.zooKeeper != null) {\n                this.zooKeeper.close();\n                this.zooKeeper = null;\n                connected = false;\n                removeWatchers(this.watchers.keySet());\n                return true;\n            }\n        } catch (Exception e) {\n            LoggerFactory.getLogger().error(\n                    \"Error occurred while disconnecting from ZooKeeper server\",\n                    e);\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getChildren(java.lang.String)\n     */\n    public List<String> getChildren(String nodePath) {\n        if (connected) {\n            try {\n\n                return zooKeeper.getChildren(nodePath, false);\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred retrieving children of node: \"\n                                + nodePath, e);\n            }\n        }\n        return null;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getData\n     * (java.lang.String)\n     */\n    public String getData(String nodePath) {\n        if (connected) {\n            try {\n                if (nodePath.length() == 0) {\n                    nodePath = \"/\";\n                }\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    return this.encryptionManager.decryptData(zooKeeper\n                            .getData(nodePath, false, s));\n                }\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred getting data for node: \" + nodePath, e);\n            }\n        }\n        return null;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getNodeChild(java.lang.String, int)\n     */\n    public String getNodeChild(String nodePath, int childIndex) {\n        if (connected) {\n            try {\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    return this.zooKeeper.getChildren(nodePath, false).get(\n                            childIndex);\n                }\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred retrieving child \" + childIndex\n                                + \" of node: \" + nodePath, e);\n            }\n        }\n        return null;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getNodeIndex(java.lang.String)\n     */\n    public int getNodeIndex(String nodePath) {\n        if (connected) {\n            int index = nodePath.lastIndexOf(\"/\");\n            if (index == -1\n                    || (!nodePath.equals(\"/\") && nodePath.charAt(nodePath\n                            .length() - 1) == '/')) {\n                throw new IllegalArgumentException(\"Invalid node path: \"\n                        + nodePath);\n            }\n            String parentPath = nodePath.substring(0, index);\n            String child = nodePath.substring(index + 1);\n            if (parentPath != null && parentPath.length() > 0) {\n                List<String> children = this.getChildren(parentPath);\n                if (children != null) {\n                    return children.indexOf(child);\n                }\n            }\n        }\n        return -1;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getACLs\n     * (java.lang.String)\n     */\n    public List<Map<String, String>> getACLs(String nodePath) {\n        List<Map<String, String>> returnACLs = new ArrayList<Map<String, String>>();\n        if (connected) {\n            try {\n                if (nodePath.length() == 0) {\n                    nodePath = \"/\";\n                }\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    List<ACL> acls = zooKeeper.getACL(nodePath, s);\n                    for (ACL acl : acls) {\n                        Map<String, String> aclMap = new LinkedHashMap<String, String>();\n                        aclMap.put(ACL_SCHEME, acl.getId().getScheme());\n                        aclMap.put(ACL_ID, acl.getId().getId());\n                        StringBuilder sb = new StringBuilder();\n                        int perms = acl.getPerms();\n                        boolean addedPerm = false;\n                        if ((perms & Perms.READ) == Perms.READ) {\n                            sb.append(\"Read\");\n                            addedPerm = true;\n                        }\n                        if (addedPerm) {\n                            sb.append(\", \");\n                        }\n                        if ((perms & Perms.WRITE) == Perms.WRITE) {\n                            sb.append(\"Write\");\n                            addedPerm = true;\n                        }\n                        if (addedPerm) {\n                            sb.append(\", \");\n                        }\n                        if ((perms & Perms.CREATE) == Perms.CREATE) {\n                            sb.append(\"Create\");\n                            addedPerm = true;\n                        }\n                        if (addedPerm) {\n                            sb.append(\", \");\n                        }\n                        if ((perms & Perms.DELETE) == Perms.DELETE) {\n                            sb.append(\"Delete\");\n                            addedPerm = true;\n                        }\n                        if (addedPerm) {\n                            sb.append(\", \");\n                        }\n                        if ((perms & Perms.ADMIN) == Perms.ADMIN) {\n                            sb.append(\"Admin\");\n                            addedPerm = true;\n                        }\n                        aclMap.put(ACL_PERMS, sb.toString());\n                        returnACLs.add(aclMap);\n                    }\n                }\n            } catch (InterruptedException e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred retrieving ACLs of node: \" + nodePath,\n                        e);\n            } catch (KeeperException e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred retrieving ACLs of node: \" + nodePath,\n                        e);\n            }\n        }\n        return returnACLs;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getNodeMeta(java.lang.String)\n     */\n    public Map<String, String> getNodeMeta(String nodePath) {\n        Map<String, String> nodeMeta = new LinkedHashMap<String, String>();\n        if (connected) {\n            try {\n                if (nodePath.length() == 0) {\n                    nodePath = \"/\";\n                }\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    nodeMeta.put(A_VERSION, String.valueOf(s.getAversion()));\n                    nodeMeta.put(C_TIME, String.valueOf(s.getCtime()));\n                    nodeMeta.put(C_VERSION, String.valueOf(s.getCversion()));\n                    nodeMeta.put(CZXID, String.valueOf(s.getCzxid()));\n                    nodeMeta\n                            .put(DATA_LENGTH, String.valueOf(s.getDataLength()));\n                    nodeMeta.put(EPHEMERAL_OWNER, String.valueOf(s\n                            .getEphemeralOwner()));\n                    nodeMeta.put(M_TIME, String.valueOf(s.getMtime()));\n                    nodeMeta.put(MZXID, String.valueOf(s.getMzxid()));\n                    nodeMeta.put(NUM_CHILDREN, String.valueOf(s\n                            .getNumChildren()));\n                    nodeMeta.put(PZXID, String.valueOf(s.getPzxid()));\n                    nodeMeta.put(VERSION, String.valueOf(s.getVersion()));\n                }\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred retrieving meta data for node: \"\n                                + nodePath, e);\n            }\n        }\n        return nodeMeta;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getNumChildren(java.lang.String)\n     */\n    public int getNumChildren(String nodePath) {\n        if (connected) {\n            try {\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    return s.getNumChildren();\n                }\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred getting the number of children of node: \"\n                                + nodePath, e);\n            }\n        }\n        return -1;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * hasChildren(java.lang.String)\n     */\n    public boolean hasChildren(String nodePath) {\n        return getNumChildren(nodePath) > 0;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * isAllowsChildren(java.lang.String)\n     */\n    public boolean isAllowsChildren(String nodePath) {\n        if (connected) {\n            try {\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    return s.getEphemeralOwner() == 0;\n                }\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred determining whether node is allowed children: \"\n                                + nodePath, e);\n            }\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#\n     * getSessionMeta()\n     */\n    public Map<String, String> getSessionMeta() {\n        Map<String, String> sessionMeta = new LinkedHashMap<String, String>();\n        try {\n            if (zooKeeper != null) {\n\n                sessionMeta.put(SESSION_ID, String.valueOf(zooKeeper\n                        .getSessionId()));\n                sessionMeta.put(SESSION_STATE, String.valueOf(zooKeeper\n                        .getState().toString()));\n                sessionMeta.put(CONNECT_STRING, this.connectString);\n                sessionMeta.put(SESSION_TIMEOUT, String\n                        .valueOf(this.sessionTimeout));\n            }\n        } catch (Exception e) {\n            LoggerFactory.getLogger().error(\n                    \"Error occurred retrieving session meta data.\", e);\n        }\n        return sessionMeta;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#createNode\n     * (java.lang.String, java.lang.String)\n     */\n    public boolean createNode(String parent, String nodeName) {\n        if (connected) {\n            try {\n                String[] nodeElements = nodeName.split(\"/\");\n                for (String nodeElement : nodeElements) {\n                    String node = parent + \"/\" + nodeElement;\n                    Stat s = zooKeeper.exists(node, false);\n                    if (s == null) {\n                        zooKeeper.create(node, this.encryptionManager\n                                .encryptData(null), Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                        parent = node;\n                    }\n                }\n                return true;\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred creating node: \" + parent + \"/\"\n                                + nodeName, e);\n            }\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#deleteNode\n     * (java.lang.String)\n     */\n    public boolean deleteNode(String nodePath) {\n        if (connected) {\n            try {\n                Stat s = zooKeeper.exists(nodePath, false);\n                if (s != null) {\n                    List<String> children = zooKeeper.getChildren(nodePath,\n                            false);\n                    for (String child : children) {\n                        String node = nodePath + \"/\" + child;\n                        deleteNode(node);\n                    }\n                    zooKeeper.delete(nodePath, -1);\n                }\n                return true;\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred deleting node: \" + nodePath, e);\n            }\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager#setData\n     * (java.lang.String, java.lang.String)\n     */\n    public boolean setData(String nodePath, String data) {\n        if (connected) {\n            try {\n                zooKeeper.setData(nodePath, this.encryptionManager\n                        .encryptData(data), -1);\n                return true;\n            } catch (Exception e) {\n                LoggerFactory.getLogger().error(\n                        \"Error occurred setting data for node: \" + nodePath, e);\n            }\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * getConnectionPropertiesTemplate()\n     */\n    public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate() {\n        Map<String, List<String>> template = new LinkedHashMap<String, List<String>>();\n        template.put(CONNECT_STRING, Arrays\n                .asList(new String[] { defaultHosts }));\n        template.put(SESSION_TIMEOUT, Arrays\n                .asList(new String[] { defaultTimeout }));\n        template.put(DATA_ENCRYPTION_MANAGER, Arrays\n                .asList(new String[] { defaultEncryptionManager }));\n        template.put(AUTH_SCHEME_KEY, Arrays\n                .asList(new String[] { defaultAuthScheme }));\n        template.put(AUTH_DATA_KEY, Arrays\n                .asList(new String[] { defaultAuthValue }));\n        Map<String, String> labels = new LinkedHashMap<String, String>();\n        labels.put(CONNECT_STRING, \"Connect String\");\n        labels.put(SESSION_TIMEOUT, \"Session Timeout\");\n        labels.put(DATA_ENCRYPTION_MANAGER, \"Data Encryption Manager\");\n        labels.put(AUTH_SCHEME_KEY, \"Authentication Scheme\");\n        labels.put(AUTH_DATA_KEY, \"Authentication Data\");\n        return new Pair<Map<String, List<String>>, Map<String, String>>(\n                template, labels);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorManager#addWatchers\n     * (java.util.Collection,\n     * org.apache.zookeeper.inspector.manager.NodeListener)\n     */\n    public void addWatchers(Collection<String> selectedNodes,\n            NodeListener nodeListener) {\n        // add watcher for each node and add node to collection of\n        // watched nodes\n        if (connected) {\n            for (String node : selectedNodes) {\n                if (!watchers.containsKey(node)) {\n                    try {\n                        watchers.put(node, new NodeWatcher(node, nodeListener,\n                                zooKeeper));\n                    } catch (Exception e) {\n                        LoggerFactory.getLogger().error(\n                                \"Error occurred adding node watcher for node: \"\n                                        + node, e);\n                    }\n                }\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.apache.zookeeper.inspector.manager.ZooInspectorManager#removeWatchers\n     * (java.util.Collection)\n     */\n    public void removeWatchers(Collection<String> selectedNodes) {\n        // remove watcher for each node and remove node from\n        // collection of watched nodes\n        if (connected) {\n            for (String node : selectedNodes) {\n                if (watchers.containsKey(node)) {\n                    NodeWatcher watcher = watchers.remove(node);\n                    if (watcher != null) {\n                        watcher.stop();\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * A Watcher which will re-add itself every time an event is fired\n     * \n     */\n    public class NodeWatcher implements Watcher {\n\n        private final String nodePath;\n        private final NodeListener nodeListener;\n        private final ZooKeeper zookeeper;\n        private boolean closed = false;\n\n        /**\n         * @param nodePath\n         *            - the path to the node to watch\n         * @param nodeListener\n         *            the {@link NodeListener} for this node\n         * @param zookeeper\n         *            - a {@link ZooKeeper} to use to access zookeeper\n         * @throws InterruptedException\n         * @throws KeeperException\n         */\n        public NodeWatcher(String nodePath, NodeListener nodeListener,\n                ZooKeeper zookeeper) throws KeeperException,\n                InterruptedException {\n            this.nodePath = nodePath;\n            this.nodeListener = nodeListener;\n            this.zookeeper = zookeeper;\n            Stat s = zooKeeper.exists(nodePath, this);\n            if (s != null) {\n                zookeeper.getChildren(nodePath, this);\n            }\n        }\n\n        public void process(WatchedEvent event) {\n            if (!closed) {\n                try {\n                    if (event.getType() != EventType.NodeDeleted) {\n\n                        Stat s = zooKeeper.exists(nodePath, this);\n                        if (s != null) {\n                            zookeeper.getChildren(nodePath, this);\n                        }\n                    }\n                } catch (Exception e) {\n                    LoggerFactory.getLogger().error(\n                            \"Error occurred re-adding node watcherfor node \"\n                                    + nodePath, e);\n                }\n                nodeListener.processEvent(event.getPath(), event.getType()\n                        .name(), null);\n            }\n        }\n\n        /**\n\t\t * \n\t\t */\n        public void stop() {\n            this.closed = true;\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * loadNodeViewersFile(java.io.File)\n     */\n    public List<String> loadNodeViewersFile(File selectedFile)\n            throws IOException {\n        List<String> result = new ArrayList<String>();\n        if (defaultNodeViewersFile.exists()) {\n            FileReader reader = new FileReader(selectedFile);\n            try {\n                BufferedReader buff = new BufferedReader(reader);\n                try {\n                    while (buff.ready()) {\n                        String line = buff.readLine();\n                        if (line != null && line.length() > 0 && !line.startsWith(\"#\")) {\n                            result.add(line);\n                        }\n                    }\n                } finally {\n                    buff.close();\n                }\n            } finally {\n                reader.close();\n            }\n        }\n        return result;\n    }\n\n    private void loadDefaultConnectionFile() throws IOException {\n        if (defaultConnectionFile.exists()) {\n            Properties props = new Properties();\n\n            FileReader reader = new FileReader(defaultConnectionFile);\n            try {\n                props.load(reader);\n            } finally {\n                reader.close();\n            }\n            defaultEncryptionManager = props\n                    .getProperty(DATA_ENCRYPTION_MANAGER) == null ? \"org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager\"\n                    : props.getProperty(DATA_ENCRYPTION_MANAGER);\n            defaultTimeout = props.getProperty(SESSION_TIMEOUT) == null ? \"5000\"\n                    : props.getProperty(SESSION_TIMEOUT);\n            defaultHosts = props.getProperty(CONNECT_STRING) == null ? \"localhost:2181\"\n                    : props.getProperty(CONNECT_STRING);\n            defaultAuthScheme = props.getProperty(AUTH_SCHEME_KEY) == null ? \"\"\n                    : props.getProperty(AUTH_SCHEME_KEY);\n            defaultAuthValue = props.getProperty(AUTH_DATA_KEY) == null ? \"\"\n                    : props.getProperty(AUTH_DATA_KEY);\n        } else {\n            defaultEncryptionManager = \"org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager\";\n            defaultTimeout = \"5000\";\n            defaultHosts = \"localhost:2181\";\n            defaultAuthScheme = \"\";\n            defaultAuthValue = \"\";\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * saveDefaultConnectionFile(java.util.Properties)\n     */\n    public void saveDefaultConnectionFile(Properties props) throws IOException {\n        File defaultDir = defaultConnectionFile.getParentFile();\n        if (!defaultDir.exists()) {\n            if (!defaultDir.mkdirs()) {\n                throw new IOException(\n                        \"Failed to create configuration directory: \"\n                                + defaultDir.getAbsolutePath());\n            }\n        }\n        if (!defaultConnectionFile.exists()) {\n            if (!defaultConnectionFile.createNewFile()) {\n                throw new IOException(\n                        \"Failed to create default connection file: \"\n                                + defaultConnectionFile.getAbsolutePath());\n            }\n        }\n        FileWriter writer = new FileWriter(defaultConnectionFile);\n        try {\n            props.store(writer, \"Default connection for ZooInspector\");\n        } finally {\n            writer.close();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * saveNodeViewersFile(java.io.File, java.util.List)\n     */\n    public void saveNodeViewersFile(File selectedFile,\n            List<String> nodeViewersClassNames) throws IOException {\n        if (!selectedFile.exists()) {\n            if (!selectedFile.createNewFile()) {\n                throw new IOException(\n                        \"Failed to create node viewers configuration file: \"\n                                + selectedFile.getAbsolutePath());\n            }\n        }\n        FileWriter writer = new FileWriter(selectedFile);\n        try {\n            BufferedWriter buff = new BufferedWriter(writer);\n            try {\n                for (String nodeViewersClassName : nodeViewersClassNames) {\n                    buff.append(nodeViewersClassName);\n                    buff.append(\"\\n\");\n                }\n            } finally {\n                buff.flush();\n                buff.close();\n            }\n        } finally {\n            writer.close();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * setDefaultNodeViewerConfiguration(java.io.File, java.util.List)\n     */\n    public void setDefaultNodeViewerConfiguration(\n            List<String> nodeViewersClassNames) throws IOException {\n        File defaultDir = defaultNodeViewersFile.getParentFile();\n        if (!defaultDir.exists()) {\n            if (!defaultDir.mkdirs()) {\n                throw new IOException(\n                        \"Failed to create configuration directory: \"\n                                + defaultDir.getAbsolutePath());\n            }\n        }\n        saveNodeViewersFile(defaultNodeViewersFile, nodeViewersClassNames);\n    }\n\n    public List<String> getDefaultNodeViewerConfiguration() throws IOException {\n        return loadNodeViewersFile(defaultNodeViewersFile);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * getLastConnectionProps()\n     */\n    public Properties getLastConnectionProps() {\n        return this.lastConnectionProps;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#\n     * setLastConnectionProps(java.util.Properties)\n     */\n    public void setLastConnectionProps(Properties connectionProps) {\n        this.lastConnectionProps = connectionProps;\n    }\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/ZooInspectorNodeManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\n/**\n * A Manager for all interactions between the application and the nodes in a\n * Zookeeper instance\n * */\npublic interface ZooInspectorNodeManager extends ZooInspectorReadOnlyManager {\n    /**\n     * @param nodePath\n     *            - the path to the node on which to set the data\n     * @param data\n     *            - the data to set on the this node\n     * @return true if the data for the node was successfully updated\n     */\n    public boolean setData(String nodePath, String data);\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/ZooInspectorNodeTreeManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\n/**\n * A Manager for all interactions between the application and the node tree in a\n * Zookeeper instance\n */\npublic interface ZooInspectorNodeTreeManager extends\n        ZooInspectorReadOnlyManager {\n\n    /**\n     * @param parent\n     *            - the parent node path for the node to add\n     * @param nodeName\n     *            - the name of the new node\n     * @return true if the node was successfully created\n     */\n    public abstract boolean createNode(String parent, String nodeName);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return true if the node was successfully deleted\n     */\n    public abstract boolean deleteNode(String nodePath);\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/inspector/manager/ZooInspectorReadOnlyManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.inspector.manager;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * A Manager for all read only interactions between the application and a node\n * in a Zookeeper instance\n */\npublic interface ZooInspectorReadOnlyManager {\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return the data for the node\n     */\n    public abstract String getData(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return the metaData for the node\n     */\n    public abstract Map<String, String> getNodeMeta(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return the ACLs set on the node\n     */\n    public abstract List<Map<String, String>> getACLs(String nodePath);\n\n    /**\n     * @return the metaData for the current session\n     */\n    public abstract Map<String, String> getSessionMeta();\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return true if the node has children\n     */\n    public abstract boolean hasChildren(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return the index of the node within its siblings\n     */\n    public abstract int getNodeIndex(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return the number of children of the node\n     */\n    public abstract int getNumChildren(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @param childIndex\n     *            - the index to the node in the list of node children\n     * @return the path to the node for the child of the nodePath at childIndex\n     */\n    public abstract String getNodeChild(String nodePath, int childIndex);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return true if the node allows children nodes\n     */\n    public abstract boolean isAllowsChildren(String nodePath);\n\n    /**\n     * @param nodePath\n     *            - the path to the node to delete\n     * @return a {@link List} of the children of the node\n     */\n    public abstract List<String> getChildren(String nodePath);\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/src/java/org/apache/zookeeper/retry/ZooKeeperRetry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.retry;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.inspector.logger.LoggerFactory;\n\n/**\n * A Class which extends {@link ZooKeeper} and will automatically retry calls to\n * zookeeper if a {@link KeeperException.ConnectionLossException} occurs\n */\npublic class ZooKeeperRetry extends ZooKeeper {\n\n    private boolean closed = false;\n    private final Watcher watcher;\n    private int limit = -1;\n\n    /**\n     * @param connectString\n     * @param sessionTimeout\n     * @param watcher\n     * @throws IOException\n     */\n    public ZooKeeperRetry(String connectString, int sessionTimeout,\n            Watcher watcher) throws IOException {\n        super(connectString, sessionTimeout, watcher);\n        this.watcher = watcher;\n    }\n\n    /**\n     * @param connectString\n     * @param sessionTimeout\n     * @param watcher\n     * @param sessionId\n     * @param sessionPasswd\n     * @throws IOException\n     */\n    public ZooKeeperRetry(String connectString, int sessionTimeout,\n            Watcher watcher, long sessionId, byte[] sessionPasswd)\n            throws IOException {\n        super(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);\n        this.watcher = watcher;\n    }\n\n    @Override\n    public synchronized void close() throws InterruptedException {\n        this.closed = true;\n        super.close();\n    }\n\n    @Override\n    public String create(String path, byte[] data, List<ACL> acl,\n            CreateMode createMode) throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.create(path, data, acl, createMode);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n                if (exists(path, false) != null) {\n                    return path;\n                }\n            } catch (KeeperException.NodeExistsException e) {\n                return path;\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public void delete(String path, int version) throws InterruptedException,\n            KeeperException {\n        int count = 0;\n        do {\n            try {\n                super.delete(path, version);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n                if (exists(path, false) == null) {\n                    return;\n                }\n            } catch (KeeperException.NoNodeException e) {\n                break;\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n    }\n\n    @Override\n    public Stat exists(String path, boolean watch) throws KeeperException,\n            InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.exists(path, watch ? watcher : null);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public Stat exists(String path, Watcher watcher) throws KeeperException,\n            InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.exists(path, watcher);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public List<ACL> getACL(String path, Stat stat) throws KeeperException,\n            InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.getACL(path, stat);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public List<String> getChildren(String path, boolean watch)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.getChildren(path, watch ? watcher : null);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return new ArrayList<String>();\n    }\n\n    @Override\n    public List<String> getChildren(String path, Watcher watcher)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.getChildren(path, watcher);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return new ArrayList<String>();\n    }\n\n    @Override\n    public byte[] getData(String path, boolean watch, Stat stat)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.getData(path, watch ? watcher : null, stat);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public byte[] getData(String path, Watcher watcher, Stat stat)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.getData(path, watcher, stat);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public Stat setACL(String path, List<ACL> acl, int aclVersion)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.setACL(path, acl, aclVersion);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n                Stat s = exists(path, false);\n                if (s != null) {\n                    if (getACL(path, s).equals(acl)) {\n                        return s;\n                    }\n                } else {\n                    return null;\n                }\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    @Override\n    public Stat setData(String path, byte[] data, int version)\n            throws KeeperException, InterruptedException {\n        int count = 0;\n        do {\n            try {\n                return super.setData(path, data, version);\n            } catch (KeeperException.ConnectionLossException e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n                Stat s = exists(path, false);\n                if (s != null) {\n                    if (getData(path, false, s) == data) {\n                        return s;\n                    }\n                } else {\n                    return null;\n                }\n            }\n        } while (!closed && (limit == -1 || count++ < limit));\n        return null;\n    }\n\n    /**\n     * @param limit\n     */\n    public void setRetryLimit(int limit) {\n        this.limit = limit;\n    }\n\n    /**\n     * @return true if successfully connected to zookeeper\n     */\n    public boolean testConnection() {\n        int count = 0;\n        do {\n            try {\n                return super.exists(\"/\", null) != null;\n            } catch (Exception e) {\n                LoggerFactory.getLogger().warn(\n                        \"ZooKeeper connection lost.  Trying to reconnect.\");\n            }\n        } while (count++ < 5);\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/contrib/zooinspector/zooInspector-dev.sh",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n         \njava -cp ../../../build/contrib/ZooInspector/zookeeper-dev-ZooInspector.jar:../../../build/lib/log4j-1.2.15.jar:lib/zookeeper-3.3.0.jar:lib/jtoaster-1.0.4.jar:lib org.apache.zookeeper.inspector.ZooInspector"
  },
  {
    "path": "src/contrib/zooinspector/zooInspector.cmd",
    "content": "#!/bin/sh\r\n\r\n# Licensed to the Apache Software Foundation (ASF) under one or more\r\n# contributor license agreements.  See the NOTICE file distributed with\r\n# this work for additional information regarding copyright ownership.\r\n# The ASF licenses this file to You under the Apache License, Version 2.0\r\n# (the \"License\"); you may not use this file except in compliance with\r\n# the License.  You may obtain a copy of the License at\r\n#\r\n#     http://www.apache.org/licenses/LICENSE-2.0\r\n#\r\n# Unless required by applicable law or agreed to in writing, software\r\n# distributed under the License is distributed on an \"AS IS\" BASIS,\r\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n# See the License for the specific language governing permissions and\r\n# limitations under the License.\r\n\r\njava -cp zookeeper-dev-ZooInspector.jar;lib/log4j-1.2.15.jar;lib/zookeeper-3.3.0.jar;lib/jToaster-1.0.4.jar;lib org.apache.zookeeper.inspector.ZooInspector"
  },
  {
    "path": "src/contrib/zooinspector/zooInspector.sh",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\njava -cp lib/New.jar:zookeeper-dev-ZooInspector.jar:lib/log4j-1.2.15.jar:;lib/zookeeper-3.3.0.jar:lib/jToaster-1.0.4.jar:lib org.apache.zookeeper.inspector.ZooInspector\n"
  },
  {
    "path": "src/csharp/.gitattributes",
    "content": "*.doc  diff=astextplain\n*.DOC\tdiff=astextplain\n*.docx\tdiff=astextplain\n*.DOCX\tdiff=astextplain\n*.dot\tdiff=astextplain\n*.DOT\tdiff=astextplain\n*.pdf\tdiff=astextplain\n*.PDF\tdiff=astextplain\n*.rtf\tdiff=astextplain\n*.RTF\tdiff=astextplain\n\n*.jpg  \tbinary\n*.png \tbinary\n*.gif \tbinary\n\n*.cs text=auto diff=csharp \n*.vb text=auto\n*.resx text=auto\n*.c text=auto\n*.cpp text=auto\n*.cxx text=auto\n*.h text=auto\n*.hxx text=auto\n*.py text=auto\n*.rb text=auto\n*.java text=auto\n*.html text=auto\n*.htm text=auto\n*.css text=auto\n*.scss text=auto\n*.sass text=auto\n*.less text=auto\n*.js text=auto\n*.lisp text=auto\n*.clj text=auto\n*.sql text=auto\n*.php text=auto\n*.lua text=auto\n*.m text=auto\n*.asm text=auto\n*.erl text=auto\n*.fs text=auto\n*.fsx text=auto\n*.hs text=auto\n\n*.csproj text=auto\n*.vbproj text=auto\n*.fsproj text=auto\n*.dbproj text=auto\n*.sln text=auto eol=crlf\n*.sh eol=lf\n"
  },
  {
    "path": "src/csharp/.gitignore",
    "content": "[Oo]bj/\n[Bb]in/\nTestResults/\n.nuget/\n*.sln.ide/\n_ReSharper.*/\n.idea/\npackages/\nartifacts/\nPublishProfiles/\n.vs/\n*.user\n*.suo\n*.cache\n*.docstates\n_ReSharper.*\nnuget.exe\n*net45.csproj\n*net451.csproj\n*k10.csproj\n*.psess\n*.vsp\n*.pidb\n*.userprefs\n*DS_Store\n*.ncrunchsolution\n*.*sdf\n*.ipch\n*.swp\n*~\n.build/\n.testPublish/\nlaunchSettings.json\nBenchmarkDotNet.Artifacts/\nBDN.Generated/\nbinaries/\nglobal.json\n"
  },
  {
    "path": "src/csharp/Directory.Build.props",
    "content": "﻿<Project>\n  <PropertyGroup>\n    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)ZooKeeperNetEx.snk</AssemblyOriginatorKeyFile>\n    <SignAssembly>true</SignAssembly>\n    <PublicSign Condition=\"'$(OS)' != 'Windows_NT'\">true</PublicSign>\n    <DelaySign>False</DelaySign>\n    <VersionPrefix>3.4.12.4</VersionPrefix>\n    <langVersion>latest</langVersion>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "src/csharp/NuGet.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <add key=\"NuGet\" value=\"https://api.nuget.org/v3/index.json\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "src/csharp/ZooKeeperNetEx.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.29324.140\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{3124BC6C-39C6-473D-B3E5-E04C85D922F4}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\t.gitattributes = .gitattributes\r\n\t\t.gitignore = .gitignore\r\n\t\tDirectory.Build.props = Directory.Build.props\r\n\t\tNuGet.config = NuGet.config\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{C28103FF-C2A2-44D5-8A9F-55255139270A}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tsrc\\Directory.Build.props = src\\Directory.Build.props\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{4B6719A8-92AF-43D8-B888-B2D51EDD5EFC}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\ttest\\Directory.Build.props = test\\Directory.Build.props\r\n\t\ttest\\xunit.runner.json = test\\xunit.runner.json\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ZooKeeperNetEx\", \"src\\ZooKeeperNetEx\\ZooKeeperNetEx.csproj\", \"{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ZooKeeperNetEx.Recipes\", \"src\\ZooKeeperNetEx.Recipes\\ZooKeeperNetEx.Recipes.csproj\", \"{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ZooKeeperNetEx.Tests\", \"test\\ZooKeeperNetEx.Tests\\ZooKeeperNetEx.Tests.csproj\", \"{D4F18D58-52B1-435D-A012-10F2123458C4}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ZooKeeperNetEx.Recipes.Tests\", \"test\\ZooKeeperNetEx.Recipes.Tests\\ZooKeeperNetEx.Recipes.Tests.csproj\", \"{E16D61E7-487C-4933-98D6-1C9A4053A767}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"build\", \"build\", \"{D267E8FA-C3D0-42E7-9A0C-EE1DFEEA6381}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tbuild\\dependencies.props = build\\dependencies.props\r\n\tEndProjectSection\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{D4F18D58-52B1-435D-A012-10F2123458C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{D4F18D58-52B1-435D-A012-10F2123458C4}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{D4F18D58-52B1-435D-A012-10F2123458C4}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{D4F18D58-52B1-435D-A012-10F2123458C4}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{E16D61E7-487C-4933-98D6-1C9A4053A767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{E16D61E7-487C-4933-98D6-1C9A4053A767}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{E16D61E7-487C-4933-98D6-1C9A4053A767}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{E16D61E7-487C-4933-98D6-1C9A4053A767}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(NestedProjects) = preSolution\r\n\t\t{FF7547E8-BD4F-4D3A-AC29-C9DD74E48CB3} = {C28103FF-C2A2-44D5-8A9F-55255139270A}\r\n\t\t{4CE3A450-A8AA-48DC-8A05-7D9B3A169B6A} = {C28103FF-C2A2-44D5-8A9F-55255139270A}\r\n\t\t{D4F18D58-52B1-435D-A012-10F2123458C4} = {4B6719A8-92AF-43D8-B888-B2D51EDD5EFC}\r\n\t\t{E16D61E7-487C-4933-98D6-1C9A4053A767} = {4B6719A8-92AF-43D8-B888-B2D51EDD5EFC}\r\n\t\t{D267E8FA-C3D0-42E7-9A0C-EE1DFEEA6381} = {3124BC6C-39C6-473D-B3E5-E04C85D922F4}\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {347287AB-D5D7-4457-9267-D7C5405316DC}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "src/csharp/src/Directory.Build.props",
    "content": "﻿<Project>\n  <Import Project=\"..\\Directory.Build.props\" />\n\n  <PropertyGroup>\n    <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>\n    <EmbedAllSources>True</EmbedAllSources>\n    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>\n    <GenerateDocumentationFile>True</GenerateDocumentationFile>\n    <IncludeSymbols>True</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)'=='netstandard2.0'\">\n    <DebugType>Embedded</DebugType>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)'=='net461'\">\n    <DebugType>Portable</DebugType>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <Copyright>© Shay Hazor</Copyright>\n    <Authors>shayhatsor2</Authors>\n    <RepositoryType>git</RepositoryType>\n    <RepositoryUrl>https://github.com/shayhatsor/zookeeper</RepositoryUrl>\n    <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>\n    <PackageReleaseNotes>\n      This project is actively maintained at: https://github.com/shayhatsor/zookeeper\n      Please feel free to open an issue or ask a question there.\n    </PackageReleaseNotes>\n    <PackageIconUrl>https://svn.apache.org/repos/asf/comdev/project-logos/originals/zookeeper.svg</PackageIconUrl>\n    <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\n    <PublishRepositoryUrl>True</PublishRepositoryUrl>\n    <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>\n    <PackageIcon>ZooKeeperNetEx.png</PackageIcon>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"../../ZooKeeperNetEx.png\" Pack=\"true\" PackagePath=\"\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/.gitignore",
    "content": "bin\nobj\nGenerated/*/"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/Properties/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ZooKeeperNetEx.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100416f66004a1fd058e5d6d0756c8bcc429965b3fd20c74901d5a4b0d69c53885a32cfd82343f0452145534caa6ee14074f885f173dddda29ab9bdad17e32e2ae1306d3b651a087e030b70caefcf6f2c91a3e1930c519507638581c5d06612a953ca879111b5383aebc452067a800b014cae8c6a4bf2c9ed71f6159d04620d1ad5\")]\n[assembly: InternalsVisibleTo(\"ZooKeeperNetEx.Recipes,PublicKey=0024000004800000940000000602000000240000525341310004000001000100416f66004a1fd058e5d6d0756c8bcc429965b3fd20c74901d5a4b0d69c53885a32cfd82343f0452145534caa6ee14074f885f173dddda29ab9bdad17e32e2ae1306d3b651a087e030b70caefcf6f2c91a3e1930c519507638581c5d06612a953ca879111b5383aebc452067a800b014cae8c6a4bf2c9ed71f6159d04620d1ad5\")]\n[assembly: InternalsVisibleTo(\"ZooKeeperNetEx.Recipes.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100416f66004a1fd058e5d6d0756c8bcc429965b3fd20c74901d5a4b0d69c53885a32cfd82343f0452145534caa6ee14074f885f173dddda29ab9bdad17e32e2ae1306d3b651a087e030b70caefcf6f2c91a3e1930c519507638581c5d06612a953ca879111b5383aebc452067a800b014cae8c6a4bf2c9ed71f6159d04620d1ad5\")]"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/ZooKeeperNetEx.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <Description>A .NET async Client fully compliant with ZooKeeper, supporting all features. Fully Task-based Asynchronous (async/await). A great measure has been taken to follow the logic of the official Java client, including all relevant unit tests. In fact, the code is almost identical. Thus allowing easy evolution alongside the Java version.</Description>\r\n    <Summary>$(Description)</Summary>\r\n\t\r\n\t<AssemblyTitle>Apache ZooKeeper .NET async Client</AssemblyTitle>\r\n\t<Product>$(AssemblyTitle)</Product>\r\n    <Title>$(AssemblyTitle)</Title>\r\n\t\r\n    <PackageId>ZooKeeperNetEx</PackageId>\r\n    <AssemblyName>$(PackageId)</AssemblyName>\r\n    \r\n\t<PackageTags>ZooKeeper;.NET;Client;Async</PackageTags>\r\n  </PropertyGroup>\r\n  \r\n  <ItemGroup>\r\n    <Compile Remove=\"Generated\\server\\**\\*.*;Generated\\txn\\**\\*.*;Generated\\data\\StatPersisted*.*;Generated\\proto\\*SASL*.*;Generated\\proto\\GetChildrenR*.*;Generated\\proto\\GetMaxChildren*.*\" />\r\n  </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/BinaryInputArchive.cs",
    "content": "using org.apache.utils;\nusing org.apache.zookeeper;\nusing System.IO;\n\nnamespace org.apache.jute\n{\n    internal class BinaryInputArchive : InputArchive\n    {\n        public const string UNREASONBLE_LENGTH = \"Unreasonable length = \";\n        private readonly BigEndianBinaryReader reader;\n\n        public static BinaryInputArchive getArchive(BigEndianBinaryReader reader)\n        {\n            return new BinaryInputArchive(reader);\n        }\n\n        private class BinaryIndex : Index\n        {\n            private int nelems;\n\n            internal BinaryIndex(int nelems)\n            {\n                this.nelems = nelems;\n            }\n            public bool done()\n            {\n                return (nelems <= 0);\n            }\n            public void incr()\n            {\n                nelems--;\n            }\n        }\n        \n        /** Creates a new instance of BinaryInputArchive */\n\n        private BinaryInputArchive(BigEndianBinaryReader reader)\n        {\n            this.reader = reader;\n        }\n\n        public bool readBool(string tag)\n        {\n            return reader.ReadBoolean();\n        }\n\n        public int readInt(string tag)\n        {\n            return reader.ReadInt32();\n        }\n\n        public long readLong(string tag)\n        {\n            return reader.ReadInt64();\n        }\n\n        public string readString(string tag)\n        {\n            int len = reader.ReadInt32();\n            if (len == -1) return null;\n            checkLength(len);\n            var b = reader.ReadBytesOrThrow(len);\n            return b.UTF8bytesToString();\n        }\n\n        public byte[] readBuffer(string tag)\n        {\n            int len = readInt(tag);\n            if (len == -1) return null;\n            checkLength(len);\n            var arr = reader.ReadBytesOrThrow(len);\n            return arr;\n        }\n\n        // Since this is a rough sanity check, add some padding to maxBuffer to\n        // make up for extra fields, etc. (otherwise e.g. clients may be able to\n        // write buffers larger than we can read from disk!)\n        private void checkLength(int len)\n        {\n        if (len < 0 || len > ClientCnxn.packetLen + 1024) {\n                throw new IOException(UNREASONBLE_LENGTH + len);\n            }\n        }\n\n        public void readRecord(Record r, string tag)\n        {\n            r.deserialize(this, tag);\n        }\n        public Index startVector(string tag)\n        {\n            int len = readInt(tag);\n            if (len == -1)\n            {\n                return null;\n            }\n            return new BinaryIndex(len);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/BinaryOutputArchive.cs",
    "content": "using org.apache.utils;\nusing org.apache.zookeeper;\nusing System.Collections.Generic;\n\nnamespace org.apache.jute\n{\n    internal class BinaryOutputArchive : OutputArchive\n    {\n        private readonly BigEndianBinaryWriter writer;\n\n        public static BinaryOutputArchive getArchive(BigEndianBinaryWriter writer)\n        {\n            return new BinaryOutputArchive(writer);\n        }\n\n        /** Creates a new instance of BinaryOutputArchive */\n\n        private BinaryOutputArchive(BigEndianBinaryWriter writer)\n        {\n            this.writer = writer;\n        }\n\n        public void writeBool(bool b, string tag)\n        {\n            writer.Write(b);\n        }\n\n        public void writeInt(int i, string tag)\n        {\n            writer.Write(i);\n        }\n\n        public void writeLong(long l, string tag)\n        {\n            writer.Write(l);\n        }\n\n        public void writeString(string s, string tag)\n        {\n            if (s == null)\n            {\n                writeInt(-1, \"len\");\n                return;\n            }\n            byte[] bb = s.UTF8getBytes();\n            writeInt(bb.Length, \"len\");\n            writer.Write(bb);\n        }\n\n        public void writeBuffer(byte[] barr, string tag)\n        {\n            if (barr == null)\n            {\n                writer.Write(-1);\n                return;\n            }\n            writer.Write(barr.Length);\n            writer.Write(barr);\n        }\n\n        public void writeRecord(Record r, string tag)\n        {\n            if (r == null) return;\n\n            r.serialize(this, tag);\n        }\n        public void startVector<T>(List<T> v, string tag)\n        {\n            if (v == null)\n            {\n                writeInt(-1, tag);\n                return;\n            }\n            writeInt(v.Count, tag);\n        }\n\n        public void endVector<T>(List<T> v, string tag) { }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/Index.cs",
    "content": "namespace org.apache.jute\n{\n    /**\n * Interface that acts as an iterator for deserializing maps.\n * The deserializer returns an instance that the record uses to\n * read vectors and maps. An example of usage is as follows:\n *\n * <code>\n * Index idx = startVector(...);\n * while (!idx.done()) {\n *   .... // read element of a vector\n *   idx.incr();\n * }\n * </code>\n *\n */\n    internal interface Index\n    {\n        bool done();\n        void incr();        \n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/InputArchive.cs",
    "content": "namespace org.apache.jute\n{\n    /**\n * Interface that all the Deserializers have to implement.\n *\n */\n\n    internal interface InputArchive\n    {\n        bool readBool(string tag);\n        int readInt(string tag);\n        long readLong(string tag);\n        string readString(string tag);\n        byte[] readBuffer(string tag);\n        void readRecord(Record r, string tag);\n        Index startVector(string tag);\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/OutputArchive.cs",
    "content": "namespace org.apache.jute\n{\n    using System.Collections.Generic;\n\n    /**\n * Interface that alll the serializers have to implement.\n *\n */\n\n    internal interface OutputArchive\n    {\n        void writeBool(bool b, string tag);\n        void writeInt(int i, string tag);\n        void writeLong(long l, string tag);\n        void writeString(string s, string tag);\n        void writeBuffer(byte[] buf, string tag);\n        void writeRecord(Record r, string tag);\n        void startVector<T>(List<T> v, string tag);\n        void endVector<T>(List<T> v, string tag);\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/jute/Record.cs",
    "content": "namespace org.apache.jute\n{\n    /**\n * Interface that is implemented by generated classes.\n * \n */\n\n    internal interface Record\n    {\n        void serialize(OutputArchive archive, string tag);\n        void deserialize(InputArchive archive, string tag);\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/AwaitableSignal.cs",
    "content": "﻿using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace ZooKeeperNetEx.utils\n{\n    // https://blogs.msdn.microsoft.com/pfxteam/2011/12/15/awaiting-socket-operations/\n    // https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Threading/Tasks/Sources/ManualResetValueTaskSource.cs\n    // https://github.com/dotnet/corefx/blob/master/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs\n    internal class AwaitableSignal : INotifyCompletion\n    { \n        private static readonly Action s_sentinel = () => { };\n\n\t\tprivate readonly ThreadLocal<bool> _stackDiveOccured = new ThreadLocal<bool>();\n\n        private readonly VolatileReference<Action> _continuation = new VolatileReference<Action>(null);\n\n        public AwaitableSignal GetAwaiter() { return this; }\n\n        public bool IsCompleted => _continuation.Value != null;\n\n        public void OnCompleted(Action continuation) \n        { \n    \t\tif (_continuation.CompareExchange(continuation, null) != null)\n            {\n                RunContinuation(continuation);\n            }\n        }\n\n        public void TrySignal()\n        {\n            var continuation = _continuation.CompareExchange(s_sentinel, null);\n            if (continuation != null && continuation != s_sentinel && \n                _continuation.CompareExchange(s_sentinel, continuation) == continuation)\n            {\n                RunContinuation(continuation);\n            }\n        }\n        \n        public void GetResult()\n        {\n        }\n\n        public void Reset()\n        {\n            _continuation.Value = null;\n        }\n\n        private void RunContinuation(Action action)\n        {\n            if (_stackDiveOccured.Value)\n            {\n                _stackDiveOccured.Value = false;\n                Task.Run(action);\n            }\n            else\n            {\n                _stackDiveOccured.Value = true;\n                action();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/ByteBuffer.cs",
    "content": "using System.IO;\n\nnamespace org.apache.utils\n{\n    internal class ByteBuffer\n    {\n        public readonly MemoryStream Stream;\n        private Mode mode;\n\n        private ByteBuffer() : this(new MemoryStream())\n        {\n        }\n\n        public ByteBuffer(MemoryStream stream)\n        {\n            Stream = stream;\n        }\n\n        public static ByteBuffer allocate(int capacity)\n        {\n            var buffer = new ByteBuffer {Stream = {Capacity = capacity}, mode = Mode.Write};\n            return buffer;\n        }\n        \n        public void flip()\n        {\n            mode = Mode.Read;\n            Stream.SetLength(Stream.Position);\n            Stream.Position = 0;\n        }\n\n        public void clear()\n        {\n            mode = Mode.Write;\n            Stream.Position = 0;\n        }\n\n        public int limit()\n        {\n            if (mode == Mode.Write)\n                return Stream.Capacity;\n            return (int) Stream.Length;\n        }\n\n        public int remaining()\n        {\n            return limit() - (int) Stream.Position;\n        }\n\n        public bool hasRemaining()\n        {\n            return remaining() > 0;\n        }\n\n        //'Mode' is only used to determine whether to return data length or capacity from the 'limit' method:\n        private enum Mode\n        {\n            Read,\n            Write\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/EnumUtil.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace org.apache.utils\n{\n    /// <summary>\n    /// Utility methods for enum values. This static type will fail to initialize \n    /// (throwing a <see cref=\"TypeInitializationException\"/>) if\n    /// you try to provide a value that is not an enum.\n    /// </summary>\n    /// <typeparam name=\"T\">An enum type. </typeparam>\n    internal static class EnumUtil<T>\n        where T : struct\n    {\n        /// <summary>\n        /// In the .NET Framework, objects can be cast to enum values which are not\n        /// defined for their type. This method provides a simple fail-fast check\n        /// that the enum value is defined, and creates a cast at the same time.\n        /// Cast the given value as the given enum type.\n        /// Throw an exception if the value is not defined for the given enum type.\n        /// </summary>\n        /// <param name=\"enumValue\"></param>\n        /// <exception cref=\"InvalidCastException\">\n        /// If the given value is not a defined value of the enum type.\n        /// </exception>\n        /// <returns></returns>\n        public static T DefinedCast(object enumValue)\n        {\n            if (!Enum.IsDefined(typeof(T), enumValue))\n                throw new InvalidCastException(enumValue + \" is not a defined value for enum type \" +\n                                               typeof(T).FullName);\n            return (T)enumValue;\n        }\n\n        public static IEnumerable<T> GetValues()\n        {\n            return Enum.GetValues(typeof(T)).Cast<T>();\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/MiscEx.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace org.apache.zookeeper\n{\n    internal static class MiscEx {\n        public static TValue remove<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) {\n            TValue value;\n            if (dictionary.TryGetValue(key, out value))\n                dictionary.Remove(key);\n            return value;\n        }\n\n        public static bool isAlive(this ZooKeeper.States state) {\n            return state != ZooKeeper.States.CLOSED && state != ZooKeeper.States.AUTH_FAILED;\n        }\n\n        /**\n         * Returns whether we are connected to a server (which\n         * could possibly be read-only, if this client is allowed\n         * to go to read-only mode)\n         * */\n\n        public static bool isConnected(this ZooKeeper.States state) {\n            return state == ZooKeeper.States.CONNECTED || state == ZooKeeper.States.CONNECTEDREADONLY;\n        }\n\n        public static int size(this ICollection collection) {\n            return collection.Count;\n        }\n\n        public static void addAll<T>(this HashSet<T> hashSet, HashSet<T> another) {\n            hashSet.UnionWith(another);\n        }\n\n        public static byte[] UTF8getBytes(this string str) {\n            return Encoding.UTF8.GetBytes(str);\n        }\n\n        public static string UTF8bytesToString(this byte[] buffer)\n        {\n            return Encoding.UTF8.GetString(buffer, 0, buffer.Length);\n        }\n\n        public static string ToHexString(this long num) {\n            return num.ToString(\"x\");\n        }\n        public static string ToHexString(this byte num)\n        {\n            return num.ToString(\"x\");\n        }\n\n        public static string ToCommaDelimited<T>(this IEnumerable<T> enumerable)\n        {\n            return string.Join(\",\", enumerable);\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/SignalTask.cs",
    "content": "using System.Threading.Tasks;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.utils\n{\n    /// <summary>\n    /// Uses <see cref=\"T:System.Threading.Tasks.TaskCompletionSource\" />s for signals\n    /// </summary>\n    public class SignalTask\n    {\n        private readonly VolatileReference<TaskCompletionSource<bool>> tcs = new VolatileReference<TaskCompletionSource<bool>>(new TaskCompletionSource<bool>());\n\n        /// <summary>\n        /// Gets the underlying <see cref=\"T:System.Threading.Tasks.Task`1\" />.\n        /// </summary>\n        public Task Task => tcs.Value.Task;\n\n        /// <summary>\n        /// Replaces the underlying <see cref=\"T:System.Threading.Tasks.TaskCompletionSource\" /> with a new one.\n        /// </summary>\n        public void Reset()\n        {\n            tcs.Value = new TaskCompletionSource<bool>();\n        }\n\n        /// <summary>Attempts to transition the underlying <see cref=\"T:System.Threading.Tasks.Task`1\" /> into the <see cref=\"F:System.Threading.Tasks.TaskStatus.RanToCompletion\" /> state.</summary>\n        public void TrySet()\n        {\n            tcs.Value.TrySetResult(true);\n        }\n\n        /// <summary>Transitions the underlying <see cref=\"T:System.Threading.Tasks.Task`1\" /> into the <see cref=\"F:System.Threading.Tasks.TaskStatus.RanToCompletion\" /> state.</summary>\n        /// <exception cref=\"T:System.InvalidOperationException\">The underlying <see cref=\"T:System.Threading.Tasks.Task`1\" /> is already in state: <see cref=\"F:System.Threading.Tasks.TaskStatus.RanToCompletion\" /> </exception>\n        public void Set()\n        {\n            tcs.Value.SetResult(true);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/SocketContext.cs",
    "content": "﻿using System;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace ZooKeeperNetEx.utils\n{\n    // https://github.com/dotnet/corefx/blob/master/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs\n    internal class SocketContext : IDisposable\n    {\n        private readonly SocketAsyncEventArgs _socketAsyncEventArgs;\n\n        private readonly AwaitableSignal _awaitableSignal;\n        private readonly Socket _socket;\n\n        private readonly VolatileInt _state = new VolatileInt(IDLE);\n\n        private readonly VolatileInt _disposed = new VolatileInt(0);\n\n        private static readonly byte[] Buffer = new byte[0];\n\n        private const int IDLE = 0;\n        private const int PENDING = 1;\n        public static SocketContext StartConnectAsync(AwaitableSignal awaitableSignal, Socket socket, EndPoint remoteEndPoint)\n        {\n            return new SocketContext(awaitableSignal, socket, remoteEndPoint);\n        }\n\n        private SocketContext(AwaitableSignal awaitableSignal, Socket socket, EndPoint remoteEndPoint)\n        {\n            _socketAsyncEventArgs = new SocketAsyncEventArgs();\n            _socketAsyncEventArgs.SetBuffer(Buffer, 0, 0);\n            _socketAsyncEventArgs.Completed += delegate { Complete(); };\n            _socketAsyncEventArgs.RemoteEndPoint = remoteEndPoint;\n            _awaitableSignal = awaitableSignal;\n            _socket = socket;\n\n            StartSocketAction(_socket.ConnectAsync);\n        }\n        \n        public void StartReceiveAsync()\n        {\n            StartSocketAction(_socket.ReceiveAsync);\n        }\n\n        private void StartSocketAction(Func<SocketAsyncEventArgs, bool> socketAction)\n        {\n            _state.SetValue(IDLE, PENDING);\n            if (socketAction(_socketAsyncEventArgs) == false)\n            {\n                Complete();\n            }\n        }\n\n        private void Complete()\n        {\n            _state.SetValue(PENDING, IDLE);\n            _awaitableSignal.TrySignal();\n        }\n\n        public EndPoint RemoteEndPoint\n        {\n            get\n            {\n                ThrowIfDisposed();\n                return _socketAsyncEventArgs.RemoteEndPoint;\n            }\n        }\n        \n        public SocketAsyncOperation GetResult()\n        {\n            ThrowIfDisposed();\n\n            if (_state.Value == PENDING) return SocketAsyncOperation.None;\n\n            var socketAsyncEventArgs = _socketAsyncEventArgs; \n\n            if (socketAsyncEventArgs.LastOperation == SocketAsyncOperation.Receive && _socket.Available == 0)\n            {\n                socketAsyncEventArgs.SocketError = SocketError.ConnectionReset;\n            }\n\n            if (socketAsyncEventArgs.SocketError != SocketError.Success)\n            {\n                throw new SocketException((int) socketAsyncEventArgs.SocketError);\n            }\n            return socketAsyncEventArgs.LastOperation;\n        }\n      \n        private void ThrowIfDisposed()\n        {\n            if (_disposed.Value == 1)\n            {\n                throw new ObjectDisposedException(nameof(SocketContext));\n            }\n        }\n\n        public void Dispose()\n        {\n            if (_disposed.TrySetValue(0, 1))\n            {\n                _socketAsyncEventArgs?.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/SocketEx.cs",
    "content": "using System.Net.Sockets;\n\nnamespace org.apache.utils\n{\n    internal static class SocketEx\n    {\n        public static void read(this Socket socket, ByteBuffer byteBuffer)\n        {\n            int size = byteBuffer.remaining();\n            byte[] data = new byte[size];\n            int index = 0;\n            while (index < size)\n            {\n                SocketError socketErrorCode;\n                int read = socket.Receive(data, index, size - index, SocketFlags.None, out socketErrorCode);\n                if (socketErrorCode != SocketError.WouldBlock && socketErrorCode != SocketError.Success)\n                {\n                    throw new SocketException((int)socketErrorCode);\n                }\n                if (read == 0) break;\n                index += read;\n            }\n            byteBuffer.Stream.Write(data, 0, index);\n        }\n\n        public static void write(this Socket socket, ByteBuffer byteBuffer)\n        {\n            byte[] data = byteBuffer.Stream.ToArray();\n            int bytesToWrite = byteBuffer.remaining();\n            int bytesWritten = (int)byteBuffer.Stream.Position;\n            do\n            {\n                SocketError socketErrorCode;\n                int actuallyWritten = socket.Send(data, bytesWritten, bytesToWrite, SocketFlags.None, out socketErrorCode);\n                if (socketErrorCode != SocketError.WouldBlock && socketErrorCode != SocketError.Success)\n                {\n                    throw new SocketException((int)socketErrorCode);\n                }\n                if (actuallyWritten == 0) break;\n                byteBuffer.Stream.Position += actuallyWritten;\n                bytesWritten += actuallyWritten;\n                bytesToWrite -= actuallyWritten;\n\n            } while (bytesToWrite > 0);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/TimeHelper.cs",
    "content": "using System.Diagnostics;\n\nnamespace org.apache.utils\n{\n    internal static class TimeHelper\n    {\n        private static readonly Stopwatch stopwatch = new Stopwatch();\n\n        static TimeHelper()\n        {\n            stopwatch.Start();\n        }\n\n        public static long ElapsedMiliseconds\n        {\n            get { return stopwatch.ElapsedMilliseconds; }\n        }\n\n        public static long ElapsedNanoseconds\n        {\n            get { return (long)((double)stopwatch.ElapsedTicks / Stopwatch.Frequency * 1000000000); }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/VolatileBool.cs",
    "content": "﻿\nusing System.Threading;\n\nnamespace ZooKeeperNetEx.utils\n{\n    internal class VolatileBool\n    {\n        public VolatileBool(bool value)\n        {\n            Value = value;\n        }\n\n        private bool m_Value;\n\n        public bool Value\n        {\n            get => Volatile.Read(ref m_Value);\n            set => Volatile.Write(ref m_Value, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/VolatileInt.cs",
    "content": "using System;\nusing System.Threading;\n\nnamespace ZooKeeperNetEx.utils\n{\n    internal class VolatileInt\n    {\n        public VolatileInt(int value)\n        {\n            Value = value;\n        }\n\n        private int m_Value;\n\n        public int Value\n        {\n            get => Volatile.Read(ref m_Value);\n            set => Volatile.Write(ref m_Value, value);\n        }\n\n        public bool TrySetValue(int preconditionValue, int newValue)\n        {\n            return Interlocked.CompareExchange(ref m_Value, newValue, preconditionValue) == preconditionValue;\n        }\n\n        public void SetValue(int preconditionValue, int newValue)\n        {\n            int actualValue = Interlocked.CompareExchange(ref m_Value, newValue, preconditionValue);\n            if (actualValue != preconditionValue)\n                throw new InvalidOperationException(\"Expected=\" + preconditionValue + \"Actual=\" + actualValue);\n        }\n\n        public int Increment() {\n            return Interlocked.Increment(ref m_Value);\n        }\n\n        public int Decrement()\n        {\n            return Interlocked.Decrement(ref m_Value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/VolatileLong.cs",
    "content": "﻿\nusing System.Threading;\n\nnamespace ZooKeeperNetEx.utils\n{\n    internal class VolatileLong\n    {\n        public VolatileLong(long value)\n        {\n            Value = value;\n        }\n\n        private long m_Value;\n\n        public long Value\n        {\n            get => Volatile.Read(ref m_Value);\n            set => Volatile.Write(ref m_Value, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/VolatileReference.cs",
    "content": "﻿using System.Threading;\n\nnamespace ZooKeeperNetEx.utils\n{\n    internal class VolatileReference<T> where T : class\n    {\n        public VolatileReference(T value)\n        {\n            Value = value;\n        }\n\n        private T m_Value;\n\n        public T Value\n        {\n            get => Volatile.Read(ref m_Value);\n            set => Volatile.Write(ref m_Value, value);\n        }\n\n        public T CompareExchange(T newValue, T preconditionValue)\n        {\n            return Interlocked.CompareExchange(ref m_Value, newValue, preconditionValue);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/bigEndian/BigEndianBinaryReader.cs",
    "content": "using System;\nusing System.IO;\n\nnamespace org.apache.utils\n{\n    /// <summary>\n    /// Equivalent of System.IO.BinaryReader, but with either endianness, depending on\n    /// the EndianBitConverter it is constructed with. No data is buffered in the\n    /// reader; the client may seek within the stream at will.\n    /// </summary>\n    internal class BigEndianBinaryReader \n    {\n        #region Fields not directly related to properties\n\n        /// <summary>\n        /// Buffer used for temporary storage before conversion into primitives\n        /// </summary>\n        private readonly byte[] byteBuffer = new byte[16];\n\n        #endregion\n\n        #region Constructors\n\n        /// <summary>\n        /// Constructs a new binary reader with the given bit converter, reading\n        /// to the given stream, using the given encoding.\n        /// </summary>\n        /// <param name=\"stream\">Stream to read data from</param>\n        public BigEndianBinaryReader(Stream stream)\n        {\n            if (stream == null)\n            {\n                throw new ArgumentNullException(\"stream\");\n            }\n            if (!stream.CanRead)\n            {\n                throw new ArgumentException(\"Stream isn't writable\", \"stream\");\n            }\n            this.stream = stream;\n        }\n\n        #endregion\n\n        #region Properties\n        \n        private readonly Stream stream;\n\n        #endregion\n\n        #region Public methods\n\n        /// <summary>\n        /// Reads a boolean from the stream. 1 byte is read.\n        /// </summary>\n        /// <returns>The boolean read</returns>\n        public bool ReadBoolean()\n        {\n            ReadInternal(byteBuffer, 1);\n            return BigEndianBitConverter.ToBoolean(byteBuffer, 0);\n        }\n\n        /// <summary>\n        /// Reads a 32-bit signed integer from the stream, using the bit converter\n        /// for this reader. 4 bytes are read.\n        /// </summary>\n        /// <returns>The 32-bit integer read</returns>\n        public int ReadInt32()\n        {\n            ReadInternal(byteBuffer, 4);\n            return BigEndianBitConverter.ToInt32(byteBuffer, 0);\n        }\n\n        /// <summary>\n        /// Reads a 64-bit signed integer from the stream, using the bit converter\n        /// for this reader. 8 bytes are read.\n        /// </summary>\n        /// <returns>The 64-bit integer read</returns>\n        public long ReadInt64()\n        {\n            ReadInternal(byteBuffer, 8);\n            return BigEndianBitConverter.ToInt64(byteBuffer, 0);\n        }\n\n        /// <summary>\n        /// Reads the specified number of bytes, returning them in a new byte array.\n        /// If not enough bytes are available before the end of the stream, this\n        /// method will throw an IOException.\n        /// </summary>\n        /// <param name=\"count\">The number of bytes to read</param>\n        /// <returns>The bytes read</returns>\n        public byte[] ReadBytesOrThrow(int count)\n        {\n            byte[] ret = new byte[count];\n            ReadInternal(ret, count);\n            return ret;\n        }\n\n        #endregion\n\n        #region Private methods\n\n        /// <summary>\n        /// Reads the given number of bytes from the stream, throwing an exception\n        /// if they can't all be read.\n        /// </summary>\n        /// <param name=\"data\">Buffer to read into</param>\n        /// <param name=\"size\">Number of bytes to read</param>\n        void ReadInternal (byte[] data, int size)\n        {\n            int index=0;\n            while (index < size)\n            {\n                int read = stream.Read(data, index, size-index);\n                if (read==0)\n                {\n                    throw new EndOfStreamException(\"End of stream reached with \" + (size - index) + \"byte(s) left to read.\");\n                }\n                index += read;\n            }\n        }\n        #endregion\n\n    \n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/bigEndian/BigEndianBinaryWriter.cs",
    "content": "using System;\nusing System.IO;\n\nnamespace org.apache.utils\n{\n\t/// <summary>\n\t/// Equivalent of System.IO.BinaryWriter, but with big endianness\n\t/// </summary>\n\tinternal class BigEndianBinaryWriter\n\t{\n\t\t#region Fields not directly related to properties\n\t\t/// <summary>\n\t\t/// Buffer used for temporary storage during conversion from primitives\n\t\t/// </summary>\n\t\tprivate readonly byte[] buffer = new byte[16];\n        #endregion\n\n        #region Constructors\n\n        /// <summary>\n        /// Constructs a new binary writer with big endian converter, writing\n        /// to the given stream.\n        /// </summary>\n        /// <param name=\"stream\">Stream to write data to</param>\n        internal BigEndianBinaryWriter (Stream stream)\n\t\t{\n\t\t\tif (stream==null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"stream\");\n\t\t\t}\n\t\t\tif (!stream.CanWrite)\n\t\t\t{\n\t\t\t\tthrow new ArgumentException(\"Stream isn't writable\", \"stream\");\n\t\t\t}\n\t\t\tthis.stream = stream;\n\t\t}\n\t\t#endregion\n\n\t\t#region Properties\n\n\t    private readonly Stream stream;\n\n        #endregion\n\n        #region Public methods\n\n        /// <summary>\n        /// Writes a boolean value to the stream. 1 byte is written.\n        /// </summary>\n        /// <param name=\"value\">The value to write</param>\n        internal void Write (bool value)\n\t\t{\n\t\t\tBigEndianBitConverter.CopyBytes(value, buffer, 0);\n\t\t\tWriteInternal(buffer, 1);\n\t\t}\n\n        /// <summary>\n        /// Writes a 32-bit signed integer to the stream, using the bit converter\n        /// for this writer. 4 bytes are written.\n        /// </summary>\n        /// <param name=\"value\">The value to write</param>\n        internal void Write (int value)\n\t\t{\n            BigEndianBitConverter.CopyBytes(value, buffer, 0);\n\t\t\tWriteInternal(buffer, 4);\n\t\t}\n\n        /// <summary>\n        /// Writes a 64-bit signed integer to the stream, using the bit converter\n        /// for this writer. 8 bytes are written.\n        /// </summary>\n        /// <param name=\"value\">The value to write</param>\n        internal void Write (long value)\n\t\t{\n            BigEndianBitConverter.CopyBytes(value, buffer, 0);\n\t\t\tWriteInternal(buffer, 8);\n\t\t}\n\n        /// <summary>\n        /// Writes an array of bytes to the stream.\n        /// </summary>\n        /// <param name=\"value\">The values to write</param>\n        internal void Write (byte[] value)\n\t\t{\n\t\t\tif (value == null)\n\t\t\t{\n\t\t\t\tthrow (new ArgumentNullException(\"value\"));\n\t\t\t}\n\t\t\tWriteInternal(value, value.Length);\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Private methods\n\n\t\t/// <summary>\n\t\t/// Writes the specified number of bytes from the start of the given byte array,\n\t\t/// after checking whether or not the writer has been disposed.\n\t\t/// </summary>\n\t\t/// <param name=\"bytes\">The array of bytes to write from</param>\n\t\t/// <param name=\"length\">The number of bytes to write</param>\n\t\tprivate void WriteInternal (byte[] bytes, int length)\n\t\t{\n\t\t\tstream.Write(bytes, 0, length);\n\t\t}\n\t\t#endregion\n\t}\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/bigEndian/BigEndianBitConverter.cs",
    "content": "using System;\n\nnamespace org.apache.utils\n{\n\t/// <summary>\n\t/// Equivalent of System.BitConverter, but with big endianness.\n\t/// </summary>\n    internal static class BigEndianBitConverter\n\t{\n\t\t#region To(PrimitiveType) conversions\n\t\t/// <summary>\n\t\t/// Returns a Boolean value converted from one byte at a specified position in a byte array.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">An array of bytes.</param>\n\t\t/// <param name=\"startIndex\">The starting position within value.</param>\n\t\t/// <returns>true if the byte at startIndex in value is nonzero; otherwise, false.</returns>\n\t\tpublic static bool ToBoolean (byte[] value, int startIndex)\n\t\t{\n\t\t\tCheckByteArgument(value, startIndex, 1);\n\t\t\treturn BitConverter.ToBoolean(value, startIndex);\n\t\t}\n        \n\t\t/// <summary>\n\t\t/// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">An array of bytes.</param>\n\t\t/// <param name=\"startIndex\">The starting position within value.</param>\n\t\t/// <returns>A 32-bit signed integer formed by four bytes beginning at startIndex.</returns>\n\t\tpublic static int ToInt32 (byte[] value, int startIndex)\n\t\t{\n\t\t\treturn unchecked((int) (CheckedFromBytes(value, startIndex, 4)));\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">An array of bytes.</param>\n\t\t/// <param name=\"startIndex\">The starting position within value.</param>\n\t\t/// <returns>A 64-bit signed integer formed by eight bytes beginning at startIndex.</returns>\n\t\tpublic static long ToInt64 (byte[] value, int startIndex)\n\t\t{\n\t\t\treturn CheckedFromBytes(value, startIndex, 8);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Checks the given argument for validity.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The byte array passed in</param>\n\t\t/// <param name=\"startIndex\">The start index passed in</param>\n\t\t/// <param name=\"bytesRequired\">The number of bytes required</param>\n\t\t/// <exception cref=\"ArgumentNullException\">value is a null reference</exception>\n\t\t/// <exception cref=\"ArgumentOutOfRangeException\">\n\t\t/// startIndex is less than zero or greater than the length of value minus bytesRequired.\n\t\t/// </exception>\n\t\tprivate static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired)\n\t\t{\n\t\t\tif (value==null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"value\");\n\t\t\t}\n\t\t\tif (startIndex < 0 || startIndex > value.Length-bytesRequired)\n\t\t\t{\n\t\t\t\tthrow new ArgumentOutOfRangeException(\"startIndex\");\n\t\t\t}\n\t\t}\n\n        /// <summary>\n        /// Checks the arguments for validity before calling FromBytes\n        /// (which can therefore assume the arguments are valid).\n        /// </summary>\n        /// <param name=\"value\">The bytes to convert after checking</param>\n        /// <param name=\"startIndex\">The index of the first byte to convert</param>\n        /// <param name=\"bytesToConvert\">The number of bytes to convert</param>\n        /// <returns></returns>\n        static long CheckedFromBytes(byte[] value, int startIndex, int bytesToConvert)\n\t\t{\n\t\t\tCheckByteArgument(value, startIndex, bytesToConvert);\n\t\t\treturn FromBytes(value, startIndex, bytesToConvert);\n\t\t}\n\n        /// <summary>\n        /// Returns a value built from the specified number of bytes from the given buffer,\n        /// starting at index.\n        /// </summary>\n        /// <param name=\"buffer\">The data in byte array format</param>\n        /// <param name=\"startIndex\">The first index to use</param>\n        /// <param name=\"bytesToConvert\">The number of bytes to use</param>\n        /// <returns>The value built from the given bytes</returns>\n        private static long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)\n        {\n            long ret = 0;\n            for (int i = 0; i < bytesToConvert; i++)\n            {\n                ret = unchecked((ret << 8) | buffer[startIndex + i]);\n            }\n            return ret;\n        }\n\t\t#endregion\n        \n\t\t#region CopyBytes conversions\n\t\t/// <summary>\n\t\t/// Copies the given number of bytes from the least-specific\n\t\t/// end of the specified value into the specified byte array, beginning\n\t\t/// at the specified index.\n\t\t/// This is used to implement the other CopyBytes methods.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to copy bytes for</param>\n\t\t/// <param name=\"bytes\">The number of significant bytes to copy</param>\n\t\t/// <param name=\"buffer\">The byte array to copy the bytes into</param>\n\t\t/// <param name=\"index\">The first index into the array to copy the bytes into</param>\n\t\tprivate static void CopyBytes(long value, int bytes, byte[] buffer, int index)\n\t\t{\n\t\t\tif (buffer==null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"buffer\", \"Byte array must not be null\");\n\t\t\t}\n\t\t\tif (buffer.Length < index+bytes)\n\t\t\t{\n\t\t\t\tthrow new ArgumentOutOfRangeException(\"buffer\",\"Buffer not big enough for value\");\n\t\t\t}\n\t\t\tCopyBytesImpl(value, bytes, buffer, index);\n\t\t}\n\n        /// <summary>\n        /// Copies the specified number of bytes from value to buffer, starting at index.\n        /// </summary>\n        /// <param name=\"value\">The value to copy</param>\n        /// <param name=\"bytes\">The number of bytes to copy</param>\n        /// <param name=\"buffer\">The buffer to copy the bytes into</param>\n        /// <param name=\"index\">The index to start at</param>\n        private static void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)\n        {\n            int endOffset = index + bytes - 1;\n            for (int i = 0; i < bytes; i++)\n            {\n                buffer[endOffset - i] = unchecked((byte)(value & 0xff));\n                value = value >> 8;\n            }\n        }\n\n\t\t/// <summary>\n\t\t/// Copies the specified Boolean value into the specified byte array,\n\t\t/// beginning at the specified index.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">A Boolean value.</param>\n\t\t/// <param name=\"buffer\">The byte array to copy the bytes into</param>\n\t\t/// <param name=\"index\">The first index into the array to copy the bytes into</param>\n\t\tpublic static void CopyBytes(bool value, byte[] buffer, int index)\n\t\t{\n\t\t\tCopyBytes(value ? 1 : 0, 1, buffer, index);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Copies the specified 32-bit signed integer value into the specified byte array,\n\t\t/// beginning at the specified index.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The number to convert.</param>\n\t\t/// <param name=\"buffer\">The byte array to copy the bytes into</param>\n\t\t/// <param name=\"index\">The first index into the array to copy the bytes into</param>\n\t\tpublic static void CopyBytes(int value, byte[] buffer, int index)\n\t\t{\n\t\t\tCopyBytes(value, 4, buffer, index);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Copies the specified 64-bit signed integer value into the specified byte array,\n\t\t/// beginning at the specified index.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The number to convert.</param>\n\t\t/// <param name=\"buffer\">The byte array to copy the bytes into</param>\n\t\t/// <param name=\"index\">The first index into the array to copy the bytes into</param>\n\t\tpublic static void CopyBytes(long value, byte[] buffer, int index)\n\t\t{\n\t\t\tCopyBytes(value, 8, buffer, index);\n\t\t}\n        \n\t\t#endregion\n\t}\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/ILogConsumer.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace org.apache.utils\n{\n    /// <summary>\n    /// This is for providing external loggers for ZooKeeper\n    /// </summary>\n    public interface ILogConsumer\n    {\n        /// <summary>\n        /// The log method\n        /// </summary>\n        /// <param name=\"severity\"></param>\n        /// <param name=\"className\"></param>\n        /// <param name=\"message\"></param>\n        /// <param name=\"exception\"></param>\n        void Log(TraceLevel severity, string className, string message, Exception exception);\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/ILogProducer.cs",
    "content": "using System;\n\nnamespace org.apache.utils\n{\n    internal interface ILogProducer\n    {\n        void debugFormat(string format, params object[] args);\n        void debug(object message, Exception e = null);\n        void warn(object message, Exception e = null);\n        void info(object message, Exception e = null);\n        void error(object message, Exception e = null);\n        bool isDebugEnabled();\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/LogWriter.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Text;\n\nnamespace org.apache.utils\n{\n    internal class LogWriter\n    {\n        private static readonly string[] TRACE_TABLE = { \"OFF\", \"ERROR\", \"WARNING\", \"INFO\", \"VERBOSE\" };\n        private readonly NonBlockingFileWriter logFileWriter;\n        public readonly string FileName;\n\n        public LogWriter()\n        {\n            FileName = $\"ZK.{DateTime.UtcNow:yyyy-MM-dd-HH.mm.ss.fffZ}.log\";\n            logFileWriter = new NonBlockingFileWriter(FileName);\n        }\n        \n        /// <summary>\n        ///     The method to call during logging.\n        ///     This method should be very fast, since it is called synchronously during logging.\n        /// </summary>\n        /// <param name=\"traceLevel\">The severity of the message being traced.</param>\n        /// <param name=\"className\">The name of the logger tracing the message.</param>\n        /// <param name=\"message\">The message to log.</param>\n        /// <param name=\"exception\">The exception to log. May be null.</param>\n        public void Log(TraceLevel traceLevel, string className, string message, Exception exception)\n        {\n            var exc = PrintException(exception);\n            string msg = $\"[{PrintDate()} \\t{TRACE_TABLE[(int)traceLevel]} \\t{className} \\t{message}] \\t{exc}\";\n\n            TraceWriter.Write(msg, traceLevel);\n            logFileWriter.Write(msg);\n        }\n\n        public bool LogToFile\n        {\n            get { return logFileWriter.IsEnabled; }\n            set { logFileWriter.IsEnabled = value; }\n        }\n\n        public bool LogToTrace\n        {\n            get { return TraceWriter.LogToTrace; }\n            set { TraceWriter.LogToTrace = value; }\n        }\n        \n        /// <summary>\n        ///     Utility function to convert a <c>DateTime</c> object into printable data format used by the TraceLogger subsystem.\n        /// </summary>\n        /// <returns>Formatted string representation of the input data, in the printable format used by the TraceLogger subsystem.</returns>\n        private static string PrintDate()\n        {\n            // http://www.csharp-examples.net/string-format-datetime/\n            // http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx\n            const string TIME_FORMAT = \"HH:mm:ss.fff 'GMT'\"; // Example: 09:50:43.341 GMT\n            const string DATE_FORMAT = \"yyyy-MM-dd \" + TIME_FORMAT;\n            // Example: 2010-09-02 09:50:43.341 GMT - Variant of UniversalSortableDateTimePattern\n            return DateTime.UtcNow.ToString(DATE_FORMAT);\n        }\n\n        /// <summary>\n        ///     Utility function to convert an exception into printable format, including expanding and formatting any nested\n        ///     sub-expressions.\n        /// </summary>\n        /// <param name=\"exception\">The exception to be printed.</param>\n        /// <returns>\n        ///     Formatted string representation of the exception, including expanding and formatting any nested\n        ///     sub-expressions.\n        /// </returns>\n        private static string PrintException(Exception exception)\n        {\n            return exception == null ? string.Empty : PrintException_Helper(exception, 0, true);\n        }\n\n        private static string PrintException_Helper(Exception exception, int level, bool includeStackTrace)\n        {\n            if (exception == null) return string.Empty;\n            var sb = new StringBuilder();\n            sb.Append(PrintOneException(exception, level, includeStackTrace));\n            \n            var aggregateException = exception as AggregateException;\n            if (aggregateException != null)\n            {\n                var innerExceptions = aggregateException.InnerExceptions;\n                if (innerExceptions == null) return sb.ToString();\n\n                foreach (var inner in innerExceptions)\n                {\n                    // call recursively on all inner exceptions. Same level for all.\n                    sb.Append(PrintException_Helper(inner, level + 1, includeStackTrace));\n                }\n            }\n            else if (exception.InnerException != null)\n            {\n                // call recursively on a single inner exception.\n                sb.Append(PrintException_Helper(exception.InnerException, level + 1, includeStackTrace));\n            }\n            return sb.ToString();\n        }\n\n        private static string PrintOneException(Exception exception, int level, bool includeStackTrace)\n        {\n            if (exception == null) return string.Empty;\n            var stack = string.Empty;\n            if (includeStackTrace && exception.StackTrace != null)\n                stack = $\"{Environment.NewLine}{exception.StackTrace}\";\n\n            var message = exception.Message;\n\n            return $\"{Environment.NewLine}Exc level {level}: {exception.GetType()}: {message}{stack}\";\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/NonBlockingFileWriter.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.utils\n{\n    internal class NonBlockingFileWriter\n    {\n        private readonly StreamWriterWrapper logOutput;\n\n        private readonly VolatileBool isEnabled = new VolatileBool(true);\n\n        private readonly VolatileInt pendingMessages = new VolatileInt(0);\n\n        internal bool IsDisposed => logOutput.IsDisposed;\n        internal bool IsEmpty => logQueue.IsEmpty;\n\n        internal bool HasFailed => logOutput.HasFailed;\n        \n        internal bool ThrowWrite\n        {\n            get { return logOutput.ThrowWrite.Value; }\n            set { logOutput.ThrowWrite.Value = value; }\n        }\n\n        private readonly ConcurrentQueue<string> logQueue = new ConcurrentQueue<string>();\n\n        public NonBlockingFileWriter(string filename)\n        {\n            logOutput = new StreamWriterWrapper(filename);\n        }\n\n        public void Write(string str)\n        {\n            if (!isEnabled.Value && logOutput.IsDisposed) return;\n            logQueue.Enqueue(str);\n            if (pendingMessages.Increment() == 1)\n            {\n                startLogTask();\n            }\n        }\n\n        public bool IsEnabled\n        {\n            get { return isEnabled.Value; }\n            set { isEnabled.Value = value; }\n        }\n\n        private async void startLogTask()\n        {\n            do\n            {\n                if (logQueue.TryDequeue(out var msg))\n                {\n                    if (isEnabled.Value && !logOutput.HasFailed)\n                    {\n                        await logOutput.WriteAsync(msg).ConfigureAwait(false);\n                    }\n                    else logOutput.Dispose();\n                }\n            } while (pendingMessages.Decrement() > 0);\n        }\n\n        private class StreamWriterWrapper\n        {\n            private readonly string fileName;\n            private readonly VolatileBool isDisposed = new VolatileBool(true);\n            private readonly VolatileBool hasFailed = new VolatileBool(false);\n            internal readonly VolatileBool ThrowWrite = new VolatileBool(false);\n            private StreamWriter streamWriter;\n\n            public StreamWriterWrapper(string filename)\n            {\n                fileName = filename;\n            }\n\n            public async Task WriteAsync(string msg)\n            {\n                try\n                {\n                    if (isDisposed.Value)\n                    {\n                        isDisposed.Value = false;\n                        streamWriter = GetOrCreateLogFile();\n                    }\n                    if (ThrowWrite.Value)\n                    {\n                        throw new InvalidOperationException();\n                    }\n                    await streamWriter.WriteLineAsync(msg).ConfigureAwait(false);\n                    await streamWriter.FlushAsync().ConfigureAwait(false);\n                }\n                catch (Exception e)\n                {\n                    hasFailed.Value = true;\n                    Trace.TraceError(\"Error while writing to log, will not try again. Exception:\" + e);\n                    Dispose();\n                }\n            }\n\n            public void Dispose()\n            {\n                if (!isDisposed.Value)\n                {\n                    isDisposed.Value = true;\n                    streamWriter?.Dispose();\n                }\n            }\n\n            public bool IsDisposed => isDisposed.Value;\n\n            public bool HasFailed => hasFailed.Value;\n\n            private StreamWriter GetOrCreateLogFile()\n            {\n                var logFile = new FileInfo(fileName);\n                return logFile.Exists ? logFile.AppendText() : logFile.CreateText();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/TraceWriter.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace org.apache.utils\n{\n    internal static class TraceWriter\n    {\n        public static bool LogToTrace = true;\n        public static void Write(string msg, TraceLevel traceLevel)\n        {\n            if (!LogToTrace) return;\n            switch (traceLevel)\n            {\n                case TraceLevel.Off:\n                    break;\n                case TraceLevel.Error:\n                    Trace.TraceError(msg);\n                    break;\n                case TraceLevel.Warning:\n                    Trace.TraceWarning(msg);\n                    break;\n                case TraceLevel.Info:\n                    Trace.TraceInformation(msg);\n                    break;\n                case TraceLevel.Verbose:\n                    Trace.WriteLine(msg);\n                    break;\n            }\n            Trace.Flush();\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/TypeLogger.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace org.apache.utils\n{\n    internal class TypeLogger<T> : ILogProducer\n    {\n        public static readonly ILogProducer Instance = new TypeLogger<T>();\n\n        private static readonly string className = typeof (T).Name;\n\n        public void debugFormat(string format, params object[] args)\n        {\n            // avoids exceptions if format string contains braces in calls that were not\n            // designed to use format strings\n            var message = args == null || args.Length == 0 ? format : string.Format(format, args);\n\n            log(TraceLevel.Verbose, message);\n        }\n\n        public void debug(object message, Exception e = null)\n        {\n            log(TraceLevel.Verbose, message, e);\n        }\n\n        public void warn(object message, Exception e = null)\n        {\n            log(TraceLevel.Warning, message, e);\n        }\n\n        public void info(object message, Exception e = null)\n        {\n            log(TraceLevel.Info, message, e);\n        }\n\n        public void error(object message, Exception e = null)\n        {\n            log(TraceLevel.Error, message, e);\n        }\n\n        public bool isDebugEnabled()\n        {\n            return ZooKeeperLogger.Instance.LogLevel == TraceLevel.Verbose;\n        }\n\n        private static void log(TraceLevel traceLevel, object message, Exception e = null)\n        {\n            ZooKeeperLogger.Instance.Log(traceLevel, className, message.ToString(), e);\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/utils/log/ZooKeeperLogger.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace org.apache.utils\n{\n    internal class ZooKeeperLogger\n    {\n        internal static readonly ZooKeeperLogger Instance = new ZooKeeperLogger();\n        internal ILogConsumer CustomLogConsumer;\n        internal TraceLevel LogLevel = TraceLevel.Warning;\n        private readonly LogWriter logWriter = new LogWriter();\n        internal bool LogToFile\n        {\n            get { return logWriter.LogToFile; }\n            set { logWriter.LogToFile = value; }\n        }\n\n        internal bool LogToTrace\n        {\n            get { return logWriter.LogToTrace; }\n            set { logWriter.LogToTrace = value; }\n        }\n\n        internal string LogFileName\n        {\n            get { return logWriter.FileName; }\n        }\n\n        internal void Log(TraceLevel sev, string className, string message, Exception exception = null)\n        {\n            if (sev > LogLevel)\n            {\n                return;\n            }\n\n            logWriter.Log(sev, className, message, exception);\n            var logConsumer = CustomLogConsumer;\n            if (logConsumer == null) return;\n            try\n            {\n                logConsumer.Log(sev, className, message, exception);\n            }\n            catch (Exception e)\n            {\n                Trace.TraceError(\n                    $@\"Exception while passing a log message to log consumer. TraceLogger type:{logConsumer.GetType().FullName},\n                       name:{className}, severity:{sev}, message:{message}, message exception:{exception}, log consumer exception:{e}\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/AsyncResults.cs",
    "content": "using System.Collections.Generic;\nusing org.apache.zookeeper.data;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// this class is the base class for all return values of ZooKeeper methods\n    /// </summary>\n    public abstract class NodeResult {\n        /// <summary>\n        /// The Node stat\n        /// </summary>\n        public readonly Stat Stat;\n\n        internal NodeResult(Stat stat) {\n            Stat = stat;\n        }\n    }\n\n    /// <summary>\n    /// this class is the return value of the public getDataAsync methods\n    /// </summary>\n    public class DataResult : NodeResult {\n        /// <summary>\n        /// The node data\n        /// </summary>\n        public readonly byte[] Data;\n\n        internal DataResult(byte[] data, Stat stat) : base(stat) {\n            Data = data;\n        }\n    }\n\n    /// <summary>\n    /// this class is the return value of the public getChildrenAsync methods\n    /// </summary>\n    public class ChildrenResult : NodeResult {\n        /// <summary>\n        /// The node's children\n        /// </summary>\n        public readonly List<string> Children;\n\n        internal ChildrenResult(List<string> children, Stat stat) : base(stat) {\n            {\n                Children = children;\n            }\n        }\n    }\n\n    /// <summary>\n    /// this class is the return value of the public getACLAsync methods\n    /// </summary>\n    public class ACLResult: NodeResult {\n\n        /// <summary>\n        /// The node acls\n        /// </summary>\n        public readonly List<ACL> Acls;\n\n        internal ACLResult(List<ACL> acls, Stat stat)\n            : base(stat)\n        {\n            Acls = acls;\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ClientCnxn.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.client;\nusing org.apache.jute;\nusing org.apache.utils;\nusing org.apache.zookeeper.proto;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.zookeeper {\n/**\n * This class manages the socket i/o for the client. ClientCnxn maintains a list\n * of available servers to connect to and \"transparently\" switches servers it is\n * connected to as needed.\n *\n */\n    internal sealed class ClientCnxn {\n        private static readonly ILogProducer LOG = TypeLogger<ClientCnxn>.Instance;\n\n        /* ZOOKEEPER-706: If a session has a large number of watches set then\n         * attempting to re-establish those watches after a connection loss may\n         * fail due to the SetWatches request exceeding the server's configured\n         * jute.maxBuffer value. To avoid this we instead split the watch\n         * re-establishement across multiple SetWatches calls. This constant\n         * controls the size of each call. It is set to 128kB to be conservative\n         * with respect to the server's 1MB default for jute.maxBuffer.\n         */\n        private const int SET_WATCHES_MAX_LENGTH = 128 * 1024;\n        \n        private class AuthData {\n            internal AuthData(string scheme, byte[] data) {\n                this.scheme = scheme;\n                this.data = data;\n            }\n\n            internal readonly string scheme;\n\t\t\t\n            internal readonly byte[] data;\n        }\n\n        private List<AuthData> authInfo = new List<AuthData>();\n        /**\n\t * These are the packets that have been sent and are waiting for a response.\n\t */\n        internal readonly LinkedList<Packet> pendingQueue = new LinkedList<Packet>();\n        /**\n\t * These are the packets that need to be sent.\n\t */\n        internal readonly LinkedList<Packet> outgoingQueue = new LinkedList<Packet>();\n        private int connectTimeout\n        {\n            get\n            {\n                int timeout = negotiatedSessionTimeout.Value;\n                if (timeout == 0) timeout = sessionTimeout;\n                return timeout / hostProvider.size();\n            }\n        }\n\n        /**\n\t * The timeout in ms the client negotiated with the server. This is the\n\t * \"real\" timeout, not the timeout request by the client (which may have\n\t * been increased/decreased by the server which applies bounds to this\n\t * value.\n\t */\n        private readonly VolatileInt negotiatedSessionTimeout = new VolatileInt(0);\n        private int readTimeout;\n        private readonly int sessionTimeout;\n        private readonly ZooKeeper zooKeeper;\n        private readonly ClientWatchManager watcher;\n        private long sessionId;\n\t\t\n        private byte[] sessionPasswd;\n        /**\n\t * If true, the connection is allowed to go to r-o mode. This field's value\n\t * is sent, besides other data, during session creation handshake. If the\n\t * server on the other side of the wire is partitioned it'll accept\n\t * read-only clients only.\n\t */\n        private readonly bool readOnly;\n\t\t\n        public readonly string chrootPath;\n        \n\t\tprivate Task sendTask;\n\t\t\n        private Task eventTask;\n\n        private readonly Timer timer;\n\t\t\n        /**\n\t * Set to true when close is called. Latches the connection such that we\n\t * don't attempt to re-connect to the server if in the middle of closing the\n\t * connection (client sends session disconnect to server as part of close\n\t * operation)\n\t */\n        private readonly VolatileBool closing = new VolatileBool(false);\n\n        /**\n\t * A set of ZooKeeper hosts this client could connect to.\n\t */\n        private readonly HostProvider hostProvider;\n\n\t // Is set to true when a connection to a r/w server is established for the\n\t // first time; never changed afterwards.\n\n\t // Is used to handle situations when client without sessionId connects to a\n\t // read-only server. Such client receives \"fake\" sessionId from read-only\n\t // server, but this sessionId is invalid for other servers. So when such\n\t // client finds a r/w server, it sends 0 instead of fake sessionId during\n\t // connection handshake and establishes new, valid session.\n\n\t // If this field is false (which implies we haven't seen r/w server before)\n\t // then non-zero sessionId is fake, otherwise it is valid.\n\t //\n        internal readonly VolatileBool seenRwServerBefore = new VolatileBool(false);\n        \n        public long getSessionId() {\n            return sessionId;\n        }\n\n        public byte[] getSessionPasswd() {\n            return sessionPasswd;\n        }\n\n        public int getSessionTimeout() {\n            return negotiatedSessionTimeout.Value;\n        }\n\n        public override string ToString() {\n            StringBuilder sb = new StringBuilder();\n\n            EndPoint local = clientCnxnSocket.getLocalSocketAddress();\n            EndPoint remote = clientCnxnSocket.getRemoteSocketAddress();\n            sb\n\t\t\t    .Append(\"sessionid:0x\").Append(getSessionId().ToHexString())\n                .Append(\" local:\").Append(local)\n\t\t\t\t.Append(\" remoteserver:\").Append(remote)\n\t\t\t\t.Append(\" lastZxid:\").Append(lastZxid)\n\t\t\t\t.Append(\" xid:\").Append(xid)\n\t\t\t\t.Append(\" sent:\").Append(clientCnxnSocket.getSentCount())\n                .Append(\" recv:\").Append(clientCnxnSocket.getRecvCount())\n                //.Append(\" queuedpkts:\").Append(outgoingQueue.size())\n                //.Append(\" pendingresp:\").Append(pendingQueue.size())\n                .Append(\" queuedevents:\").Append(waitingEvents.size());\n\n            return sb.ToString();\n        }\n\n    /**\n\t * This class allows us to pass the headers and the relevant records around.\n\t */\n\n        public sealed class Packet : TaskCompletionSource<bool> {\n            internal readonly RequestHeader requestHeader;\n\n            internal readonly ReplyHeader replyHeader;\n\n            private readonly Record request;\n\n            internal readonly Record response;\n\n            internal ByteBuffer bb { get; private set; }\n\n            /** Client's view of the path (may differ due to chroot) **/\n            internal string clientPath;\n            /** Servers's view of the path (may differ due to chroot) **/\n            internal string serverPath;\n\n            internal void SetFinished() {\n                TrySetResult(true);\n            }\n            internal readonly ZooKeeper.WatchRegistration watchRegistration;\n            private readonly bool readOnly;\n\n            /** Convenience ctor */\n\n            internal Packet(RequestHeader requestHeader, ReplyHeader replyHeader,\n                Record request, Record response,\n                ZooKeeper.WatchRegistration watchRegistration) :\n                    this(requestHeader, replyHeader, request, response,\n                        watchRegistration, false) {\n            }\n\n            internal Packet(RequestHeader requestHeader, ReplyHeader replyHeader,\n                Record request, Record response,\n                ZooKeeper.WatchRegistration watchRegistration, bool readOnly):base(TaskCreationOptions.RunContinuationsAsynchronously) {\n                this.requestHeader = requestHeader;\n                this.replyHeader = replyHeader;\n                this.request = request;\n                this.response = response;\n                this.readOnly = readOnly;\n                this.watchRegistration = watchRegistration;\n            }\n\n        \tpublic void createBB() {\n            \ttry {\n                    MemoryStream ms = new MemoryStream();\n                    BigEndianBinaryWriter writer = new BigEndianBinaryWriter(ms);\n                    BinaryOutputArchive boa = BinaryOutputArchive.getArchive(writer);\n\n                    boa.writeInt(-1, \"len\"); // We'll fill this in later\n                    if (requestHeader != null) {\n                        ((Record) requestHeader).serialize(boa, \"header\");\n                    }\n                    if (request is ConnectRequest) {\n                        request.serialize(boa, \"connect\");\n                        // append \"am-I-allowed-to-be-readonly\" flag\n                        boa.writeBool(readOnly, \"readOnly\");\n                    } else if (request != null) {\n                        request.serialize(boa, \"request\");\n                    }\n                    ms.Position = 0;\n                    bb = new ByteBuffer(ms);\n                    boa.writeInt(bb.limit() - 4, \"len\");\n                    ms.Position = 0;\n\t\t\t\t} catch (Exception e) {\n                    LOG.warn(\"Ignoring unexpected exception\", e);\n\t\t\t\t}\n        }\n\n            public override string ToString() {\n                StringBuilder sb = new StringBuilder();\n                sb.Append(\"  clientPath:\").Append(clientPath);\n                sb.Append(\"  serverPath:\").Append(serverPath);\n                sb.Append(\"    finished:\").Append(Task.IsCompleted);\n                sb.Append(\"     header::\").Append(requestHeader);\n                sb.Append(\"replyHeader::\").Append(replyHeader);\n                sb.Append(\"    request::\").Append(request);\n                sb.Append(\"   response::\").Append(response);\n                // jute toString is horrible, remove unnecessary newlines\n                return sb.ToString().Replace(@\"\\r*\\n+\", \" \");\n            }\n        }\n\n\n        /**\n\t * Creates a connection object. The actual network connect doesn't get\n\t * established until needed. The start() instance method must be called\n\t * subsequent to construction.\n\t *\n\t * @param chrootPath - the chroot of this client. Should be removed from this Class in ZOOKEEPER-838\n\t * @param hostProvider\n\t *            the list of ZooKeeper servers to connect to\n\t * @param sessionTimeout\n\t *            the timeout for connections.\n\t * @param zooKeeper\n\t *            the zookeeper object that this connection is related to.\n\t * @param watcher watcher for this connection\n\t * @param clientCnxnSocket\n\t *            the socket implementation used (e.g. NIO/Netty)\n\t * @param sessionId\n\t *            session id if re-establishing session\n\t * @param sessionPasswd\n\t *            session passwd if re-establishing session\n\t * @param canBeReadOnly\n\t *            whether the connection is allowed to go to read-only mode in\n\t *            case of partitioning\n\t * @throws IOException\n\t */\n\n        internal ClientCnxn(string chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper,\n            ClientWatchManager watcher,\n            long sessionId, byte[] sessionPasswd, bool canBeReadOnly) {\n            this.zooKeeper = zooKeeper;\n            this.watcher = watcher;\n            this.sessionId = sessionId;\n            this.sessionPasswd = sessionPasswd;\n            this.sessionTimeout = sessionTimeout;\n            this.hostProvider = hostProvider;\n            this.chrootPath = chrootPath;\n            readTimeout = sessionTimeout*2/3;\n            readOnly = canBeReadOnly;\n            clientCnxnSocket = new ClientCnxnSocketNIO(this);\n            timer = new Timer(delegate { clientCnxnSocket.wakeupCnxn(); }, null, Timeout.Infinite, Timeout.Infinite);\n            state.Value = (int) ZooKeeper.States.CONNECTING;\n        }\n        public void start() {\n            sendTask = startSendTask();\n            eventTask = startEventTask();\n        }\n\n        private static readonly WatcherSetEventPair eventOfDeath = new WatcherSetEventPair(null, null);\n\n        private class WatcherSetEventPair {\n            internal readonly HashSet<Watcher> watchers;\n            internal readonly WatchedEvent @event;\n\n            public WatcherSetEventPair(HashSet<Watcher> watchers, WatchedEvent @event) {\n                this.watchers = watchers;\n                this.@event = @event;\n            }\n        }\n\n      private readonly AwaitableSignal waitingEventsSignal = new AwaitableSignal();\n      \n      private readonly ConcurrentQueue<WatcherSetEventPair> waitingEvents=new ConcurrentQueue<WatcherSetEventPair>();\n\n        \n\n\t\t\n\t\t/** This is really the queued session state until the event\n\t\t * task actually processes the event and hands it to the watcher. But for all\n\t\t * But for all intents and purposes this is the state.\n\t\t */\n            private readonly VolatileInt sessionState = new VolatileInt((int) Watcher.Event.KeeperState.Disconnected);\n\n        private void queueEvent(WatchedEvent @event) {\n                if (@event.get_Type() == Watcher.Event.EventType.None &&\n                    sessionState.Value == (int) @event.getState()) {\n                    return;\n                }\n                sessionState.Value = (int) @event.getState();\n                // materialize the watchers based on the event\n                WatcherSetEventPair pair = new WatcherSetEventPair(\n                    watcher.materialize(@event.getState(), @event.get_Type(),\n                        @event.getPath()), \n\t\t\t\t\t\t@event);\n                // queue the pair (watch set & event) for later processing\n                waitingEvents.Enqueue(pair);\n                waitingEventsSignal.TrySignal();\n            }\n\n\n            private void queueEventOfDeath() {\n                waitingEvents.Enqueue(eventOfDeath);\n                waitingEventsSignal.TrySignal();\n            }\n\n        private async Task startEventTask() {\n            bool wasKilled = false;\n\n            try {\n            while (!(wasKilled && waitingEvents.IsEmpty)) {\n                await waitingEventsSignal;\n                waitingEventsSignal.Reset();\n\n                WatcherSetEventPair @event;\n                while (waitingEvents.TryDequeue(out @event)) {\n                    if (@event == eventOfDeath) {\n                        wasKilled = true;\n                    }\n                    else {\n                        await processEvent(@event).ConfigureAwait(false);\n                    }\n                }\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Exception occurred in EventTask\", e);\n            }\n            LOG.info(\"EventTask shut down for session: 0x\" +\n                     getSessionId().ToHexString());\n        }\n\n        private static async Task processEvent(WatcherSetEventPair @event) {\n            foreach (Watcher watcher in @event.watchers) {\n                try {\n                    await watcher.process(@event.@event).ConfigureAwait(false);\n                } catch (Exception t) {\n                    LOG.error(\"Error while calling watcher \", t);\n                }\n            }\n        }\n\n        private static void finishPacket(Packet p) {\n            if (p.watchRegistration != null) {\n                p.watchRegistration.register(p.replyHeader.getErr());\n            }\n                p.SetFinished();\n        }\n\n        private void conLossPacket(Packet p) {\n            if (p.replyHeader == null) {\n                return;\n            }\n            switch (getState()) {\n                case ZooKeeper.States.AUTH_FAILED:\n                    p.replyHeader.setErr((int) KeeperException.Code.AUTHFAILED);\n                    break;\n                case ZooKeeper.States.CLOSED:\n                    p.replyHeader.setErr((int) KeeperException.Code.SESSIONEXPIRED);\n                    break;\n                default:\n                    p.replyHeader.setErr((int) KeeperException.Code.CONNECTIONLOSS);\n                    break;\n            }\n            //finishPacket(p); <-- moved outside since it should be called outside of a lock\n        }\n\n        private readonly VolatileLong lastZxid = new VolatileLong(0);\n\n        private class SessionTimeoutException : IOException {\n            public SessionTimeoutException(string msg) : base(msg) {\n            }\n        }\n\n        private class SessionExpiredException : IOException {\n            public SessionExpiredException(string msg) : base(msg) {\n            }\n        }\n\n        private class RWServerFoundException : IOException {\n            public RWServerFoundException(string msg) : base(msg) {\n            }\n        }\n\n        public const int packetLen = 0xfffff;\n\n            private long lastPingSentNs;\n            private readonly ClientCnxnSocketNIO clientCnxnSocket;\n            private readonly Random r = new Random();\n            private bool isFirstConnect = true;\n\n            internal void readResponse(ByteBuffer incomingBuffer) {\n                BigEndianBinaryReader bbis = new BigEndianBinaryReader(incomingBuffer.Stream);\n                BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);\n\n                ReplyHeader replyHdr = new ReplyHeader();\n                ((Record) replyHdr).deserialize(bbia, \"header\");\n                if (replyHdr.getXid() == -2) {\n                    // -2 is the xid for pings\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Got ping response for sessionid: 0x\" \n\t\t\t\t\t\t+ sessionId.ToHexString() \n\t\t\t\t\t\t+ \" after \" \n\t\t\t\t\t\t+ ((TimeHelper.ElapsedNanoseconds - lastPingSentNs) / 1000000) \n\t\t\t\t\t\t+ \"ms\");\n                    }\n                    return;\n                }\n                if (replyHdr.getXid() == -4) {\n                    // -4 is the xid for AuthPacket               \n                    if (replyHdr.getErr() == (int) KeeperException.Code.AUTHFAILED) {\n                        state.Value = (int) ZooKeeper.States.AUTH_FAILED;\n                        queueEvent(new WatchedEvent(Watcher.Event.EventType.None,\n                            Watcher.Event.KeeperState.AuthFailed, null));\n                    }\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Got auth sessionid:0x\"\n                                  + sessionId.ToHexString());\n                    }\n                    return;\n                }\n                if (replyHdr.getXid() == -1) {\n                    // -1 means notification\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Got notification sessionid:0x\"\n                                  + sessionId.ToHexString());\n                    }\n                    WatcherEvent @event = new WatcherEvent();\n                    ((Record) @event).deserialize(bbia, \"response\");\n                    // convert from a server path to a client path\n                    if (chrootPath != null) {\n                        string serverPath = @event.getPath();\n                        if (serverPath == chrootPath) {\n                            @event.setPath(\"/\");\n                        }\n                        else if (serverPath.Length > chrootPath.Length) {\n                            @event.setPath(serverPath.Substring(chrootPath.Length));\n                        }\n                        else {\n                            LOG.warn(\"Got server path \" + @event.getPath()\n                                     + \" which is too short for chroot path \"\n                                     + chrootPath);\n                        }\n                    }\n                    WatchedEvent we = new WatchedEvent(@event);\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Got \" + we + \" for sessionid 0x\" \n\t\t\t\t\t\t\t    + sessionId.ToHexString());\n                    }\n                    queueEvent(we);\n                    return;\n                }\n       \n                Packet packet;\n                lock (pendingQueue) {\n                    if (pendingQueue.size() == 0) {\n                        throw new IOException(\"Nothing in the queue, but got \"\n                                              + replyHdr.getXid());\n                    }\n                    packet = pendingQueue.First.Value;\n                    pendingQueue.RemoveFirst();\n                }\n            \t/*\n             \t* Since requests are processed in order, we better get a response\n             \t* to the first request!\n             \t*/\n                try {\n                    if (packet.requestHeader.getXid() != replyHdr.getXid()) {\n                        packet.replyHeader.setErr((int) \n\t\t\t\t\t\t        KeeperException.Code.CONNECTIONLOSS);\n                    throw new IOException(\"Xid out of order. Got Xid \"\n                                              + replyHdr.getXid() + \" with err \" +\n\t\t\t\t\t\t\t\t\t\t\t  + replyHdr.getErr() + \n\t\t\t\t\t\t\t\t\t\t\t  \" expected Xid \"\n                                              + packet.requestHeader.getXid()\n                                              + \" for a packet with details: \" \n\t\t\t\t\t\t\t\t\t\t\t  + packet);\n                    }\n                    packet.replyHeader.setXid(replyHdr.getXid());\n                    packet.replyHeader.setErr(replyHdr.getErr());\n                    packet.replyHeader.setZxid(replyHdr.getZxid());\n                    if (replyHdr.getZxid() > 0) {\n                        lastZxid.Value = replyHdr.getZxid();\n                    }\n                    if (packet.response != null && replyHdr.getErr() == 0) {\n                        packet.response.deserialize(bbia, \"response\");\n                    }\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Reading reply sessionid:0x\" \n\t\t\t\t\t\t+ sessionId.ToHexString() + \", packet:: \" + packet);\n                    }\n                } finally {\n                    finishPacket(packet);\n                }\n            }\n        internal void primeConnection() {\n                LOG.info(\"Socket connection established to \" +\n                         clientCnxnSocket.getRemoteSocketAddress() +\n                         \", initiating session\");\n                isFirstConnect = false;\n                long sessId = (seenRwServerBefore.Value) ? sessionId : 0;\n                ConnectRequest conReq = new ConnectRequest(0, lastZxid.Value,\n                    sessionTimeout, sessId, sessionPasswd);\n                lock (outgoingQueue) {\n                    // We add backwards since we are pushing into the front\n                    // Only send if there's a pending watch\n                    // TODO: here we have the only remaining use of zooKeeper in\n                    // this class. It's to be eliminated!\n                        List<string> dataWatches = zooKeeper.getDataWatches();\n                        List<string> existWatches = zooKeeper.getExistWatches();\n                        List<string> childWatches = zooKeeper.getChildWatches();\n                        long setWatchesLastZxid = lastZxid.Value;\n                        bool done = false;\n                        if (dataWatches.Count > 0 \n\t\t\t\t\t\t           || existWatches.Count > 0 || childWatches.Count > 0) {\n                        using(var dataWatchesIter = prependChroot(dataWatches).GetEnumerator())\n                        using(var existWatchesIter = prependChroot(existWatches).GetEnumerator())\n                        using(var childWatchesIter = prependChroot(childWatches).GetEnumerator())\n                        while (!done) {\n                            var dataWatchesBatch = new List<string>();\n                            var existWatchesBatch = new List<string>();\n                            var childWatchesBatch = new List<string>();\n                            int batchLength = 0;\n\n                            // Note, we may exceed our max length by a bit when we add the last\n                            // watch in the batch. This isn't ideal, but it makes the code simpler.\n                            while (batchLength < SET_WATCHES_MAX_LENGTH) {\n                                string watch;\n                                if (dataWatchesIter.MoveNext()) {\n                                    watch = dataWatchesIter.Current;\n                                    dataWatchesBatch.Add(watch);\n                                } else if (existWatchesIter.MoveNext()) {\n                                    watch = existWatchesIter.Current;\n                                    existWatchesBatch.Add(watch);\n                                } else if (childWatchesIter.MoveNext()) {\n                                    watch = childWatchesIter.Current;\n                                    childWatchesBatch.Add(watch);\n                                } else {\n                                    done = true;\n                                    break;\n                                }\n                                batchLength += watch.Length;\n                            }\n\n                            SetWatches sw = new SetWatches(setWatchesLastZxid,\n                                    dataWatchesBatch,\n                                    existWatchesBatch,\n                                    childWatchesBatch);\n                            RequestHeader h = new RequestHeader();\n                            h.set_Type((int) ZooDefs.OpCode.setWatches);\n                            h.setXid(-8);\n                            Packet packet = new Packet(h, new ReplyHeader(), sw, null, null);\n                            outgoingQueue.AddFirst(packet);\n                        }\n                    }\n                    foreach (AuthData id in authInfo) {\n                        outgoingQueue.AddFirst(new Packet(new RequestHeader(-4,\n                            (int) ZooDefs.OpCode.auth), null, new AuthPacket(0, id.scheme,\n                                id.data), null, null));\n                    }\n                    outgoingQueue.AddFirst(new Packet(null, null, conReq, \n\t\t\t\t\t            null, null, readOnly));\n                }\n                clientCnxnSocket.enableReadWriteOnly();\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Session establishment request sent on \" \n\t\t\t\t\t\t    + clientCnxnSocket.getRemoteSocketAddress());\n                }\n            }\n\n            private List<string> prependChroot(List<string> paths) {\n                if (chrootPath != null && paths.Count > 0) \n                {\n                    for (int i = 0; i < paths.size(); ++i) {\n                        string clientPath = paths[i];\n                        string serverPath;\n                        // handle clientPath = \"/\"\n                        if (clientPath.Length == 1) {\n                            serverPath = chrootPath;\n                        } else {\n                            serverPath = chrootPath + clientPath;\n                        }\n                        paths[i] = serverPath;\n                    }\n                }\n                return paths;\n            }\n\n            private void sendPing() {\n                lastPingSentNs = TimeHelper.ElapsedNanoseconds;\n                RequestHeader h = new RequestHeader(-2, (int) ZooDefs.OpCode.ping);\n                queuePacket(h, null, null, null, null, null, null);\n            }\n\n            private ResolvedEndPoint rwServerAddress;\n            private const int minPingRwTimeout = 100;\n            private const int maxPingRwTimeout = 60000;\n            private int pingRwTimeout = minPingRwTimeout;\n\n            private void startConnect(ResolvedEndPoint addr) {\n                state.Value = (int) ZooKeeper.States.CONNECTING;\n\n                logStartConnect(addr);\n\t\t\t\t\n                clientCnxnSocket.connect(addr);\n            }\n\n            private static void logStartConnect(ResolvedEndPoint addr) {\n                string msg = \"Opening socket connection to server \" + addr;\n                LOG.info(msg);\n            }\n\n            private const string RETRY_CONN_MSG = \n\t\t\t    \", closing socket connection and attempting reconnect\";\n\n            private async Task startSendTask() {\n                try { \n                clientCnxnSocket.introduce(sessionId);\n                clientCnxnSocket.updateNow();\n                clientCnxnSocket.updateLastSendAndHeard();\n            \tint to;\n                long lastPingRwServer = TimeHelper.ElapsedMiliseconds;\n                const int MAX_SEND_PING_INTERVAL = 10000; //10 seconds\n                ResolvedEndPoint serverAddress = null;\n                while (getState().isAlive()) {\n                    try {\n                        if (!clientCnxnSocket.isConnected()) {\n                            if (!isFirstConnect) {\n                                await Task.Delay(r.Next(1000)).ConfigureAwait(false);\n                            }\n                            else\n                            {\n                                await hostProvider.next(1000).ConfigureAwait(false);\n                            }\n                            // don't re-establish connection if we are closing\n                            if (closing.Value || !getState().isAlive()) {\n                                break;\n                            }\n                            if (rwServerAddress != null) {\n                                serverAddress = rwServerAddress;\n                                rwServerAddress = null;\n                            } else {\n                                serverAddress = await hostProvider.next(1000).ConfigureAwait(false);\n                            }\n                            startConnect(serverAddress);\n                            clientCnxnSocket.updateLastSendAndHeard();\n                        }\n\n                        if (getState().isConnected()) {\n                            to = readTimeout - clientCnxnSocket.getIdleRecv();\n                        } else {\n                            to = connectTimeout - clientCnxnSocket.getIdleRecv();\n                        }\n\n                        if (to <= 0) {\n                            string warnInfo;\n\t\t\t\t\t\t\twarnInfo = \"Client session timed out, have not heard from server in \"\n                                + clientCnxnSocket.getIdleRecv() \n\t\t\t\t\t\t\t\t+ \"ms\"\n                                + \" for sessionid 0x\"\n                                + clientCnxnSocket.sessionId.ToHexString();\n                            LOG.warn(warnInfo);\n                            throw new SessionTimeoutException(warnInfo);\n                        }\n                        if (getState().isConnected()) {\n                            // 1000(1 second) is to prevent race condition missing to send the second ping\n                            // also make sure not to send too many pings when readTimeout is small\n                            int timeToNextPing = readTimeout / 2 - clientCnxnSocket.getIdleSend() - \n\t\t\t\t\t\t\t ((clientCnxnSocket.getIdleSend() > 1000) ? 1000 : 0);\n                            // send a ping request either time is due or no packet sent out within MAX_SEND_PING_INTERVAL\n                            if (timeToNextPing <= 0 || clientCnxnSocket.getIdleSend() > MAX_SEND_PING_INTERVAL) {\n                                sendPing();\n                                clientCnxnSocket.updateLastSend();\n                            } else {\n                                if (timeToNextPing < to) {\n                                    to = timeToNextPing;\n                                }\n                            }\n                        }\n                        // If we are in read-only mode, seek for read/write server\n                        if (getState() == ZooKeeper.States.CONNECTEDREADONLY) {\n                            long now = TimeHelper.ElapsedMiliseconds;\n                            int idlePingRwServer = (int) (now - lastPingRwServer);\n                            if (idlePingRwServer >= pingRwTimeout) {\n                                lastPingRwServer = now;\n                                idlePingRwServer = 0;\n                                pingRwTimeout =\n\t\t\t\t\t\t\t\t    Math.Min(2*pingRwTimeout, maxPingRwTimeout);\n                                await pingRwServer().ConfigureAwait(false);\n                            }\n                            to = Math.Min(to, pingRwTimeout - idlePingRwServer);\n                        }\n                        if (to > 0 && !clientCnxnSocket.somethingIsPending.IsCompleted)\n                        {\n                            timer.Change(to, Timeout.Infinite);\n                            await clientCnxnSocket.somethingIsPending;\n                            timer.Change(Timeout.Infinite, Timeout.Infinite);\n                        }\n                        clientCnxnSocket.doTransport();\n                    } catch (Exception e) {\n                        if (closing.Value) {\n                            if (LOG.isDebugEnabled()) {\n                                // closing so this is expected\n                                LOG.debug(\"An exception was thrown while closing send task for session 0x\" +\n                                          getSessionId().ToHexString(), e);\n                            }\n                            break;\n                        }\n                        // this is ugly, you have a better way speak up\n                        if (e is SessionExpiredException) {\n                            LOG.info(\"closing socket connection\", e);\n                        } else if (e is SessionTimeoutException) {\n                            LOG.info(RETRY_CONN_MSG, e);\n                        } else if (e is EndOfStreamException) {\n                            LOG.info(RETRY_CONN_MSG, e);\n                        } else if (e is RWServerFoundException) {\n                            LOG.info(e);\n                        } else if (e is SocketException) {\n                            LOG.info(string.Format(\"Socket error occurred: {0}\", serverAddress), e);\n                        } else {\n                            LOG.warn(string.Format(\"Session 0x{0} for server {1}, unexpected error{2}\",\n                                    getSessionId().ToHexString(),\n                                    serverAddress,\n                                    RETRY_CONN_MSG), \n\t\t\t\t\t\t\t\te);\n                        }\n                        cleanup();\n                        if (getState().isAlive()) {\n                            queueEvent(new WatchedEvent(\n                                Watcher.Event.EventType.None,\n                                Watcher.Event.KeeperState.Disconnected, null));\n                        }\n                        clientCnxnSocket.updateNow();\n                        clientCnxnSocket.updateLastSendAndHeard();\n                    }\n                }\n\n                cleanup();\n                clientCnxnSocket.close();\n                if (getState().isAlive()) {\n                    queueEvent(new WatchedEvent(Watcher.Event.EventType.None,\n                        Watcher.Event.KeeperState.Disconnected, null));\n                }\n                }\n                catch(Exception e){\n                LOG.warn(\"Exception occurred in SendTask\", e);\n                }\n            LOG.debug(\"SendTask exited loop for session: 0x\" \n\t\t\t\t\t + getSessionId().ToHexString());\n            }\n\n            private async Task pingRwServer() {\n                string result = null;\n                ResolvedEndPoint addr = await hostProvider.next(0).ConfigureAwait(false);\n                LOG.info(\"Checking server \" + addr + \" for being r/w.\" +\n                         \" Timeout \" + pingRwTimeout);\n\n                TcpClient sock = null;\n                StreamReader br = null;\n                try {\n                    sock = new TcpClient();\n                    sock.LingerState = new LingerOption(false, 0);\n                    sock.SendTimeout = 1000;\n                    sock.NoDelay = true;\n                    await sock.ConnectAsync(addr.Address, addr.Port).ConfigureAwait(false);\n                    var networkStream = sock.GetStream();\n                    await networkStream.WriteAsync(\"isro\".UTF8getBytes(), 0, 4).ConfigureAwait(false);\n                    await networkStream.FlushAsync().ConfigureAwait(false);\n                    br = new StreamReader(networkStream);\n                    result = await br.ReadLineAsync().ConfigureAwait(false);\n            }\n                catch (Exception e) {\n                    var se = e.InnerException as SocketException;\n                    if (se != null && se.SocketErrorCode == SocketError.ConnectionRefused) {\n                        // ignore, this just means server is not up\n                    }\n                    else {\n                        // some unexpected error, warn about it\n                        LOG.warn(\"Exception while seeking for r/w server \", e);\n                    }\n                }\n                if (sock != null) {\n                    try {\n                        ((IDisposable) sock).Dispose();\n                    }\n                    catch (Exception e) {\n                        LOG.warn(\"Unexpected exception\", e);\n                    }\n                }\n                if (br != null) {\n                    try {\n                        br.Dispose();\n                    }\n                    catch (Exception e) {\n                        LOG.warn(\"Unexpected exception\", e);\n                    }\n                }\n\n                if (\"rw\" == result) {\n                    pingRwTimeout = minPingRwTimeout;\n                    // save the found address so that it's used during the next\n                    // connection attempt\n                    rwServerAddress = addr;\n                    throw new RWServerFoundException(\"Majority server found at \" \n\t\t\t\t\t        + addr);\n                }\n            }\n\n            private void cleanup() { \n                clientCnxnSocket.cleanup();\n                var connLostPackets = new List<Packet>();\n                lock (pendingQueue) {\n                    foreach (Packet p in pendingQueue) {\n                        conLossPacket(p);\n                        connLostPackets.Add(p);\n                    }\n                    pendingQueue.Clear();\n                }\n                lock (outgoingQueue) {\n                    foreach (Packet p in outgoingQueue) {\n                        conLossPacket(p);\n                        connLostPackets.Add(p);\n                    }\n                    outgoingQueue.Clear();\n                }\n                foreach (var conLostPacket in connLostPackets)\n                {\n                    finishPacket(conLostPacket);\n                }\n            }\n\n        /**\n         * Callback invoked by the ClientCnxnSocket once a connection has been\n         * established.\n         * \n         * @param _negotiatedSessionTimeout\n         * @param _sessionId\n         * @param _sessionPasswd\n         * @param isRO\n         * @throws IOException\n         */\n            internal void onConnected(int _negotiatedSessionTimeout, long _sessionId,\n                byte[] _sessionPasswd, bool isRO) {\n                negotiatedSessionTimeout.Value = _negotiatedSessionTimeout;\n                if (negotiatedSessionTimeout.Value <= 0) {\n                    state.Value = (int) ZooKeeper.States.CLOSED;\n                    queueEvent(new WatchedEvent(\n                        Watcher.Event.EventType.None,\n                        Watcher.Event.KeeperState.Expired, null));\n                    queueEventOfDeath();\n                string warnInfo = \"Unable to reconnect to ZooKeeper service, session 0x\" +\n                                                      sessionId.ToHexString() + \" has expired\";\n                LOG.warn(warnInfo);\n                throw new SessionExpiredException(warnInfo);\n                }\n                if (!readOnly && isRO) {\n                    LOG.error(\"Read/write client got connected to read-only server\");\n                }\n                readTimeout = negotiatedSessionTimeout.Value*2/3;\n                hostProvider.onConnected();\n                sessionId = _sessionId;\n                sessionPasswd = _sessionPasswd;\n                state.Value = (int) (isRO ? \n                    ZooKeeper.States.CONNECTEDREADONLY : ZooKeeper.States.CONNECTED);\n                seenRwServerBefore.Value |= !isRO;\n                LOG.info(\"Session establishment complete on server \" \n\t\t\t\t\t\t + clientCnxnSocket.getRemoteSocketAddress()\n                         + \", sessionid = 0x\" + sessionId.ToHexString()\n                         + \", negotiated timeout = \" + negotiatedSessionTimeout.Value\n                         + (isRO ? \" (READ-ONLY mode)\" : \"\"));\n                Watcher.Event.KeeperState eventState = (isRO)\n                    ? Watcher.Event.KeeperState.ConnectedReadOnly : Watcher.Event.KeeperState.SyncConnected;\n                queueEvent(new WatchedEvent(\n                    Watcher.Event.EventType.None, \n\t\t\t\t\teventState, null));\n            }\n\n            private void close() {\n                state.Value = (int) ZooKeeper.States.CLOSED;\n                clientCnxnSocket.wakeupCnxn();\n            }\n        \n\n        /**\n             * Shutdown the send/event tasks. This method should not be called\n             * directly - rather it should be called as part of close operation. This\n             * method is primarily here to allow the tests to verify disconnection\n             * behavior.\n             */\n\n        private void disconnect() {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Disconnecting client for session: 0x\" \n\t\t\t\t          + getSessionId().ToHexString());\n            }\n\t\t\t\n            close();\n            queueEventOfDeath();\n        }\n\n        private int isDisposed;\n\n    /**\n     * Close the connection, which includes; send session disconnect to the\n     * server, shutdown the send/event tasks.\n     *\n     */\n\n        internal async Task closeAsync() {\n            if (Interlocked.CompareExchange(ref isDisposed, 1, 0) == 0) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Closing client for session: 0x\" \n\t\t\t\t\t          + getSessionId().ToHexString());\n                }\n\n        \t\ttry {\n                \tRequestHeader h = new RequestHeader();\n                \th.set_Type((int) ZooDefs.OpCode.closeSession);\n\t\t\t\t\t\n                    await submitRequest(h, null, null, null).ConfigureAwait(false);\n                }\n                finally {\n                    disconnect();\n                }\n                await sendTask.ConfigureAwait(false);\n                await eventTask.ConfigureAwait(false);\n                timer.Dispose();\n            }\n        }\n\n        private int xid = 1;\n\n        private readonly VolatileInt state = new VolatileInt((int) ZooKeeper.States.NOT_CONNECTED);\n\t\t\n        /*\n             * getXid() is called externally by ClientCnxnNIO::doIO() when packets are\n             * sent from the outgoingQueue to the server. Thus, getXid() must be public.\n             */\n\n        public int getXid() {\n            return Interlocked.Increment(ref xid);\n        }\n        \n        public async Task<ReplyHeader> submitRequest(RequestHeader h, Record request, Record response,\n            ZooKeeper.WatchRegistration watchRegistration) {\n            ReplyHeader rep = new ReplyHeader();\n            Packet packet = queuePacket(h, rep, request, response, null, null, watchRegistration);\n            await packet.Task.ConfigureAwait(false);\n            return rep;\n        }\n\n  \n\n        internal Packet queuePacket(RequestHeader h, ReplyHeader rep, Record request,\n            Record response, string clientPath,\n            string serverPath, ZooKeeper.WatchRegistration watchRegistration) {\n            Packet packet;\n            // Note that we do not generate the Xid for the packet yet. It is\n            // generated later at send-time, by an implementation of\n            // ClientCnxnSocket::doIO(),\n            // where the packet is actually sent.\n            bool isConnectionLostPacket = false;\n            lock (outgoingQueue) {\n                packet = new Packet(h, rep, request, response, watchRegistration);\n                packet.clientPath = clientPath;\n                packet.serverPath = serverPath;\n                if (!getState().isAlive() || closing.Value) {\n                    conLossPacket(packet);\n                    isConnectionLostPacket = true;\n                }\n                else {\n                    // If the client is asking to close the session then\n                    // mark as closing\n                    if (h.get_Type() == (int) ZooDefs.OpCode.closeSession) {\n                        closing.Value = true;\n                    }\n                    outgoingQueue.AddLast(packet);\n                }\n            }\n            if(isConnectionLostPacket) finishPacket(packet);\n            clientCnxnSocket.wakeupCnxn();\n            return packet;\n        }\n\n        public void addAuthInfo(string scheme, byte[] auth) {\n            if (!getState().isAlive()) {\n                return;\n            }\n            List<AuthData> newAuthDataList = new List<AuthData>(authInfo) {new AuthData(scheme, auth)};\n            authInfo = newAuthDataList;\n            queuePacket(new RequestHeader(-4, (int) ZooDefs.OpCode.auth), null, new AuthPacket(0,\n                scheme, auth), null, null, null, null);\n        }\n\n        internal ZooKeeper.States getState() {\n            return (ZooKeeper.States) state.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ClientCnxnSocket.cs",
    "content": "﻿using System.IO;\nusing System.Net;\nusing System.Text;\nusing org.apache.jute;\nusing org.apache.utils;\nusing org.apache.zookeeper.proto;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// A ClientCnxnSocket does the lower level communication with a socket\n    /// implementation.\n    /// \n    /// This code has been moved out of ClientCnxn so that a Netty implementation can\n    /// be provided as an alternative to the NIO socket code.\n    /// \n    /// </summary>\n    internal abstract class ClientCnxnSocket {\n        private static readonly ILogProducer LOG = TypeLogger<ClientCnxnSocket>.Instance;\n\n        //This buffer is only used to read the length of the incoming message.\n        protected readonly ByteBuffer lenBuffer = ByteBuffer.allocate(4);\n        \n        //This is the current incoming data buffer\n        protected ByteBuffer incomingBuffer;\n\n        // This buffer is only used to read the incoming message contents (not the length) \n        private readonly ByteBuffer messageBuffer = ByteBuffer.allocate(256);\n\n        protected ClientCnxnSocket(ClientCnxn cnxn) {\n            incomingBuffer = lenBuffer;\n            clientCnxn = cnxn;\n        }\n\n        protected long sentCount;\n        protected long recvCount;\n        private long lastHeard;\n        private long lastSend;\n        private long now;\n        protected readonly ClientCnxn clientCnxn;\n\n        /// <summary>\n        /// The sessionId is only available here for Log and Exception messages.\n        /// Otherwise the socket doesn't need to know it.\n        /// </summary>\n        protected internal long sessionId;\n\n        internal void introduce(long sessionid) {\n            sessionId = sessionid;\n        }\n\n        internal void updateNow() {\n            now = TimeHelper.ElapsedMiliseconds;\n        }\n\n        internal int getIdleRecv() {\n            return (int) (now - lastHeard);\n        }\n\n        internal int getIdleSend() {\n            return (int) (now - lastSend);\n        }\n\n        internal long getSentCount() {\n            return sentCount;\n        }\n\n        internal long getRecvCount() {\n            return recvCount;\n        }\n\n        internal void updateLastHeard() {\n            lastHeard = now;\n        }\n\n        internal void updateLastSend() {\n            lastSend = now;\n        }\n\n        internal void updateLastSendAndHeard() {\n            lastSend = now;\n            lastHeard = now;\n        }\n\n        protected void readLength() {\n            int len = new BigEndianBinaryReader(incomingBuffer.Stream).ReadInt32();\n\n            if (len < 0 || len >= ClientCnxn.packetLen) {\n                throw new IOException(\"Packet len\" + len + \" is out of range!\");\n            }\n            messageBuffer.clear();\n            messageBuffer.Stream.SetLength(len);\n            messageBuffer.Stream.Capacity = len;\n\n            incomingBuffer = messageBuffer;\n        }\n\n        internal void readConnectResult() {\n            if (LOG.isDebugEnabled()) {\n                StringBuilder buf = new StringBuilder(\"0x[\");\n                foreach (byte b in incomingBuffer.Stream.ToArray()){\n                    buf.Append(b.ToHexString() + \",\");\n                }\n                buf.Append(\"]\");\n                LOG.debug(\"readConnectResult \" + incomingBuffer.remaining() + \" \" + buf);\n            }\n\n            BigEndianBinaryReader bebr = new BigEndianBinaryReader(incomingBuffer.Stream);\n            BinaryInputArchive bbia = BinaryInputArchive.getArchive(bebr);\n            ConnectResponse conRsp = new ConnectResponse();\n            ((Record) conRsp).deserialize(bbia, \"connect\");\n\n            // read \"is read-only\" flag\n            bool isRO = false;\n            try {\n                isRO = bbia.readBool(\"readOnly\");\n            }\n            catch (IOException) {\n                // this is ok -- just a packet from an old server which\n                // doesn't contain readOnly field\n                LOG.warn(\"Connected to an old server; r-o mode will be unavailable\");\n            }\n\n            sessionId = conRsp.getSessionId();\n            clientCnxn.onConnected(conRsp.getTimeOut(), sessionId, conRsp.getPasswd(), isRO);\n        }\n\n        internal abstract bool isConnected();\n\n        internal abstract void connect(IPEndPoint ipEndPoint);\n\n        internal abstract EndPoint getRemoteSocketAddress();\n\n        internal abstract EndPoint getLocalSocketAddress();\n\n        internal abstract void cleanup();\n\n        internal abstract void wakeupCnxn();\n\n        internal abstract void enableReadWriteOnly();\n\n        internal abstract void doTransport();\n\n        internal virtual void close() {\n            lenBuffer.Stream.Dispose();\n            messageBuffer.Stream.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ClientCnxnSocketNIO.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.zookeeper\n{\n    internal sealed class ClientCnxnSocketNIO : ClientCnxnSocket\n\t{\n        private static readonly ILogProducer LOG = TypeLogger<ClientCnxnSocketNIO>.Instance;\n\n\t    private bool initialized;\n\n\t\tprivate Socket socket;\n        \n        internal readonly AwaitableSignal somethingIsPending = new AwaitableSignal();\n\n\t    private readonly VolatileBool readEnabled = new VolatileBool(false);\n\n        private readonly VolatileBool writeEnabled = new VolatileBool(false);\n\n\t    private readonly VolatileReference<SocketContext> _socketAsyncEventArgsWrapper = new VolatileReference<SocketContext>(null);\n        \n\t    internal ClientCnxnSocketNIO(ClientCnxn cnxn) : base(cnxn)\n\t    {\n\t    }\n\n\t    internal override bool isConnected() {\n\t        return socket != null;\n\t    }\n\n        private void doIO()\n\t\t{\n\t\t\tvar localSock = socket;\n\t\t\tif (localSock == null)\n\t\t\t{\n\t\t\t\tthrow new IOException(\"Socket is null!\");\n\t\t\t}\n\t\t\tif (Readable && _socketAsyncEventArgsWrapper.Value.GetResult() == SocketAsyncOperation.Receive)\n\t\t\t{\n\t\t\t    try\n\t\t\t    {\n\t\t\t        localSock.read(incomingBuffer);\n                    _socketAsyncEventArgsWrapper.Value.StartReceiveAsync();\n\t\t\t    }\n\t\t\t\tcatch(Exception e)\n\t\t\t\t{\n\t\t\t\t\tthrow new EndOfStreamException(\"Unable to read additional data from server sessionid 0x\" + sessionId.ToHexString() + \", likely server has closed socket\",e);\n\t\t\t\t}\n\t\t\t\tif (!incomingBuffer.hasRemaining())\n\t\t\t\t{\n\t\t\t\t\tincomingBuffer.flip();\n\t\t\t\t\tif (incomingBuffer == lenBuffer)\n\t\t\t\t\t{\n\t\t\t\t\t\trecvCount++;\n\t\t\t\t\t\treadLength();\n\t\t\t\t\t}\n\t\t\t\t\telse if (!initialized)\n\t\t\t\t\t{\n\t\t\t\t\t\treadConnectResult();\n\t\t\t\t\t\tenableRead();\n                        if (findSendablePacket() != null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tenableWrite();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlenBuffer.clear();\n\t\t\t\t\t\tincomingBuffer = lenBuffer;\n\t\t\t\t\t\tupdateLastHeard();\n\t\t\t\t\t\tinitialized = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tclientCnxn.readResponse(incomingBuffer);\n\t\t\t\t\t\tlenBuffer.clear();\n\t\t\t\t\t\tincomingBuffer = lenBuffer;\n\t\t\t\t\t\tupdateLastHeard();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Writable)\n\t\t\t{\n                lock (clientCnxn.outgoingQueue)\n\t\t\t\t{\n                    var pNode = findSendablePacket();\n\t\t\t\t    var p = pNode.Value;\n\t\t\t\t\tif (p != null)\n\t\t\t\t\t{\n\t\t\t\t\t\tupdateLastSend();\n\t\t\t\t\t\t// If we already started writing p, p.bb will already exist\n\t\t\t\t\t\tif (p.bb == null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((p.requestHeader != null) && (p.requestHeader.get_Type() != (int) ZooDefs.OpCode.ping) && (p.requestHeader.get_Type() != (int) ZooDefs.OpCode.auth)) {\n                                p.requestHeader.setXid(clientCnxn.getXid());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tp.createBB();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlocalSock.write(p.bb);\n\t\t\t\t\t\tif (!p.bb.hasRemaining())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsentCount++;\n                            clientCnxn.outgoingQueue.Remove(pNode);\n\t\t\t\t\t\t\tif (p.requestHeader != null && p.requestHeader.get_Type() != (int) ZooDefs.OpCode.ping && p.requestHeader.get_Type() != (int) ZooDefs.OpCode.auth)\n\t\t\t\t\t\t\t{\n                                lock (clientCnxn.pendingQueue)\n\t\t\t\t\t\t\t\t{\n                                    clientCnxn.pendingQueue.AddLast(p);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n                    if (clientCnxn.outgoingQueue.Count == 0)\n\t\t\t\t\t{\n                        // No more packets to send: turn off write interest flag.\n                        // Will be turned on later by a later call to enableWrite(),\n                        // or in either doIO() or in doTransport() if not.\n\t\t\t\t\t\tdisableWrite();\n\t\t\t\t\t}\n\t\t\t\t\telse if (!initialized && p != null && !p.bb.hasRemaining())\n\t\t\t\t\t{\n                        p.bb.Stream.Dispose();\n                        disableWrite();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Just in case\n\t\t\t\t\t\tenableWrite();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t   \n        \n\t    private LinkedListNode<ClientCnxn.Packet> findSendablePacket()\n\t\t{\n            lock (clientCnxn.outgoingQueue)\n\t\t\t{\n                if (clientCnxn.outgoingQueue.Count == 0)\n                {\n                    return null;\n                }\n                return clientCnxn.outgoingQueue.First;\n\t\t\t}\n\t\t}\n\n\t\tinternal override void cleanup()\n\t\t{\n            readEnabled.Value = false;\n            writeEnabled.Value = false;\n\t\t\tif (socket != null)\n\t\t\t{\n                try\n                {\n                    socket.Close(0);\n                }\n\t\t\t\tcatch (Exception e)\n\t\t\t\t{\n\t\t\t\t\tif (LOG.isDebugEnabled())\n\t\t\t\t\t{\n                        LOG.debug(\"Ignoring exception during socket close\", e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t    try\n\t\t\t\t{\n\t\t\t         _socketAsyncEventArgsWrapper.Value.Dispose();\n\t\t\t\t}\n\t\t\t\tcatch (Exception e)\n\t\t\t\t{\n\t\t\t\t\tif (LOG.isDebugEnabled())\n\t\t\t\t\t{\n\t\t\t            LOG.debug(\"Ignoring exception during SocketAsyncEventArgs dispose\", e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tsocket = null;\n\t\t}\n\n\n        /// <summary>\n        /// create a socket channel. </summary>\n        /// <returns> the created socket channel </returns>\n        private static Socket createSock(AddressFamily addressFamily)\n\t    {\n\t\t\tSocket sock=new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);\n\t\t\tsock.Blocking = false;\n\t\t\tsock.LingerState = new LingerOption(false, 0);\n\t\t\tsock.NoDelay=true;\n\t\t\treturn sock;\n\t    }\n\n\t    /// <summary>\n\t\t/// register with the selection and connect </summary>\n        /// <param name=\"sock\"> the <seealso cref=\"Socket\"/> </param>\n\t\t/// <param name=\"addr\"> the address of remote host </param>\n        private void registerAndConnect(Socket sock, EndPoint addr)\n\t\t{\n\t\t    socket = sock;\n            _socketAsyncEventArgsWrapper.Value = SocketContext.StartConnectAsync(somethingIsPending, sock, addr);\n\t    }\n\n        internal override void connect(IPEndPoint addr)\n\t\t{\n\t\t\tSocket sock = createSock(addr.AddressFamily);\n            \n            try\n\t\t\t{\n\t\t\t   registerAndConnect(sock, addr);\n\t\t\t}\n\t\t\tcatch (Exception e)\n\t\t\t{\n\t\t\t    LOG.error(\"Unable to open socket to \" + addr, e);\n                sock.Dispose();\n\t\t\t\tthrow;\n\t\t\t}\n\t\t\tinitialized = false;\n\n\t\t\t/*\n\t\t\t * Reset incomingBuffer\n\t\t\t */\n\t\t\tlenBuffer.clear();\n\t\t\tincomingBuffer = lenBuffer;\n\t\t}\n\n        /// <summary>\n        /// Returns the address to which the socket is connected.\n        /// </summary>\n        /// <returns> ip address of the remote side of the connection or null if not\n        ///         connected </returns>\n\t    internal override EndPoint getRemoteSocketAddress() {\n            // a lot could go wrong here, so rather than put in a bunch of code\n            // to check for nulls all down the chain let's do it the simple\n            // yet bulletproof way\n            try\n            {\n                return _socketAsyncEventArgsWrapper.Value.RemoteEndPoint;\n            }\n            catch (NullReferenceException)\n            {\n                return null;\n            }\n\t    }\n\n\t\t/// <summary>\n\t\t/// Returns the local address to which the socket is bound.\n\t\t/// </summary>\n\t\t/// <returns> ip address of the remote side of the connection or null if not\n\t\t///         connected </returns>\n\t\tinternal override EndPoint getLocalSocketAddress()\n\t\t{\n\t\t\t\t// a lot could go wrong here, so rather than put in a bunch of code\n\t\t\t\t// to check for nulls all down the chain let's do it the simple\n\t\t\t\t// yet bulletproof way\n\t\t\t\ttry\n\t\t\t\t{\n                    return socket.LocalEndPoint;\n\t\t\t\t}\n\t\t\t\tcatch (NullReferenceException)\n\t\t\t\t{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t}\n\n\t\tinternal override void wakeupCnxn()\n\t\t{\n            somethingIsPending.TrySignal();\n\t\t}\n\n        internal override void doTransport() \n        {\n            somethingIsPending.Reset();\n\n            // Everything below and until we get back to the select is\n\t\t\t// non blocking, so time is effectively a constant. That is\n\t\t\t// Why we just have to do this once, here\n\t\t\tupdateNow();\n\n            if (_socketAsyncEventArgsWrapper.Value.GetResult() == SocketAsyncOperation.Connect)\n            {\n                updateLastSendAndHeard();\n                clientCnxn.primeConnection();\n                _socketAsyncEventArgsWrapper.Value.StartReceiveAsync();\n            }\n\n            doIO();\n\n\t        if (clientCnxn.getState().isConnected())\n\t\t\t{   \n                lock (clientCnxn.outgoingQueue)\n\t\t\t\t{\n                    if (findSendablePacket() != null)\n\t\t\t\t    {\n\t\t\t\t\t\tenableWrite();\n\t\t\t\t    }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n        private void enableWrite()\n        {\n            writeEnabled.Value = true;\n            wakeupCnxn();\n        }\n\n        private void disableWrite()\n        {\n            writeEnabled.Value = false;\n        }\n\n\t    private void enableRead()\n        {\n            readEnabled.Value = true;\n        }\n\t    \n        internal override void enableReadWriteOnly()\n        {\n            enableRead();\n            enableWrite();\n        }\n\t\n\t    private bool Writable\n\t    {\n\t        get\n\t        {\n\t            return writeEnabled.Value;\n\t        }\n\t    }\n\n\t    private bool Readable\n\t    {\n\t        get\n\t        {\n\t            return readEnabled.Value;\n\t        }\n\t    }\n    }\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ClientWatchManager.cs",
    "content": "using System.Collections.Generic;\n\nnamespace org.apache.zookeeper\n{\n    internal interface ClientWatchManager\n    {\n        /**\n         * Return a set of watchers that should be notified of the event. The \n         * manager must not notify the watcher(s), however it will update it's \n         * internal structure as if the watches had triggered. The intent being \n         * that the callee is now responsible for notifying the watchers of the \n         * event, possibly at some later time.\n         * \n         * @param state event state\n         * @param type event type\n         * @param path event path\n         * @return\n         */\n        HashSet<Watcher> materialize(Watcher.Event.KeeperState state, Watcher.Event.EventType type, string path);\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/CreateMode.cs",
    "content": "using org.apache.utils;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// The type of node creation\n    /// </summary>\n    public sealed class CreateMode\n    {\n        /// <summary>\n        /// The znode will not be automatically deleted upon client's disconnect.\n        /// </summary>\n        public static readonly CreateMode PERSISTENT = new CreateMode(0, false, false, false, false);\n\n        /// <summary>\n        /// The znode will not be automatically deleted upon client's disconnect,\n        /// and its name will be appended with a monotonically increasing number.\n        /// </summary>\n        public static readonly CreateMode PERSISTENT_SEQUENTIAL = new CreateMode(2, false, true, false, false);\n\n        /// <summary>\n        /// The znode will be deleted upon the client's disconnect.\n        /// </summary>\n        public static readonly CreateMode EPHEMERAL = new CreateMode(1, true, false, false, false);\n\n        /// <summary>\n        /// The znode will be deleted upon the client's disconnect, and its name\n        /// will be appended with a monotonically increasing number.\n        /// </summary>\n        public static readonly CreateMode EPHEMERAL_SEQUENTIAL = new CreateMode(3, true, true, false, false);\n\n        /// <summary>\n        /// The znode will be a container node. Container\n        /// nodes are special purpose nodes useful for recipes such as leader, lock,\n        /// etc.When the last child of a container is deleted, the container becomes\n        /// a candidate to be deleted by the server at some point in the future.\n        /// Given this property, you should be prepared to get\n        /// <see cref=\"KeeperException.NoNodeException\"/>\n        /// when creating children inside of this container node.\n        /// </summary>\n        public static readonly CreateMode CONTAINER = new CreateMode(4, false, false, true, false);\n\n        /// <summary>\n        /// The znode will not be automatically deleted upon client's disconnect.\n        /// However if the znode has not been modified within the given TTL, it\n\t\t/// will be deleted once it has no children.\n        /// </summary>  \n        public static readonly CreateMode PERSISTENT_WITH_TTL = new CreateMode(5, false, false, false, true);\n\n        /// <summary>\n        /// The znode will not be automatically deleted upon client's disconnect,\n        /// and its name will be appended with a monotonically increasing number.\n        /// However if the znode has not been modified within the given TTL, it\n        /// will be deleted once it has no children.\n        /// </summary>       \n        public static readonly CreateMode PERSISTENT_SEQUENTIAL_WITH_TTL = new CreateMode(6, false, true, false, true);\n\n        private static readonly ILogProducer LOG = TypeLogger<CreateMode>.Instance;\n\n        private readonly bool ephemeral;\n        private readonly bool sequential;\n        private readonly bool container;\n        private readonly int flag;\n        private readonly bool ttl;\n\n        private CreateMode(int flag, bool ephemeral, bool sequential,\n\t\t                   bool container, bool ttl) {\n            this.flag = flag;\n            this.ephemeral = ephemeral;\n            this.sequential = sequential;\n            this.container = container;\n            this.ttl = ttl;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is ephemeral.\n        /// </summary>\n        public bool isEphemeral() {\n            return ephemeral;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is sequential.\n        /// </summary>\n        public bool isSequential() {\n            return sequential;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is a container.\n        /// </summary>\n        public bool isContainer() {\n            return container;\n        }\n\n        /// <summary>\n        /// Determines whether this instance has ttl.\n        /// </summary>\n        public bool isTTL() {\n            return ttl;\n        }\n\n        internal int toFlag() {\n            return flag;\n        }\n\n    /**\n     * Map an integer value to a CreateMode value\n     */\n        internal static CreateMode fromFlag(int flag) {\n            switch (flag) {\n                case 0: return PERSISTENT;\n                case 1: return EPHEMERAL;\n                case 2: return PERSISTENT_SEQUENTIAL;\n                case 3: return EPHEMERAL_SEQUENTIAL;\n                case 4: return CONTAINER;\n                case 5: return PERSISTENT_WITH_TTL;\n                case 6: return PERSISTENT_SEQUENTIAL_WITH_TTL;\n\n                default:\n                    string errMsg = \"Received an invalid flag value: \" + flag\n                            + \" to convert to a CreateMode\";\n                    LOG.error(errMsg);\n                    throw new KeeperException.BadArgumentsException(errMsg);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/KeeperException.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing org.apache.utils;\n\nnamespace org.apache.zookeeper\n {\n    /// <summary>\n    /// ZooKeeper Base Exception\n    /// </summary>\n    public abstract class KeeperException : Exception\n    {\n        /// <summary>\n        /// All multi-requests that result in an exception retain the results\n        /// here so that it is possible to examine the problems in the catch\n        /// scope.Non-multi requests will get a null if they try to access these results.\n        /// </summary>\n        private List<OpResult> results;\n\n        /// <summary>\n        /// Factory method to create an instance of <see cref=\"KeeperException\"/> \n        /// according to passed Zookeeper error code and znode path(for which error happend).\n        /// All non-specific keeper exceptions should be constructed via \n        /// this factory method in order to guarantee consistency in error\n        /// codes and such.If you know the error code, then you should\n        /// construct the special purpose exception directly.That will\n        /// allow you to have the most specific possible declarations of\n        /// what exceptions might actually be thrown.\n        /// @param code The error code of your new exception.This will \n        /// also determine the specific type of the exception that is\n        /// returned.\n        /// @return The specialized exception, presumably to be thrown by\n        /// the caller.\n        /// </summary>\n        /// <param name=\"code\">Zookeeper error code(see <see cref=\"KeeperException.Code\"/> enum)</param>\n        /// <param name=\"path\">Znode path for which error happend</param>\n        /// <returns></returns>\n        public static KeeperException create(int code, string path = null)\n﻿        {\n﻿            switch (EnumUtil<Code>.DefinedCast(code))\n﻿            {\n﻿                //case Code.SYSTEMERROR:\n﻿                //    return new SystemErrorException();\n﻿                case Code.RUNTIMEINCONSISTENCY:\n﻿                    return new RuntimeInconsistencyException();\n﻿                case Code.DATAINCONSISTENCY:\n﻿                    return new DataInconsistencyException();\n﻿                case Code.CONNECTIONLOSS:\n﻿                    return new ConnectionLossException();\n﻿                case Code.MARSHALLINGERROR:\n﻿                    return new MarshallingErrorException();\n﻿                case Code.UNIMPLEMENTED:\n﻿                    return new UnimplementedException();\n﻿                case Code.OPERATIONTIMEOUT:\n﻿                    return new OperationTimeoutException();\n﻿                case Code.BADARGUMENTS:\n﻿                    return new BadArgumentsException(path);\n﻿                //case Code.APIERROR:\n﻿                //    return new APIErrorException();\n﻿                case Code.NONODE:\n﻿                    return new NoNodeException(path);\n﻿                case Code.NOAUTH:\n﻿                    return new NoAuthException();\n﻿                case Code.BADVERSION:\n﻿                    return new BadVersionException(path);\n﻿                case Code.NOCHILDRENFOREPHEMERALS:\n﻿                    return new NoChildrenForEphemeralsException(path);\n﻿                case Code.NODEEXISTS:\n﻿                    return new NodeExistsException(path);\n﻿                case Code.INVALIDACL:\n﻿                    return new InvalidACLException(path);\n﻿                case Code.AUTHFAILED:\n﻿                    return new AuthFailedException();\n﻿                case Code.NOTEMPTY:\n﻿                    return new NotEmptyException(path);\n﻿                case Code.SESSIONEXPIRED:\n﻿                    return new SessionExpiredException();\n﻿                case Code.INVALIDCALLBACK:\n﻿                    return new InvalidCallbackException();\n﻿                case Code.SESSIONMOVED:\n﻿                    return new SessionMovedException();\n﻿                case Code.NOTREADONLY:\n﻿                    return new NotReadOnlyException();\n﻿                case Code.OK:\n﻿                default:\n﻿                    throw new ArgumentOutOfRangeException(\"code\", \"Invalid exception code\");\n﻿            }\n        }\n              \n﻿        /// <summary>\n        /// Codes which represent the various KeeperException\n        /// types.This enum replaces the deprecated earlier static final int\n        /// constants.The old, deprecated, values are in \"camel case\" while the new \n        /// enum values are in all CAPS.\n        /// </summary>\n        public enum Code\n﻿        {\n            /// <summary>\n            /// Everything is OK\n            /// </summary>\n            OK = 0,\n\n            // System and server-side errors.\n            // This is never thrown by the server, it shouldn't be used other than\n            // to indicate a range. Specifically error codes greater than this\n            // value, but lesser than {@link #APIERROR}, are system errors.\n            //\n            //SYSTEMERROR = -1,\n\n            /// <summary> A runtime inconsistency was found </summary> \n            RUNTIMEINCONSISTENCY = -2,\n﻿            /// <summary> A data inconsistency was found </summary> \n﻿            DATAINCONSISTENCY = -3,\n﻿            /// <summary> Connection to the server has been lost </summary> \n﻿            CONNECTIONLOSS = -4,\n﻿            /// <summary> Error while marshalling or unmarshalling data </summary> \n﻿            MARSHALLINGERROR = -5,\n﻿            /// <summary> Operation is unimplemented </summary> \n﻿            UNIMPLEMENTED = -6,\n﻿            /// <summary> Operation timeout </summary> \n﻿            OPERATIONTIMEOUT = -7,\n﻿            /// <summary> Invalid arguments </summary> \n﻿            BADARGUMENTS = -8,\n\n            // API errors.\n            // This is never thrown by the server, it shouldn't be used other than\n            // to indicate a range. Specifically error codes greater than this\n            // value are API errors (while values less than this indicate a\n            // {@link #SYSTEMERROR}).\n            //\n            //APIERROR = -100,\n\n            /// <summary> Node does not exist </summary> \n            NONODE = -101,\n﻿            /// <summary> Not authenticated </summary> \n﻿            NOAUTH = -102,\n﻿            /// <summary> Version conflict </summary> \n﻿            BADVERSION = -103,\n﻿            /// <summary> Ephemeral nodes may not have children </summary> \n﻿            NOCHILDRENFOREPHEMERALS = -108,\n﻿            /// <summary> The node already exists </summary> \n﻿            NODEEXISTS = -110,\n﻿            /// <summary> The node has children </summary> \n﻿            NOTEMPTY = -111,\n﻿            /// <summary> The session has been expired by the server </summary> \n﻿            SESSIONEXPIRED = -112,\n﻿            /// <summary> Invalid callback specified </summary> \n﻿            INVALIDCALLBACK = -113,\n﻿            /// <summary> Invalid ACL specified </summary> \n﻿            INVALIDACL = -114,\n﻿            /// <summary> Client authentication failed </summary> \n﻿            AUTHFAILED = -115,\n﻿            /// <summary> Session moved to another server, so operation is ignored </summary> \n﻿            SESSIONMOVED = -118,\n\n﻿            /// <summary> State-changing request is passed to read-only server </summary>\n﻿            NOTREADONLY = -119\n﻿        }\n\n\t\tprivate readonly Code code;\n\n﻿        private readonly string path;\n\n﻿        private KeeperException(Code code)\n﻿        {\n﻿            this.code = code;\n﻿        }\n\n﻿        private KeeperException(Code code, string path)\n﻿        {\n﻿            this.code = code;\n﻿            this.path = path;\n        }\n\n        /// <summary>\n        /// Read the error Code for this exception\n        /// </summary>\n        /// <returns>the error Code for this exception</returns>\n        public Code getCode()\n        {\n            return code;\n        }\n\n        /// <summary>\n        /// Read the path for this exception\n        /// </summary>\n        /// <returns>the path associated with this error, null if none</returns>\n        public string getPath()\n        {\n            return path;\n        }\n\n        internal void setMultiResults(List<OpResult> res)\n        {\n            results = res;\n        }\n\n        /// <summary>\n        /// If this exception was thrown by a multi-request then the (partial) results\n        /// and error codes can be retrieved using this getter.\n        /// </summary>\n        /// <returns>A copy of the list of results from the operations in the multi-request.</returns>\n        public List<OpResult> getResults()\n        {\n            return results != null \n                    ? new List<OpResult>(results) \n                    : null;\n        }\n\n        /// <summary>\n        /// <see cref=\"Code.AUTHFAILED\"/>\n        /// </summary>\n        public class AuthFailedException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"AuthFailedException\"/>\n            /// </summary>\n            public AuthFailedException()\n﻿                : base(Code.AUTHFAILED)\n﻿            {\n﻿            }\n﻿        }\n\n        /// <summary>\n        /// <see cref=\"Code.BADARGUMENTS\"/>\n        /// </summary>\n        public class BadArgumentsException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"BadArgumentsException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public BadArgumentsException(string path)\n﻿                : base(Code.BADARGUMENTS, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.BADVERSION\"/>\n        /// </summary>\n        public class BadVersionException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"BadVersionException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public BadVersionException(string path)\n﻿                : base(Code.BADVERSION, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.CONNECTIONLOSS\"/>\n        /// </summary>\n        public class ConnectionLossException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"ConnectionLossException\"/>\n            /// </summary>\n            public ConnectionLossException()\n﻿                : base(Code.CONNECTIONLOSS)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.DATAINCONSISTENCY\"/>\n        /// </summary>\n        public class DataInconsistencyException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"DataInconsistencyException\"/>\n            /// </summary>\n            public DataInconsistencyException()\n﻿                : base(Code.DATAINCONSISTENCY)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.INVALIDACL\"/>\n        /// </summary>\n        public class InvalidACLException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"InvalidACLException\"/>\n            /// </summary>\n            public InvalidACLException()\n﻿                : base(Code.INVALIDACL)\n﻿            {\n﻿            }\n\n            /// <summary>\n            /// Create an instance of <see cref=\"InvalidACLException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public InvalidACLException(string path)\n﻿                : base(Code.INVALIDACL, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.INVALIDCALLBACK\"/>\n        /// </summary>\n        public class InvalidCallbackException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"InvalidCallbackException\"/>\n            /// </summary>\n            public InvalidCallbackException()\n﻿                : base(Code.INVALIDCALLBACK)\n﻿            {\n﻿            }\n﻿        }\n\n        /// <summary>\n        /// <see cref=\"Code.MARSHALLINGERROR\"/>\n        /// </summary>\n        public class MarshallingErrorException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"MarshallingErrorException\"/>\n            /// </summary>\n            public MarshallingErrorException()\n﻿                : base(Code.MARSHALLINGERROR)\n﻿            {\n﻿            }\n﻿        }\n\n        /// <summary>\n        /// <see cref=\"Code.NOAUTH\"/>\n        /// </summary>\n        public class NoAuthException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NoAuthException\"/>\n            /// </summary>\n            public NoAuthException()\n﻿                : base(Code.NOAUTH)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.NOCHILDRENFOREPHEMERALS\"/>\n        /// </summary>\n        public class NoChildrenForEphemeralsException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NoChildrenForEphemeralsException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public NoChildrenForEphemeralsException(string path)\n﻿                : base(Code.NOCHILDRENFOREPHEMERALS, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.NODEEXISTS\"/>\n        /// </summary>\n\n        public class NodeExistsException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NodeExistsException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public NodeExistsException(string path)\n﻿                : base(Code.NODEEXISTS, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.NONODE\"/>\n        /// </summary>\n        public class NoNodeException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NoNodeException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public NoNodeException(string path)\n﻿                : base(Code.NONODE, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.NOTEMPTY\"/>\n        /// </summary>\n        public class NotEmptyException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NotEmptyException\"/>\n            /// </summary>\n            /// <param name=\"path\"></param>\n            public NotEmptyException(string path)\n﻿                : base(Code.NOTEMPTY, path)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.OPERATIONTIMEOUT\"/>\n        /// </summary>\n        public class OperationTimeoutException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"OperationTimeoutException\"/>\n            /// </summary>\n            public OperationTimeoutException()\n﻿                : base(Code.OPERATIONTIMEOUT)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.RUNTIMEINCONSISTENCY\"/>\n        /// </summary>\n        public class RuntimeInconsistencyException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"RuntimeInconsistencyException\"/>\n            /// </summary>\n            public RuntimeInconsistencyException()\n﻿                : base(Code.RUNTIMEINCONSISTENCY)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.SESSIONEXPIRED\"/>\n        /// </summary>\n        public class SessionExpiredException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"SessionExpiredException\"/>\n            /// </summary>\n            public SessionExpiredException()\n﻿                : base(Code.SESSIONEXPIRED)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.SESSIONMOVED\"/>\n        /// </summary>\n        public class SessionMovedException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"SessionMovedException\"/>\n            /// </summary>\n            public SessionMovedException()\n﻿                : base(Code.SESSIONMOVED)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.NOTREADONLY\"/>\n        /// </summary>\n        public class NotReadOnlyException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"NotReadOnlyException\"/>\n            /// </summary>\n            public NotReadOnlyException() : base(Code.NOTREADONLY)\n﻿            {\n﻿            }\n﻿        }\n        \n        /// <summary>\n        /// <see cref=\"Code.UNIMPLEMENTED\"/>\n        /// </summary>\n        public class UnimplementedException : KeeperException\n﻿        {\n            /// <summary>\n            /// Create an instance of <see cref=\"UnimplementedException\"/>\n            /// </summary>\n            public UnimplementedException()\n﻿                : base(Code.UNIMPLEMENTED)\n﻿            {\n﻿            }\n﻿        }\n﻿    }\n﻿}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/MultiResponse.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing org.apache.jute;\nusing org.apache.utils;\nusing org.apache.zookeeper.proto;\n\nnamespace org.apache.zookeeper\n{\n\t/// <summary>\n\t/// Handles the response from a multi request.  Such a response consists of\n\t/// a sequence of responses each prefixed by a MultiResponse that indicates\n\t/// the type of the response.  The end of the list is indicated by a MultiHeader\n\t/// with a negative type.  Each individual response is in the same format as\n\t/// with the corresponding operation in the original request list.\n\t/// </summary>\n\tinternal class MultiResponse : Record, IEnumerable<OpResult>\n\t{\n\t\tprivate List<OpResult> results = new List<OpResult>();\n\n    public void add(OpResult x) {\n        results.Add(x);\n    }\n\n    public IEnumerator<OpResult> GetEnumerator()\n    {\n        return results.GetEnumerator();\n    }\n\n        public void serialize(OutputArchive archive, string tag) {\n\n\t\t\tforeach (OpResult result in results) {\n\t\t\t    ZooDefs.OpCode opcode = EnumUtil<ZooDefs.OpCode>.DefinedCast(result.get_Type());\n            int err = result.get_Type() == (int) ZooDefs.OpCode.error ? ((OpResult.ErrorResult)result).getErr() : 0;\n\n            ((Record) new MultiHeader(result.get_Type(), false, err)).serialize(archive, tag);\n\n                switch (opcode)\n\t\t\t\t{\n\t\t\t\t\tcase ZooDefs.OpCode.create:\n                    ((Record)new CreateResponse(((OpResult.CreateResult) result).getPath())).serialize(archive, tag);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ZooDefs.OpCode.delete:\n\t\t\t\t\tcase ZooDefs.OpCode.check:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ZooDefs.OpCode.setData:\n                    ((Record)new SetDataResponse(((OpResult.SetDataResult) result).getStat())).serialize(archive, tag);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ZooDefs.OpCode.error:\n                    ((Record)new ErrorResponse(((OpResult.ErrorResult) result).getErr())).serialize(archive, tag);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n                    throw new IOException(\"Invalid type \" + result.get_Type() + \" in MultiResponse\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t((Record) new MultiHeader(-1, true, -1)).serialize(archive, tag);\n\t\t}\n\n\n\t\tpublic void deserialize(InputArchive archive, string tag)\n\t\t{\n            results=new List<OpResult>();\n\t\t\tMultiHeader h = new MultiHeader();\n\t\t\t((Record) h).deserialize(archive, tag);\n\t\t\twhile (!h.getDone())\n\t\t\t{\n                ZooDefs.OpCode opcode = EnumUtil<ZooDefs.OpCode>.DefinedCast(h.get_Type());\n                switch (opcode)\n\t\t\t\t{\n\t\t\t\t\tcase ZooDefs.OpCode.create:\n\t\t\t\t\t\tCreateResponse cr = new CreateResponse();\n\t\t\t\t\t\t((Record) cr).deserialize(archive, tag);\n\t\t\t\t\t\tresults.Add(new OpResult.CreateResult(cr.getPath()));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ZooDefs.OpCode.delete:\n\t\t\t\t\t\tresults.Add(new OpResult.DeleteResult());\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ZooDefs.OpCode.setData:\n\t\t\t\t\t\tSetDataResponse sdr = new SetDataResponse();\n\t\t\t\t\t\t((Record) sdr).deserialize(archive, tag);\n\t\t\t\t\t\tresults.Add(new OpResult.SetDataResult(sdr.getStat()));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ZooDefs.OpCode.check:\n\t\t\t\t\t\tresults.Add(new OpResult.CheckResult());\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ZooDefs.OpCode.error:\n\t\t\t\t\t\t//FIXME: need way to more cleanly serialize/deserialize exceptions\n\t\t\t\t\t\tErrorResponse er = new ErrorResponse();\n\t\t\t\t\t\t((Record) er).deserialize(archive, tag);\n\t\t\t\t\t\tresults.Add(new OpResult.ErrorResult(er.getErr()));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new IOException(\"Invalid type \" + h.get_Type() + \" in MultiResponse\");\n\t\t\t\t}\n\t\t\t\t((Record) h).deserialize(archive, tag);\n\t\t\t}\n\t\t}\n\n    public List<OpResult> getResultList() {\n        return results;\n    }\n\n\t    IEnumerator IEnumerable.GetEnumerator()\n\t    {\n\t        return GetEnumerator();\n\t    }\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/MultiTransactionRecord.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing org.apache.jute;\nusing org.apache.utils;\nusing org.apache.zookeeper.proto;\n\nnamespace org.apache.zookeeper \n{\n    /// <summary>\n    /// Encodes a composite transaction.  In the wire format, each transaction\n    /// consists of a single MultiHeader followed by the appropriate request.\n    /// Each of these MultiHeaders has a type which indicates\n    /// the type of the following transaction or a negative number if no more transactions\n    /// are included.\n    /// </summary>\n    internal class MultiTransactionRecord : Record, IEnumerable<Op> {\n        private readonly List<Op> ops;\n\n        public MultiTransactionRecord() { ops=new List<Op>();}\n\n        public MultiTransactionRecord(IEnumerable<Op> o) {\n            ops = new List<Op>(o);\n        }\n\n        public IEnumerator<Op> GetEnumerator() {\n            return ops.GetEnumerator();\n        }\n\n        internal void add(Op op) {\n            ops.Add(op);\n        }\n\n        public void serialize(OutputArchive archive, string tag) {\n            foreach (Op op in ops) {\n                MultiHeader h = new MultiHeader(op.get_Type(), false, -1);\n                ((Record) h).serialize(archive, tag);\n                ZooDefs.OpCode opCode = EnumUtil<ZooDefs.OpCode>.DefinedCast(op.get_Type());\n                switch (opCode) {\n                    case ZooDefs.OpCode.create:\n                        op.toRequestRecord().serialize(archive, tag);\n                        break;\n                    case ZooDefs.OpCode.delete:\n                        op.toRequestRecord().serialize(archive, tag);\n                        break;\n                    case ZooDefs.OpCode.setData:\n                        op.toRequestRecord().serialize(archive, tag);\n                        break;\n                    case ZooDefs.OpCode.check:\n                        op.toRequestRecord().serialize(archive, tag);\n                        break;\n                    default:\n                        throw new IOException(\"Invalid type of op\");\n                }\n            }\n            ((Record) new MultiHeader(-1, true, -1)).serialize(archive, tag);\n        }\n\n        public void deserialize(InputArchive archive, string tag) {\n            MultiHeader h = new MultiHeader();\n            ((Record) h).deserialize(archive, tag);\n\n            while (!h.getDone()) {\n                ZooDefs.OpCode opCode = EnumUtil<ZooDefs.OpCode>.DefinedCast(h.get_Type());\n                switch (opCode) {\n                    case ZooDefs.OpCode.create:\n                        CreateRequest cr = new CreateRequest();\n                        ((Record) cr).deserialize(archive, tag);\n                        add(Op.create(cr.getPath(), cr.getData(), cr.getAcl(), cr.getFlags()));\n                        break;\n                    case ZooDefs.OpCode.delete:\n                        DeleteRequest dr = new DeleteRequest();\n                        ((Record) dr).deserialize(archive, tag);\n                        add(Op.delete(dr.getPath(), dr.getVersion()));\n                        break;\n                    case ZooDefs.OpCode.setData:\n                        SetDataRequest sdr = new SetDataRequest();\n                        ((Record) sdr).deserialize(archive, tag);\n                        add(Op.setData(sdr.getPath(), sdr.getData(), sdr.getVersion()));\n                        break;\n                    case ZooDefs.OpCode.check:\n                        CheckVersionRequest cvr = new CheckVersionRequest();\n                        ((Record) cvr).deserialize(archive, tag);\n                        add(Op.check(cvr.getPath(), cvr.getVersion()));\n                        break;\n                    default:\n                        throw new IOException(\"Invalid type of op\");\n                }\n                ((Record) h).deserialize(archive, tag);\n            }\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() {\n            return GetEnumerator();\n        }\n    }\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/Op.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing org.apache.jute;\nusing org.apache.zookeeper.common;\nusing org.apache.zookeeper.data;\nusing org.apache.zookeeper.proto;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    ///     Represents a single operation in a multi-operation transaction.  Each operation can be a create, update\n    ///     or delete or can just be a version check.\n    ///     Sub-classes of Op each represent each detailed type but should not normally be referenced except via\n    ///     the provided factory methods.\n    /// </summary>\n    public abstract class Op {\n        private readonly string path;\n        private readonly int type;\n        // prevent untyped construction\n        private Op(ZooDefs.OpCode type, string path) {\n            this.type = (int) type;\n            this.path = path;\n        }\n        /// <summary>\n        ///     Constructs a create operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path for the node\n        /// </param>\n        /// <param name=\"data\">\n        ///     the initial data for the node\n        /// </param>\n        /// <param name=\"acl\">\n        ///     the acl for the node\n        /// </param>\n        /// <param name=\"flags\">\n        ///     specifying whether the node to be created is ephemeral\n        ///     and/or sequential but using the integer encoding.\n        /// </param>\n        internal static Op create(string path, byte[] data, List<ACL> acl, int flags) {\n            return new Create(path, data, acl, flags);\n        }\n\n        /// <summary>\n        ///     Constructs a create operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path for the node\n        /// </param>\n        /// <param name=\"data\">\n        ///     the initial data for the node\n        /// </param>\n        /// <param name=\"acl\">\n        ///     the acl for the node\n        /// </param>\n        /// <param name=\"createMode\">\n        ///     specifying whether the node to be created is ephemeral\n        ///     and/or sequential\n        /// </param>\n        public static Op create(string path, byte[] data, List<ACL> acl, CreateMode createMode) {\n            return new Create(path, data, acl, createMode);\n        }\n\n        /// <summary>\n        ///     Constructs a delete operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node to be deleted.\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected node version.\n        /// </param>\n        public static Op delete(string path, int version = -1) {\n            return new Delete(path, version);\n        }\n\n        /// <summary>\n        ///     Constructs an update operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node\n        /// </param>\n        /// <param name=\"data\">\n        ///     the data to set\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected matching version\n        /// </param>\n        public static Op setData(string path, byte[] data, int version = -1) {\n            return new SetData(path, data, version);\n        }\n\n        /// <summary>\n        ///     Constructs an version check operation.  Arguments are as for the ZooKeeper.setData method except that\n        ///     no data is provided since no update is intended.  The purpose for this is to allow read-modify-write\n        ///     operations that apply to multiple znodes, but where some of the znodes are involved only in the read,\n        ///     not the write.  A similar effect could be achieved by writing the same data back, but that leads to\n        ///     way more version updates than are necessary and more writing in general.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected matching version\n        /// </param>\n        public static Op check(string path, int version) {\n            return new Check(path, version);\n        }\n\n        /**\n         * Gets the integer type code for an Op.  This code should be as from ZooDefs.OpCode\n         * @see ZooDefs.OpCode\n         * @return  The type code.\n         */\n        public int get_Type() {\n            return type;\n        }\n\n        /**\n         * Gets the path for an Op.\n         * @return  The path.\n         */\n        public string getPath() {\n            return path;\n        }\n        ///     Encodes an op for wire transmission.\n        /// <returns> An appropriate Record structure. </returns>\n        internal abstract Record toRequestRecord();\n\n        /// <summary>\n        ///     Reconstructs the transaction with the chroot prefix.\n        /// </summary>\n        /// <returns> transaction with chroot. </returns>\n        public abstract Op withChroot(string addRootPrefix);\n\n        /// <summary>\n        ///     Performs client path validations.\n        /// </summary>\n        /// <exception cref=\"ArgumentException\">\n        ///     if an invalid path is specified\n        /// </exception>\n        /// <exception cref=\"KeeperException.BadArgumentsException\">\n        ///     if an invalid create mode flag is specified\n        /// </exception>\n        internal virtual void validate() {\n            PathUtils.validatePath(path);\n        }\n        private class Create : Op {\n            private readonly List<ACL> acl;\n            private readonly byte[] data;\n            private readonly int flags;\n\n            internal Create(string path, byte[] data, List<ACL> acl, int flags)\n                : base(ZooDefs.OpCode.create, path) {\n                this.data = data;\n                this.acl = acl;\n                this.flags = flags;\n            }\n\n            internal Create(string path, byte[] data, List<ACL> acl, CreateMode createMode)\n                : base(ZooDefs.OpCode.create, path) {\n                this.data = data;\n                this.acl = acl;\n                flags = createMode.toFlag();\n            }\n\n            internal override Record toRequestRecord() {\n                return new CreateRequest(getPath(), data, acl, flags);\n            }\n\n            public override Op withChroot(string p) {\n                return new Create(p, data, acl, flags);\n            }\n\n            internal override void validate() {\n                CreateMode createMode = CreateMode.fromFlag(flags);\n                PathUtils.validatePath(getPath(), createMode.isSequential());\n            }\n        }\n\n        private class Delete : Op {\n            private readonly int version;\n\n            internal Delete(string path, int version) : base(ZooDefs.OpCode.delete, path) {\n                this.version = version;\n            }\n\n            internal override Record toRequestRecord() {\n                return new DeleteRequest(getPath(), version);\n            }\n\n            public override Op withChroot(string p) {\n                return new Delete(p, version);\n            }\n        }\n\n        private class SetData : Op {\n            private readonly byte[] data;\n            private readonly int version;\n\n            internal SetData(string path, byte[] data, int version) : base(ZooDefs.OpCode.setData, path) {\n                this.data = data;\n                this.version = version;\n            }\n\n            internal override Record toRequestRecord() {\n                return new SetDataRequest(getPath(), data, version);\n            }\n\n            public override Op withChroot(string p) {\n                return new SetData(p, data, version);\n            }\n        }\n\n        private class Check : Op {\n            private readonly int version;\n\n            internal Check(string path, int version) : base(ZooDefs.OpCode.check, path) {\n                this.version = version;\n            }\n\n            internal override Record toRequestRecord() {\n                return new CheckVersionRequest(getPath(), version);\n            }\n\n            public override Op withChroot(string p) {\n                return new Check(p, version);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/OpResult.cs",
    "content": "﻿using org.apache.zookeeper.data;\n\nnamespace org.apache.zookeeper \n{\n    /// <summary>\n    /// Encodes the result of a single part of a multiple operation commit.\n    /// </summary>\n    public abstract class OpResult \n    {\n        private readonly int type;\n        private OpResult(ZooDefs.OpCode type) \n        {\n            this.type = (int) type;\n        }\n        \n        /// <summary>\n        /// Encodes the return type as from <see cref=\"ZooDefs.OpCode\"/>.  Can be used\n        ///to dispatch to the correct cast needed for getting the desired\n        ///additional result data\n        /// </summary>\n        /// <returns>an integer identifying what kind of operation this result came from.</returns>\n        internal int get_Type() {\n            return type;\n        }\n\n        /// <summary>\n        /// A result from a create operation.  This kind of result allows the\n        /// path to be retrieved since the create might have been a sequential\n        /// create.\n        /// </summary>\n        public class CreateResult : OpResult \n        {\n            private readonly string path;\n\n            internal CreateResult(string path) : base(ZooDefs.OpCode.create) \n            {\n                this.path = path;\n            }\n\n            /// <summary>\n            /// Gets the path.\n            /// </summary>\n            public string getPath() {\n                return path;\n            }\n        }\n\n        /// <summary>\n        /// A result from a delete operation.  No special values are available.\n        /// </summary>\n        public class DeleteResult : OpResult \n        {\n            internal DeleteResult() : base(ZooDefs.OpCode.delete) \n            {\n            }\n        }\n\n        /// <summary>\n        /// A result from a setData operation.  This kind of result provides access\n        /// to the Stat structure from the update.\n        /// </summary>\n        public class SetDataResult : OpResult {\n            private readonly Stat stat;\n\n            internal SetDataResult(Stat stat) : base(ZooDefs.OpCode.setData) {\n                this.stat = stat;\n            }\n\n            /// <summary>\n            /// Gets the stat.\n            /// </summary>\n            /// <returns></returns>\n            public Stat getStat() {\n                return stat;\n            }\n        }\n\n        /// <summary>\n        /// A result from a version check operation.  No special values are available.\n        /// </summary>\n        public class CheckResult : OpResult \n        {\n            internal CheckResult() : base(ZooDefs.OpCode.check) \n            {\n            }\n\n        }\n\n        /// <summary>\n        /// An error result from any kind of operation.  The point of error results\n        /// is that they contain an error code which helps understand what happened. </summary>\n        public class ErrorResult : OpResult \n        {\n            private readonly int err;\n\n            internal ErrorResult(int err) : base(ZooDefs.OpCode.error) \n            {\n                this.err = err;\n            }\n\n            /// <summary>\n            /// Gets the error.\n            /// </summary>\n            public int getErr() {\n                return err;\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/Quotas.cs",
    "content": "namespace org.apache.zookeeper\n{\n    /// <summary>\n    /// Path Quotas\n    /// </summary>\n    public static class Quotas {\n        /// <summary>\n        /// the zookeeper nodes that acts as the management and status node\n        /// </summary>\n        public const string procZookeeper = \"/zookeeper\";\n        \n        /// <summary>\n        /// the zookeeper quota node that acts as the quota management node for zookeeper\n        /// </summary>\n        public const string quotaZookeeper = \"/zookeeper/quota\";\n        \n        /// <summary>\n        /// the limit node that has the limit of a subtree\n        /// </summary>\n        public const string limitNode = \"zookeeper_limits\";\n        \n        /// <summary>\n        /// the stat node that monitors the limit of a subtree.\n        /// </summary>\n        public const string statNode = \"zookeeper_stats\";\n        \n        /// <summary>\n        /// return the quota path associated with this prefix.\n        /// </summary>\n        /// <param name=\"path\">the actual path in zookeeper</param>\n        /// <returns>the limit quota path</returns>\n        public static string quotaPath(string path) {\n            return quotaZookeeper + path +\n                   \"/\" + limitNode;\n        }\n        \n        /// <summary>\n        /// return the stat quota path associated with this prefix.\n        /// </summary>\n        /// <param name=\"path\">the actual path in zookeeper</param>\n        /// <returns>the stat quota path</returns>\n        public static string statPath(string path) {\n            return quotaZookeeper + path + \"/\" +\n                   statNode;\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/StatsTrack.cs",
    "content": "namespace org.apache.zookeeper\n{\n\n\t/// <summary>\n\t/// a class that represents the stats associated with quotas\n\t/// </summary>\n\tpublic sealed class StatsTrack\n\t{\n\t    private const string countStr = \"count\";\n\t    private const string byteStr = \"bytes\";\n\n\t    /// <summary>\n\t\t/// a default constructor for\n\t\t/// stats\n\t\t/// </summary>\n\t\tpublic StatsTrack() : this(null)\n\t\t{\n\t\t}\n\t\t/// <summary>\n\t\t/// the stat string should be of the form count=int,bytes=long\n\t\t/// if stats is called with null the count and bytes are initialized\n\t\t/// to -1. </summary>\n\t\t/// <param name=\"stats\"> the stat string to be initialized with </param>\n\t\tpublic StatsTrack(string stats)\n\t\t{\n\t\t\tif (stats == null)\n\t\t\t{\n\t\t\t\tstats = \"count=-1,bytes=-1\";\n\t\t\t}\n\t\t\tstring[] split = stats.Split(',');\n\t\t\tif (split.Length != 2)\n\t\t\t{\n\t\t\t\tthrow new System.ArgumentException(\"invalid string \" + stats);\n\t\t\t}\n\t\t    Count = int.Parse(split[0].Split('=')[1]);\n\t\t    Bytes = long.Parse(split[1].Split('=')[1]);\n\t\t}\n\n\n\t    /// <summary>\n\t    /// get the count of nodes allowed as part of quota\n\t    /// </summary>\n\t    /// <returns> the count as part of this string </returns>\n\t    public readonly int Count;\n\n\n\t    /// <summary>\n\t    /// get the count of bytes allowed as part of quota\n\t    /// </summary>\n\t    /// <returns> the bytes as part of this string </returns>\n\t    public readonly long Bytes;\n\n\n        /// <summary>\n        /// returns the string that maps to this stat tracking.\n        /// </summary>\n        public override string ToString()\n\t\t{\n\t\t\treturn countStr + \"=\" + Count + \",\" + byteStr + \"=\" + Bytes;\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/Transaction.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\n\nnamespace org.apache.zookeeper\n{\n\t/// <summary>\n\t/// Provides a builder style interface for doing multiple updates. This is\n\t/// really just a thin layer on top of <see cref=\"ZooKeeper.multiAsync\"/>.\n\t/// \n\t/// @since 3.4.0\n\t/// \n\t/// </summary>\n\tpublic class Transaction\n\t{\n\t\tprivate readonly ZooKeeper zk;\n\t\tprivate readonly List<Op> ops = new List<Op>();\n\n\t    internal Transaction(ZooKeeper zk)\n\t\t{\n\t\t\tthis.zk = zk;\n\t\t}\n\n        /// <summary>\n        ///     Constructs a create operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path for the node\n        /// </param>\n        /// <param name=\"data\">\n        ///     the initial data for the node\n        /// </param>\n        /// <param name=\"acl\">\n        ///     the acl for the node\n        /// </param>\n        /// <param name=\"createMode\">\n        ///     specifying whether the node to be created is ephemeral\n        ///     and/or sequential.\n        /// </param>\n\t\tpublic Transaction create(string path, byte[] data, List<ACL> acl, CreateMode createMode)\n\t\t{\n            if (createMode == null) throw new ArgumentNullException(nameof(createMode));\n            ops.Add(Op.create(path, data, acl, createMode.toFlag()));\n\t\t\treturn this;\n\t\t}\n\n        /// <summary>\n        ///     Constructs a delete operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node to be deleted.\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected node version.\n        /// </param>\n\t\tpublic Transaction delete(string path, int version = -1)\n\t\t{\n\t\t\tops.Add(Op.delete(path, version));\n\t\t\treturn this;\n\t\t}\n\n        /// <summary>\n        ///     Constructs an version check operation.  Arguments are as for the ZooKeeper.setData method except that\n        ///     no data is provided since no update is intended.  The purpose for this is to allow read-modify-write\n        ///     operations that apply to multiple znodes, but where some of the znodes are involved only in the read,\n        ///     not the write.  A similar effect could be achieved by writing the same data back, but that leads to\n        ///     way more version updates than are necessary and more writing in general.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected matching version\n        /// </param>\n\t\tpublic Transaction check(string path, int version)\n\t\t{\n\t\t\tops.Add(Op.check(path, version));\n\t\t\treturn this;\n\t\t}\n\n        /// <summary>\n        ///     Constructs an update operation.  Arguments are as for the ZooKeeper method of the same name.\n        /// </summary>\n        /// <param name=\"path\">\n        ///     the path of the node\n        /// </param>\n        /// <param name=\"data\">\n        ///     the data to set\n        /// </param>\n        /// <param name=\"version\">\n        ///     the expected matching version\n        /// </param>\n        public Transaction setData(string path, byte[] data, int version = -1)\n\t\t{\n\t\t\tops.Add(Op.setData(path, data, version));\n\t\t\treturn this;\n\t\t}\n\n        /// <summary>\n        /// Commits the transaction.\n        /// </summary>\n        /// <returns>the results of each op</returns>\n        public Task<List<OpResult>> commitAsync()\n        {\n            return zk.multiAsync(ops);\n        }\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/WatchedEvent.cs",
    "content": "using org.apache.utils;\nusing org.apache.zookeeper.proto;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// an incoming event\n    /// </summary>\n    public class WatchedEvent {\n        private readonly Watcher.Event.KeeperState keeperState;\n        private readonly Watcher.Event.EventType eventType;\n        private readonly string path;\n\n        internal WatchedEvent(Watcher.Event.EventType eventType, Watcher.Event.KeeperState keeperState, string path) {\n            this.keeperState = keeperState;\n            this.eventType = eventType;\n            this.path = path;\n        }\n\n        /**\n     * Convert a WatcherEvent sent over the wire into a full-fledged WatcherEvent\n     */\n\n        internal WatchedEvent(WatcherEvent eventMessage) {\n            keeperState = EnumUtil<Watcher.Event.KeeperState>.DefinedCast(eventMessage.getState());\n            eventType = EnumUtil<Watcher.Event.EventType>.DefinedCast(eventMessage.get_Type());\n            path = eventMessage.getPath();\n        }\n\n        /// <summary>\n        /// Gets the state of the client.\n        /// </summary>\n        public Watcher.Event.KeeperState getState() {\n            return keeperState;\n        }\n\n        /// <summary>\n        /// Gets the node type.\n        /// </summary>\n        public Watcher.Event.EventType get_Type() {\n            return eventType;\n        }\n\n        /// <summary>\n        /// Gets the ndoe path.\n        /// </summary>\n        public string getPath() {\n            return path;\n        }\n\n        /// <summary/>\n        public override string ToString() {\n            return \"WatchedEvent state:\" + keeperState\n                   + \" type:\" + eventType + \" path:\" + path;\n        }\n\n        /**\n     *  Convert WatchedEvent to type that can be sent over network\n     */\n\n        internal WatcherEvent getWrapper() {\n            return new WatcherEvent((int)eventType,\n                (int)keeperState,\n                path);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/Watcher.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// This is a base class that an event handler class must implement. \n    /// A ZooKeeper client will get various events from the ZooKeepr server it connects to. \n    /// An application using such a client handles these events by registering a callback object \n    /// with the client. The callback object is expected to be an instance of a class that implements \n    /// Watcher class.\n    /// </summary>\n    public abstract class Watcher {\n        /// <summary>\n        /// Defines the possible states an Event may represent\n        /// </summary>\n        public static class Event\n        {\n            /// <summary>\n            /// Enumeration of states the ZooKeeper may be at the event\n            /// </summary>\n            public enum KeeperState\n            {\n                /// <summary>\n                /// The client is in the disconnected state - it is not connected\n                /// to any server in the ensemble.\n                /// </summary>\n                Disconnected = 0,\n                /// <summary>\n                /// The client is in the connected state - it is connected\n                /// to a server in the ensemble (one of the servers specified\n                /// in the host connection parameter during ZooKeeper client\n                /// creation).\n                /// </summary>\n                SyncConnected = 3,\n                /// <summary>\n                /// The authentication failed\n                /// </summary>\n                AuthFailed = 4,\n                /// <summary>\n                /// The client is connected to a read-only server, that is the\n                /// server which is not currently connected to the majority.\n                /// The only operations allowed after receiving this state is\n                /// read operations.\n                /// This state is generated for read-only clients only since\n                /// read/write clients aren't allowed to connect to r/o servers.\n                /// </summary>\n                ConnectedReadOnly = 5,\n                /// <summary>\n                /// The serving cluster has expired this session. The ZooKeeper\n                /// client connection (the session) is no longer valid. You must\n                /// create a new client connection (instantiate a new ZooKeeper\n                /// instance) if you with to access the ensemble.\n                /// </summary>\n                Expired = -112\n            }\n            /// <summary>\n            /// Enumeration of types of events that may occur on the ZooKeeper\n            /// </summary>\n            public enum EventType\n            {\n                /// <summary/>\n                None = -1,\n                /// <summary>\n                /// a node created\n                /// </summary>\n                NodeCreated = 1,\n                /// <summary>\n                /// a node deleted\n                /// </summary>\n                NodeDeleted = 2,\n                /// <summary>\n                /// node's data changed\n                /// </summary>\n                NodeDataChanged = 3,\n                /// <summary>\n                /// node's children changed\n                /// </summary>\n                NodeChildrenChanged = 4,\n                /// <summary>\n                /// node's data watch removed\n                /// </summary>\n                DataWatchRemoved = 5,\n                /// <summary>\n                /// a node's children watch removed\n                /// </summary>\n                ChildWatchRemoved = 6\n            }\n\n            /// <summary>\n            /// Enumeration of types of watchers\n            /// </summary>\n            public enum WatcherType\n            {\n                /// <summary/>\n                Children = 1,\n                /// <summary/>\n                Data = 2,\n                /// <summary/>\n                Any = 3\n            }\n        }\n\n        /// <summary>\n        /// Processes the specified event.\n        /// </summary>\n        /// <param name=\"event\">The event.</param>\n        public abstract Task process(WatchedEvent @event);\n    }\n\n    internal class WatcherDelegate : Watcher {\n        private readonly Func<WatchedEvent,Task> processor;\n        public WatcherDelegate(Func<WatchedEvent,Task> processor) {\n            this.processor = processor;\n        }\n\n        public override Task process(WatchedEvent @event) {\n            return processor(@event);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ZKUtil.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing org.apache.zookeeper.common;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary>\n    /// Some ZooKeeper Utilities\n    /// </summary>\n    public class ZKUtil\n\t{\n        private ZKUtil(){}\n        private static readonly ILogProducer LOG = TypeLogger<ZKUtil>.Instance;\n\t\t/// <summary>\n\t\t/// Recursively delete the node with the given path. \n\t\t/// <para>\n\t\t/// Important: All versions, of all nodes, under the given node are deleted.\n\t\t/// </para>\n\t\t/// <para>\n\t\t/// If there is an error with deleting one of the sub-nodes in the tree, \n\t\t/// this operation would abort and would be the responsibility of the app to handle the same.\n\t\t/// \n\t\t/// </para>\n\t\t/// </summary>\n\t\tpublic static async Task deleteRecursiveAsync(ZooKeeper zk, string pathRoot)\n\t\t{\n\t\t\tPathUtils.validatePath(pathRoot);\n\n\t\t\tList<string> tree = await listSubTreeBFS(zk, pathRoot).ConfigureAwait(false);\n\t\t\tLOG.debug(\"Deleting \" + tree);\n\t\t\tLOG.debug(\"Deleting \" + tree.Count + \" subnodes \");\n            Transaction t = new Transaction(zk);\n            \n\t\t\tfor (int i = tree.Count - 1; i >= 0 ; --i)\n\t\t\t{\n\t\t\t\t//Delete the leaves first and eventually get rid of the root\n\t\t\t\tt.delete(tree[i]); //Delete all versions of the node with -1.\n\t\t\t}\n\t\t    await t.commitAsync().ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// BFS Traversal of the system under pathRoot, with the entries in the list, in the \n\t\t/// same order as that of the traversal.\n\t\t/// <para>\n\t\t/// <b>Important:</b> This is <i>not an atomic snapshot</i> of the tree ever, but the\n\t\t///  state as it exists across multiple RPCs from zkClient to the ensemble.\n\t\t/// For practical purposes, it is suggested to bring the clients to the ensemble \n\t\t/// down (i.e. prevent writes to pathRoot) to 'simulate' a snapshot behavior.   \n\t\t/// \n\t\t/// </para>\n\t\t/// </summary>\n\t\t/// <param name=\"zk\"> the zookeeper handle </param>\n\t\t/// <param name=\"pathRoot\"> The znode path, for which the entire subtree needs to be listed. </param>\n\t\t/// <exception cref=\"KeeperException\">  </exception>\n\t\tpublic static async Task<List<string>> listSubTreeBFS(ZooKeeper zk, string pathRoot)\n\t\t{\n            Queue<string> queue = new Queue<string>();\n\t\t\tList<string> tree = new List<string>();\n\t\t\tqueue.Enqueue(pathRoot);\n\t\t\ttree.Add(pathRoot);\n\t\t\twhile (true) {\n\t\t\t    string node;\n\t\t\t    if (queue.Count == 0) {\n\t\t\t        break;\n\t\t\t    }\n\t\t\t    node = queue.Dequeue();\n\t\t\t    IList<string> children = (await zk.getChildrenAsync(node).ConfigureAwait(false)).Children;\n\t\t\t\tforeach (string child in children)\n\t\t\t\t{\n\t\t\t\t\tstring childPath = node + \"/\" + child;\n\t\t\t\t\tqueue.Enqueue(childPath);\n\t\t\t\t\ttree.Add(childPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tree;\n\t\t}\n\n        /// <summary>\n        /// Visits the subtree with root as given path and calls the passed callback with each znode\n        /// found during the search.It performs a depth-first, pre-order traversal of the tree.\n        /// <para>\n        /// <b>Important:</b> This is <i>not an atomic snapshot</i> of the tree ever, but the\n        /// state as it exists across multiple RPCs from zkClient to the ensemble.\n        /// For practical purposes, it is suggested to bring the clients to the ensemble\n        /// down (i.e.prevent writes to pathRoot) to 'simulate' a snapshot behavior.\n        /// </para>\n        /// </summary>\n         /// <param name=\"zk\"></param>\n         /// <param name=\"path\"></param>\n         /// <param name=\"watch\"></param>\n         /// <param name=\"visit\"></param>\n         /// <returns></returns>\n        public static async Task visitSubTreeDFS(ZooKeeper zk, string path, bool watch, Func<string, Task> visit)\n        {\n            PathUtils.validatePath(path);\n\n            await zk.getDataAsync(path, watch).ConfigureAwait(false);\n            await visit(path).ConfigureAwait(false);\n            await visitSubTreeDFSHelper(zk, path, watch, visit).ConfigureAwait(false);\n        }\n\n        private static async Task visitSubTreeDFSHelper(ZooKeeper zk, string path, bool watch, Func<string, Task> visit)\n        {\n            // we've already validated, therefore if the path is of length 1 it's the root\n            bool isRoot = path.Length == 1;\n            try\n            {\n                var childrenResult = await zk.getChildrenAsync(path, watch).ConfigureAwait(false);\n                List<string> childrenPaths = childrenResult.Children.Select(child => (isRoot ? path : path + \"/\") + child).ToList();\n                childrenPaths.Sort();\n\n                foreach (string childPath in childrenPaths)\n                {\n                    await visit(childPath).ConfigureAwait(false);\n                }\n\n                foreach (string childPath in childrenPaths)\n                {\n                    await visitSubTreeDFSHelper(zk, childPath, watch, visit).ConfigureAwait(false);\n                }\n            }\n            catch (KeeperException.NoNodeException)\n            {\n                // Handle race condition where a node is listed\n                // but gets deleted before it can be queried\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ZooDefs.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing org.apache.zookeeper.data;\n\nnamespace org.apache.zookeeper\n{\n    /// <summary/>\n    public static class ZooDefs\n    {\n        /// <summary>\n        /// Zookeeper configuration node\n        /// </summary>\n        public const string CONFIG_NODE = \"/zookeeper/config\";\n        internal enum OpCode\n        {\n            create = 1,\n            delete = 2,\n            exists = 3,\n            getData = 4,\n            setData = 5,\n            getACL = 6,\n            setACL = 7,\n            sync = 9,\n            ping = 11,\n            getChildren2 = 12,\n            check = 13,\n            multi = 14,\n            create2 = 15,\n            reconfig = 16,\n            checkWatches = 17,\n            removeWatches = 18,\n            createContainer = 19,\n            deleteContainer = 20,\n            createTTL = 21,\n            auth = 100,\n            setWatches = 101,\n            closeSession = -11,\n            error = -1,\n        }\n\n        /// <summary>\n        /// ZooKeeper Permissions\n        /// </summary>\n        [Flags]\n        public enum Perms\n        {\n            /// <summary>\n            /// read permission\n            /// </summary>\n            READ = 1 << 0,\n            /// <summary>\n            /// write permission\n            /// </summary>\n            WRITE = 1 << 1,\n            /// <summary>\n            /// create permission\n            /// </summary>\n            CREATE = 1 << 2,\n            /// <summary>\n            /// delete permission\n            /// </summary>\n            DELETE = 1 << 3,\n            /// <summary>\n            /// admin permission\n            /// </summary>\n            ADMIN = 1 << 4,\n            /// <summary>\n            /// All permissions\n            /// </summary>\n            ALL = READ | WRITE | CREATE | DELETE | ADMIN\n        }\n\n        \n        /// <summary/>\n        public static class Ids\n        {\n            /// <summary>\n            /// This Id represents anyone.\n            /// </summary>\n            public static readonly Id ANYONE_ID_UNSAFE = new Id(\"world\", \"anyone\");\n            \n            /// <summary>\n            /// This Id is only usable to set ACLs. It will get substituted with the \n            /// Id's the client authenticated with.\n            /// </summary>\n            public static readonly Id AUTH_IDS = new Id(\"auth\", \"\");\n            \n            /// <summary>\n            /// This is a completely open ACL\n            /// </summary>\n            public static readonly List<ACL> OPEN_ACL_UNSAFE = new List<ACL>(new[] { new ACL((int)Perms.ALL, ANYONE_ID_UNSAFE) });\n            \n            /// <summary>\n            /// This ACL gives the creators authentication id's all permissions.\n            /// </summary>\n            public static readonly List<ACL> CREATOR_ALL_ACL = new List<ACL>(new[] { new ACL((int)Perms.ALL, AUTH_IDS) });\n            \n            /// <summary>\n            /// This ACL gives the world the ability to read.\n            /// </summary>\n            public static readonly List<ACL> READ_ACL_UNSAFE = new List<ACL>(new[] { new ACL((int)Perms.READ, ANYONE_ID_UNSAFE) });\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/ZooKeeper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\n\nusing org.apache.utils;\nusing org.apache.zookeeper.client;\nusing org.apache.zookeeper.common;\nusing org.apache.zookeeper.data;\nusing org.apache.zookeeper.proto;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.zookeeper {\n    /// <summary>\n    /// This is the main class of ZooKeeper client library. To use a ZooKeeper\n    /// service, an application must first instantiate an object of ZooKeeper class.\n    /// All the iterations will be done by calling the methods of ZooKeeper class.\n    /// The methods of this class are thread-safe unless otherwise noted.\n    /// </summary>\n    /// <remarks>\n    /// Once a connection to a server is established, a session ID is assigned to the\n    /// client. The client will send heart beats to the server periodically to keep\n    /// the session valid.\n    /// \n    /// The application can call ZooKeeper APIs through a client as long as the\n    /// session ID of the client remains valid.\n    /// \n    /// If for some reason, the client fails to send heart beats to the server for a\n    /// prolonged period of time (exceeding the sessionTimeout value, for instance),\n    /// the server will expire the session, and the session ID will become invalid.\n    /// The client object will no longer be usable. To make ZooKeeper API calls, the\n    /// application must create a new client object.\n    /// \n    /// If the ZooKeeper server the client currently connects to fails or otherwise\n    /// does not respond, the client will automatically try to connect to another\n    /// server before its session ID expires. If successful, the application can\n    /// continue to use the client.\n    /// \n    /// The ZooKeeper API methods are either synchronous or asynchronous. Synchronous\n    /// methods blocks until the server has responded. Asynchronous methods just queue\n    /// the request for sending and return immediately. They take a callback object that\n    /// will be executed either on successful execution of the request or on error with\n    /// an appropriate return code (rc) indicating the error.\n    /// \n    /// Some successful ZooKeeper API calls can leave watches on the \"data nodes\" in\n    /// the ZooKeeper server. Other successful ZooKeeper API calls can trigger those\n    /// watches. Once a watch is triggered, an event will be delivered to the client\n    /// which left the watch at the first place. Each watch can be triggered only\n    /// once. Thus, up to one event will be delivered to a client for every watch it\n    /// leaves.\n    /// \n    /// A client needs an object of a class implementing Watcher interface for\n    /// processing the events delivered to the client.\n    ///\n    /// When a client drops the current connection and re-connects to a server, all the\n    /// existing watches are considered as being triggered but the undelivered events\n    /// are lost. To emulate this, the client will generate a special event to tell\n    /// the event handler a connection has been dropped. This special event has type\n    /// EventType None and KeeperState Disconnected\n    /// </remarks>\n    public class ZooKeeper {\n        private static readonly byte[] NO_PASSWORD = new byte[0];\n        private static readonly ILogProducer LOG = TypeLogger<ZooKeeper>.Instance;\n\n        private readonly ZKWatchManager watchManager = new ZKWatchManager();\n\n        internal List<string> getDataWatches() {\n            lock (watchManager.dataWatches) {\n                List<string> rc = new List<string>(watchManager.dataWatches.Keys);\n                return rc;\n            }\n        }\n\n        internal List<string> getExistWatches() {\n            lock (watchManager.existWatches) {\n                List<string> rc = new List<string>(watchManager.existWatches.Keys);\n                return rc;\n            }\n        }\n\n        internal List<string> getChildWatches() {\n            lock (watchManager.childWatches) {\n                List<string> rc = new List<string>(watchManager.childWatches.Keys);\n                return rc;\n            }\n        }\n\n        /// <summary>\n        /// Manage watchers and handle events generated by the ClientCnxn object.\n        /// We are implementing this as a nested class of ZooKeeper so that\n        /// the public methods will not be exposed as part of the ZooKeeper client API.\n        /// </summary>\n        private class ZKWatchManager : ClientWatchManager {\n            internal readonly Dictionary<string, HashSet<Watcher>> dataWatches =\n                new Dictionary<string, HashSet<Watcher>>();\n\n            internal readonly Dictionary<string, HashSet<Watcher>> existWatches =\n                new Dictionary<string, HashSet<Watcher>>();\n\n            internal readonly Dictionary<string, HashSet<Watcher>> childWatches =\n                new Dictionary<string, HashSet<Watcher>>();\n\n            private readonly VolatileReference<Watcher> _defaultWatcher = new VolatileReference<Watcher>(null);\n\n            internal Watcher defaultWatcher {\n                get { return _defaultWatcher.Value; }\n                set { _defaultWatcher.Value = value; }\n            }\n\n            private static void addTo(HashSet<Watcher> from, HashSet<Watcher> to) {\n                if (from != null) {\n                    to.addAll(from);\n                }\n            }\n\n            public HashSet<Watcher> materialize(Watcher.Event.KeeperState state, \n\t\t\t\t\t\t\t\t\t\tWatcher.Event.EventType type,\n                \t\t\t\t\t\tstring clientPath) \n\t\t{\n                HashSet<Watcher> result = new HashSet<Watcher>();\n                switch (type) {\n                    case Watcher.Event.EventType.None:\n                        result.Add(defaultWatcher);\n                        lock (dataWatches) {\n                            foreach (HashSet<Watcher> ws in dataWatches.Values) {\n                                result.addAll(ws);\n                            }\n                        }\n                        lock (existWatches) {\n                            foreach (HashSet<Watcher> ws in existWatches.Values) {\n                                result.addAll(ws);\n                            }\n                        }\n                        lock (childWatches) {\n                            foreach (HashSet<Watcher> ws in childWatches.Values) {\n                                result.addAll(ws);\n                            }\n                        }\n                        return result;\n                    case Watcher.Event.EventType.NodeDataChanged:\n                    case Watcher.Event.EventType.NodeCreated:\n                        lock (dataWatches) {\n                            addTo(dataWatches.remove(clientPath), result);\n                        }\n                        lock (existWatches) {\n                            addTo(existWatches.remove(clientPath), result);\n                        }\n                        break;\n                    case Watcher.Event.EventType.NodeChildrenChanged:\n                        lock (childWatches) {\n                            addTo(childWatches.remove(clientPath), result);\n                        }\n                        break;\n                    case Watcher.Event.EventType.NodeDeleted:\n                        lock (dataWatches) {\n                            addTo(dataWatches.remove(clientPath), result);\n                        }\n                        // XXX This shouldn't be needed, but just in case\n                        lock (existWatches) {\n                            HashSet<Watcher> list = existWatches.remove(clientPath);\n                            if (list != null) {\n                                addTo(list, result);\n                                LOG.warn(\"We are triggering an exists watch for delete! Shouldn't happen!\");\n                            }\n                        }\n                        lock (childWatches) {\n                            addTo(childWatches.remove(clientPath), result);\n                        }\n                        break;\n                    default:\n                        string msg = \"Unhandled watch event type \" + type \n\t\t\t\t\t\t    + \" with state \" + state + \" on path \" + clientPath;\n                        LOG.error(msg);\n                        throw new InvalidOperationException(msg);\n                }\n\t\t\t\t\n                return result;\n            }\n        }\n\n        /// <summary>\n        /// Register a watcher for a particular path.\n        /// </summary>\n        internal abstract class WatchRegistration {\n            private readonly Watcher watcher;\n            private readonly string clientPath;\n\n            protected WatchRegistration(Watcher watcher, string clientPath) {\n                this.watcher = watcher;\n                this.clientPath = clientPath;\n            }\n\n            protected abstract Dictionary<string, HashSet<Watcher>> getWatches(int rc);\n\n            /// <summary>\n            /// Register the watcher with the set of watches on path.\n            /// </summary>\n            /// <param name=\"rc\">the result code of the operation that attempted to add the watch on the path.</param>\n            public void register(int rc) {\n                if (shouldAddWatch(rc)) {\n                    var watches = getWatches(rc);\n                    lock (watches){\n                        HashSet<Watcher> watchers;\n                        watches.TryGetValue(clientPath, out watchers);\n                        if (watchers == null) {\n                            watchers = new HashSet<Watcher>();\n                            watches[clientPath] = watchers;\n                        }\n                        watchers.Add(watcher);\n                    }\n                }\n            }\n\n            /// <summary>\n            /// Determine whether the watch should be added based on return code.\n            /// </summary>\n            /// <param name=\"rc\">the result code of the operation that attempted to add the watch on the node</param>\n            /// <returns>true if the watch should be added, otw false</returns>\n            protected virtual bool shouldAddWatch(int rc) {\n                return rc == 0;\n            }\n        }\n\n        /// <summary>\n        /// Handle the special case of exists watches - they add a watcher\n        /// even in the case where NONODE result code is returned.\n        /// </summary>\n        private class ExistsWatchRegistration : WatchRegistration {\n            private readonly ZKWatchManager watchManager;\n\n            public ExistsWatchRegistration(ZKWatchManager watchManager, Watcher watcher, string clientPath)\n                : base(watcher, clientPath) {\n                this.watchManager = watchManager;\n            }\n\n            protected override Dictionary<string, HashSet<Watcher>> getWatches(int rc) {\n                return rc == 0 ? watchManager.dataWatches : watchManager.existWatches;\n            }\n\n            protected override bool shouldAddWatch(int rc) {\n                return rc == 0 || rc == (int) KeeperException.Code.NONODE;\n            }\n        }\n\n        private class DataWatchRegistration : WatchRegistration {\n            private readonly ZKWatchManager watchManager;\n\n            public DataWatchRegistration(ZKWatchManager watchManager, Watcher watcher, string clientPath)\n                : base(watcher, clientPath) {\n                this.watchManager = watchManager;\n            }\n\n            protected override Dictionary<string, HashSet<Watcher>> getWatches(int rc) {\n                return watchManager.dataWatches;\n            }\n        }\n\n        private class ChildWatchRegistration : WatchRegistration {\n            private readonly ZKWatchManager watchManager;\n\n            public ChildWatchRegistration(ZKWatchManager watchManager, Watcher watcher, string clientPath)\n                : base(watcher, clientPath) {\n                this.watchManager = watchManager;\n            }\n\n            protected override Dictionary<string, HashSet<Watcher>> getWatches(int rc) {\n                return watchManager.childWatches;\n            }\n        }\n\n        /// <summary>\n        /// ZooKeeper client states\n        /// </summary>\n        public enum States {\n            /// <summary>\n            /// Connecting to ZooKeeper Server\n            /// </summary>\n            CONNECTING, /*ASSOCIATING,*/\n            /// <summary>\n            /// Connected to ZooKeeper Service\n            /// </summary>\n            CONNECTED,\n            /// <summary>\n            /// Connecting to ZooKeeper Service in read only state\n            /// </summary>\n            CONNECTEDREADONLY,\n            /// <summary>\n            /// Closed Connection to ZooKeeper Service\n            /// </summary>\n            CLOSED,\n            /// <summary>\n            /// Authentication Failed with ZooKeeper Service\n            /// </summary>\n            AUTH_FAILED,\n            /// <summary>\n            /// Not Connected to ZooKeeper Service\n            /// </summary>\n            NOT_CONNECTED\n        }\n\n        internal readonly ClientCnxn cnxn;\n\n        /// <summary>\n        /// To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list \n        /// of host:port pairs, each corresponding to a ZooKeeper server.\n        /// Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - \n        /// potentially (usually) before the session is fully established. The watcher argument specifies the watcher that will be \n        /// notified of any changes in state. This notification can come at any point before or after the constructor call has returned.\n        /// The instantiated ZooKeeper client object will pick an arbitrary server from the connectstring and attempt to connect to it.\n        /// If establishment of the connection fails, another server in the connect string will be tried (the order is non-deterministic, as we random shuffle the list)\n        /// , until a connection is established. The client will continue attempts until the session is explicitly closed \n        /// (or the session is expired by the server).\n        /// Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the connection string. This will run the client \n        /// commands while interpreting all paths relative to this root (similar to the unix chroot command).\n        /// </summary>\n        /// <param name=\"connectstring\">comma separated host:port pairs, each corresponding to a zk server. \n        /// 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:\n        /// \"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 \n        /// be relative to this root - ie getting/setting/etc... \"/foo/bar\" would result in operations being run on \"/app/a/foo/bar\" \n        /// (from the server perspective).</param>\n        /// <param name=\"sessionTimeout\"> session timeout in milliseconds</param>\n        /// <param name=\"watcher\">a watcher object which will be notified of state changes, may also be notified for node events</param>\n        /// <param name=\"canBeReadOnly\">(added in 3.4) whether the created client is allowed to go to read-only mode in case of \n        /// partitioning. Read-only mode basically means that if the client can't find any majority servers but there's partitioned \n        /// server it could reach, it connects to one in read-only mode, i.e. read requests are allowed while write requests are not.\n        /// It continues seeking for majority in the background.</param>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"connectstring\"/>parsed or resolved to an empty list. also when given chroot is invalid\"/></exception>\n        public ZooKeeper(string connectstring, int sessionTimeout, Watcher watcher, bool canBeReadOnly = false) :\n            this(connectstring, sessionTimeout, watcher, 0, NO_PASSWORD, canBeReadOnly){\n        }\n\n        /// <summary>\n        /// To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list \n        /// of host:port pairs, each corresponding to a ZooKeeper server.\n        /// Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - \n        /// potentially (usually) before the session is fully established. The watcher argument specifies the watcher that will be \n        /// notified of any changes in state. This notification can come at any point before or after the constructor call has returned.\n        /// The instantiated ZooKeeper client object will pick an arbitrary server from the connectstring and attempt to connect to it.\n        /// If establishment of the connection fails, another server in the connect string will be tried (the order is non-deterministic, as we random shuffle the list)\n        /// , until a connection is established. The client will continue attempts until the session is explicitly closed \n        /// (or the session is expired by the server).\n        /// Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the connection string. This will run the client \n        /// commands while interpreting all paths relative to this root (similar to the unix chroot command).\n        /// Use <see cref=\"getSessionId\"/> and <see cref=\"getSessionPasswd\"/> on an established client connection, these values must be \n        /// passed as sessionId and sessionPasswd respectively if reconnecting. Otherwise, if not reconnecting, use the other \n        /// constructor which does not require these parameters.\n        /// </summary>\n        /// <param name=\"connectString\">comma separated host:port pairs, each corresponding to a zk server. \n        /// 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:\n        /// \"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 \n        /// be relative to this root - ie getting/setting/etc... \"/foo/bar\" would result in operations being run on \"/app/a/foo/bar\" \n        /// (from the server perspective).</param>\n        /// <param name=\"sessionTimeout\"> session timeout in milliseconds</param>\n        /// <param name=\"watcher\">a watcher object which will be notified of state changes, may also be notified for node events</param>\n        /// <param name=\"sessionId\">specific session id to use if reconnecting</param>\n        /// <param name=\"sessionPasswd\">password for this session</param>\n        /// <param name=\"canBeReadOnly\">(added in 3.4) whether the created client is allowed to go to read-only mode in case of \n        /// partitioning. Read-only mode basically means that if the client can't find any majority servers but there's partitioned \n        /// server it could reach, it connects to one in read-only mode, i.e. read requests are allowed while write requests are not.\n        /// It continues seeking for majority in the background.</param>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"connectString\"/> parsed or resolved to an empty list. also when given chroot is invalid\"/></exception>\n        public ZooKeeper(string connectString, int sessionTimeout, Watcher watcher,\n            long sessionId, byte[] sessionPasswd, bool canBeReadOnly = false) {\n            LOG.info(\"Initiating client connection, connectString=\" + connectString\n                     + \" sessionTimeout=\" + sessionTimeout\n                     + \" watcher=\" + watcher\n                     + \" sessionId=\" + sessionId.ToHexString()\n                     + \" sessionPasswd=\"\n                     + (sessionPasswd == null ? \"<null>\" : \"<hidden>\"));\n\n            sessionPasswd = sessionPasswd ?? NO_PASSWORD;\n            watchManager.defaultWatcher = new WatcherDelegate(@event =>\n            {\n                if (@event.getState() == Watcher.Event.KeeperState.SyncConnected || @event.getState() == Watcher.Event.KeeperState.ConnectedReadOnly) \n                { \n                    connectedSignal.TrySet();\n                }\n                else\n                { \n                    if(connectedSignal.Task.IsCompleted) connectedSignal.Reset();\n                }   \n                return watcher.process(@event);\n            });\n\n            ConnectStringParser connectStringParser = new ConnectStringParser(connectString);\n            HostProvider hostProvider = new DynamicHostProvider(\n                connectStringParser.getServerAddresses());\n            cnxn = new ClientCnxn(connectStringParser.getChrootPath(),\n                hostProvider, sessionTimeout, this, watchManager, \n                sessionId, sessionPasswd, canBeReadOnly);\n            cnxn.seenRwServerBefore.Value = sessionId > 0; // since user has provided sessionId\n            userDefinedSessionTimeout = sessionTimeout;\n            cnxn.start();\n        }\n\n        private readonly int userDefinedSessionTimeout;\n\n        internal readonly SignalTask connectedSignal = new SignalTask();\n        \n        /// <summary>\n        /// The session id for this ZooKeeper client instance. The value returned is not valid until the client connects to a \n        /// server and may change after a re-connect. This method is NOT thread safe.\n        /// </summary>\n        public long getSessionId() {\n            return cnxn.getSessionId();\n        }\n\n        /// <summary>\n        /// The session password for this ZooKeeper client instance. The value returned is not valid until the client connects to \n        /// a server and may change after a re-connect.This method is NOT thread safe\n        /// </summary>\n        public byte[] getSessionPasswd() {\n            return cnxn.getSessionPasswd();\n        }\n\n        /// <summary>\n        /// The negotiated session timeout for this ZooKeeper client instance.The value returned is not valid until the client \n        /// connects to a server and may change after a re-connect.This method is NOT thread safe.\n        /// </summary>\n        public int getSessionTimeout() {\n            return cnxn.getSessionTimeout();\n        }\n\n        /// <summary>\n        /// Add the specified scheme:auth information to this connection.\n        ///\n        /// This method is NOT thread safe\n        /// </summary>\n        /// <param name=\"scheme\">The scheme.</param>\n        /// <param name=\"auth\">The auth.</param>\n        public void addAuthInfo(string scheme, byte[] auth) {\n            cnxn.addAuthInfo(scheme, auth);\n        }\n        \n        /// <summary>\n        /// Close this client object. Once the client is closed, its session becomes\n        /// invalid. All the ephemeral nodes in the ZooKeeper server associated with\n        /// the session will be removed. The watches left on those nodes (and on\n        /// their parents) will be triggered.\n        /// </summary>   \n        public async Task closeAsync() \n        {\n            if (!cnxn.getState().isAlive()) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Close called on already closed client\");\n                }\n                return;\n            }\n\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Closing session: 0x\" + getSessionId().ToHexString());\n            }\n\n            try {\n                await cnxn.closeAsync().ConfigureAwait(false);\n            }\n            catch (Exception e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Ignoring unexpected exception during close\", e);\n                }\n            }\n\n            LOG.info(\"Session: 0x\" + getSessionId().ToHexString() + \" closed\");\n        }\n\n        /// <summary>\n        /// Prepend the chroot to the client path (if present). The expectation of\n        /// this function is that the client path has been validated before this\n        /// function is called\n        /// </summary>\n        /// <param name=\"clientPath\">The path to the node.</param>\n        /// <returns>server view of the path (chroot prepended to client path)</returns>\n        private string prependChroot(string clientPath) {\n            if (cnxn.chrootPath != null) {\n                // handle clientPath = \"/\"\n                if (clientPath.Length == 1) {\n                    return cnxn.chrootPath;\n                }\n                return cnxn.chrootPath + clientPath;\n            }\n            return clientPath;\n        }\n\n        /// <summary>\n        /// Create a node with the given path. The node data will be the given data,\n        /// and node acl will be the given acl.\n        /// \n        /// This operation, if successful, will trigger all the watches left on the\n        /// node of the given path by exists and getData API calls, and the watches\n        /// left on the parent node by getChildren API calls.\n        /// \n        /// If a node is created successfully, the ZooKeeper server will trigger the\n        /// watches on the path left by exists calls, and the watches on the parent\n        /// of the node by getChildrenAsync calls\n        /// \n        /// The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n        /// Arrays larger than this will cause a KeeperExecption to be thrown.\n        /// </summary>\n        /// <param name=\"path\">The path for the node.</param>\n        /// <param name=\"data\">The data for the node.</param>\n        /// <param name=\"acl\">The acl for the node.</param>\n        /// <param name=\"createMode\">specifying whether the node to be created is ephemeral and/or sequential. \n        /// An ephemeral node will be removed by the ZK server automatically when the session associated with the creation of the node expires.\n        /// A sequential node will be the given path plus a suffix \"i\" where i is the current sequential number of the node. \n        /// The sequence number is always fixed length of 10 digits, 0 padded. Once such a node is created, the sequential number will be incremented by one.\n        /// </param>\n        /// <returns>the actual path of the created node</returns>\n        /// <exception cref=\"KeeperException.NoChildrenForEphemeralsException\">An ephemeral node cannot have children.</exception>\n        /// <exception cref=\"KeeperException.NoNodeException\">the parent node does not exist</exception>\n        /// <exception cref=\"KeeperException.NodeExistsException\">a node with the same actual path already exists.(Never happens when CreateMode is sequential)</exception>\n        /// <exception cref=\"KeeperException.InvalidACLException\">the ACL is invalid, null, or empty</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task<string> createAsync(string path, byte[] data, List<ACL> acl, CreateMode createMode) {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath, createMode.isSequential());\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int) ZooDefs.OpCode.create);\n            CreateRequest request = new CreateRequest();\n            CreateResponse response = new CreateResponse();\n            request.setData(data);\n            request.setFlags(createMode.toFlag());\n            request.setPath(serverPath);\n            if (acl != null && acl.size() == 0) {\n                throw new KeeperException.InvalidACLException();\n            }\n            request.setAcl(acl);\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, null).ConfigureAwait(false);\n            if (r.getErr() != 0) {\n                throw KeeperException.create(r.getErr(),\n                    clientPath);\n            }\n            if (cnxn.chrootPath == null) {\n                return response.getPath();\n            }\n            return response.getPath().Substring(cnxn.chrootPath.Length);\n        }\n\n        /// <summary>\n        /// Delete the node with the given path.\n        /// This operation, if successful, will trigger all the watches on the node of the given path left by existsAsync calls, \n        /// and the watches on the parent node left by getChildrenAsync calls.\n        /// </summary>\n        /// <param name=\"path\">The path to delete</param>\n        /// <param name=\"version\">The version matches the node's version(if the given  version is -1, it matches any node's versions).</param>\n        /// <exception cref=\"KeeperException.NoNodeException\">the parent node does not exist</exception>\n        /// <exception cref=\"KeeperException.NotEmptyException\">the node has children</exception>\n        /// <exception cref=\"KeeperException.BadVersionException\">the given version does not match the node's version</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task deleteAsync(string path, int version = -1)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            string serverPath;\n\n            // maintain semantics even in chroot case\n            // specifically - root cannot be deleted\n            // I think this makes sense even in chroot case.\n            if (clientPath.Equals(\"/\"))\n            {\n                // a bit of a hack, but delete(/) will never succeed and ensures\n                // that the same semantics are maintained\n                serverPath = clientPath;\n            }\n            else\n            {\n                serverPath = prependChroot(clientPath);\n            }\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.delete);\n            DeleteRequest request = new DeleteRequest();\n            request.setPath(serverPath);\n            request.setVersion(version);\n            ReplyHeader r = await cnxn.submitRequest(h, request, null, null).ConfigureAwait(false);\n            if (r.getErr() != 0)\n            {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n        }\n\n        /// <summary>\n        /// Executes multiple ZooKeeper operations or none of them.\n        /// </summary>\n        /// <param name=\"ops\">A list that contains the operations to be done.\n        /// These should be created using the factory methods on <see cref=\"Op\"/></param>\n        /// <remarks>\n        /// Note: The maximum allowable size of all of the data arrays in all of the setData operations in this single \n        /// request is typically 1 MB (1,048,576 bytes). This limit is specified on the server via\n        /// <a href=\"http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#Unsafe+Options\">jute.maxbuffer</a>.\n        /// Requests larger than this will cause a KeeperException to be thrown.\n        /// @since 3.4.0\n        /// </remarks>\n        /// <returns>A list of results, one for each input Op, the order of\n        /// which exactly matches the order of the <paramref name=\"ops\"/> input\n        /// operations.</returns>\n        /// <exception cref=\"KeeperException\">If the operation could not be completed due to some error in doing one of \n        /// the specified ops.contains partial results and error details, see <see cref=\"KeeperException.getResults()\"/></exception> \n        public Task<List<OpResult>> multiAsync(List<Op> ops) {\n            if (ops == null) throw new ArgumentNullException(\"ops\");\n            List<OpResult> results = validatePath(ops);\n            if (results.size() > 0) {\n                var ex = new KeeperException.BadArgumentsException(ops[0].getPath());\n                ex.setMultiResults(results);\n                throw ex;\n            }\n            return multiInternal(generateMultiTransaction(ops));\n        }\n        private List<OpResult> validatePath(List<Op> ops) {\n            List<OpResult> results = new List<OpResult>();\n            bool error = false;\n            foreach (Op op in ops) {\n                OpResult.ErrorResult err;\n                try {\n                    op.validate();\n                } catch (ArgumentException iae) {\n                    LOG.error(\"ArgumentException: \", iae);\n                    err = new OpResult.ErrorResult(\n                            (int) KeeperException.Code.BADARGUMENTS);\n                    results.Add(err);\n                    error = true;\n                    continue;\n                } catch (KeeperException ke) {\n                    LOG.error(\"KeeperException: \", ke);\n                    err = new OpResult.ErrorResult((int) ke.getCode());\n                    results.Add(err);\n                    error = true;\n                    continue;\n                }\n                err = new OpResult.ErrorResult(\n                        (int) KeeperException.Code.RUNTIMEINCONSISTENCY);\n                results.Add(err);\n            }\n            if (false == error) {\n                results.Clear();\n            }\n            return results;\n        }\n        private MultiTransactionRecord generateMultiTransaction(List<Op> ops) {\n            List<Op> transaction = new List<Op>();\n\n            foreach (Op op in ops) {\n                transaction.Add(withRootPrefix(op));\n            }\n            return new MultiTransactionRecord(transaction);\n        }\n\n        private Op withRootPrefix(Op op) {\n            if (null != op.getPath()) {\n                string serverPath = prependChroot(op.getPath());\n                if (!op.getPath().Equals(serverPath)) {\n                    return op.withChroot(serverPath);\n                }\n            }\n            return op;\n        }\n\n        private async Task<List<OpResult>> multiInternal(MultiTransactionRecord request) {\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int) ZooDefs.OpCode.multi);\n            MultiResponse response = new MultiResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, null).ConfigureAwait(false);\n            if (r.getErr() != 0) {\n                throw KeeperException.create(r.getErr());\n            }\n            List<OpResult> results = response.getResultList();\n\n            OpResult.ErrorResult fatalError = null;\n            foreach (OpResult result in results) {\n                if (result is OpResult.ErrorResult &&\n                    ((OpResult.ErrorResult) result).getErr() != (int) KeeperException.Code.OK) {\n                    fatalError = (OpResult.ErrorResult) result;\n                    break;\n                }\n            }\n            if (fatalError != null) {\n                KeeperException ex = KeeperException.create(fatalError.getErr());\n                ex.setMultiResults(results);\n                throw ex;\n            }\n            return results;\n        }\n        \n        /// <summary>\n        /// A Transaction is a thin wrapper on the <see cref=\"multiAsync\"/> method which provides a builder object \n        /// that can be used to construct and commit an atomic set of operations. @since 3.4.0\n        /// </summary>\n        /// <returns>Transaction builder object</returns>\n        public Transaction transaction() {\n            return new Transaction(this);\n        }\n\n        /// <summary>\n        /// Return the stat of the node of the given path. Return null if no such a\n        /// node exists.\n        /// If the watch is non-null and the call is successful (no exception is thrown),\n        /// a watch will be left on the node with the given path. The watch will be\n        /// triggered by a successful operation that creates/delete the node or sets\n        /// the data on the node.\n        /// </summary>\n        /// <param name=\"path\">the node path</param>\n        /// <param name=\"watcher\">explicit watcher</param>\n        /// <returns>the stat of the node of the given path; return null if no such a node exists.</returns>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task<Stat> existsAsync(string path, Watcher watcher)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            // the watch contains the un-chroot path\n            WatchRegistration wcb = null;\n            if (watcher != null)\n            {\n                wcb = new ExistsWatchRegistration(watchManager, watcher, clientPath);\n            }\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.exists);\n            ExistsRequest request = new ExistsRequest();\n            request.setPath(serverPath);\n            request.setWatch(watcher != null);\n            SetDataResponse response = new SetDataResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, wcb).ConfigureAwait(false);\n\n            if (r.getErr() != 0)\n            {\n                if (r.getErr() == (int)KeeperException.Code.NONODE)\n                {\n                    return null;\n                }\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n\n            return response.getStat().getCzxid() == -1 ? null : response.getStat();\n        }\n\n        /// <summary>\n        /// Return the stat of the node of the given path. Return null if no such a\n        /// node exists.\n        /// If the watch is true and the call is successful (no exception is thrown),\n        /// a watch will be left on the node with the given path. The watch will be\n        /// triggered by a successful operation that creates/delete the node or sets\n        /// the data on the node.\n        /// </summary>\n        /// <param name=\"path\">the node path</param>\n        /// <param name=\"watch\">whether need to watch this node</param>\n        /// <returns>the stat of the node of the given path; return null if no such a node exists.</returns>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public Task<Stat> existsAsync(string path, bool watch = false) {\n            return existsAsync(path, watch ? watchManager.defaultWatcher : null);\n        }\n\n        /// <summary>\n        /// Returns the data and the stat of the node of the given path.\n        /// If the watch is non-null and the call is successful (no exception is\n        /// thrown), a watch will be left on the node with the given path. The watch\n        /// will be triggered by a successful operation that sets data on the node, or\n        /// deletes the node.\n        /// </summary>\n        /// <returns>the data and the stat of the node of the given path</returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task<DataResult> getDataAsync(string path, Watcher watcher)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            // the watch contains the un-chroot path\n            WatchRegistration wcb = null;\n            if (watcher != null)\n            {\n                wcb = new DataWatchRegistration(watchManager, watcher, clientPath);\n            }\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.getData);\n            GetDataRequest request = new GetDataRequest();\n            request.setPath(serverPath);\n            request.setWatch(watcher != null);\n            GetDataResponse response = new GetDataResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, wcb).ConfigureAwait(false);\n            if (r.getErr() != 0)\n            {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n\n            return new DataResult(response.getData(), response.getStat());\n        }\n\n        /// <summary>\n        /// Return the data and the stat of the node of the given path.\n        /// If the watch is true and the call is successful (no exception is\n        /// thrown), a watch will be left on the node with the given path. The watch\n        /// will be triggered by a successful operation that sets data on the node, or\n        /// deletes the node.\n        /// </summary>\n        /// <param name=\"path\">the given path</param>\n        /// <param name=\"watch\">whether need to watch this node</param>\n        /// <returns>\n        /// the data and the stat of the node of the given path\n        /// </returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public Task<DataResult> getDataAsync(string path, bool watch = false) {\n            return getDataAsync(path, watch ? watchManager.defaultWatcher : null);\n        }\n\n        /// <summary>\n        /// Set the data for the node of the given path if such a node exists and the\n        /// given version matches the version of the node (if the given version is\n        /// -1, it matches any node's versions). Return the stat of the node.\n        /// This operation, if successful, will trigger all the watches on the node\n        /// of the given path left by getData calls.\n        /// The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n        /// Arrays larger than this will cause a KeeperExecption to be thrown.\n        /// </summary>\n        /// <param name=\"path\">the path of the node</param>\n        /// <param name=\"data\">the data to set</param>\n        /// <param name=\"version\">the expected matching version</param>\n        /// <returns>the state of the node</returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.BadVersionException\">the given version does not match the node's version</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task<Stat> setDataAsync(string path, byte[] data, int version = -1)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.setData);\n            SetDataRequest request = new SetDataRequest();\n            request.setPath(serverPath);\n            request.setData(data);\n            request.setVersion(version);\n            SetDataResponse response = new SetDataResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, null).ConfigureAwait(false);\n            if (r.getErr() != 0)\n            {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n            return response.getStat();\n        }\n\n        /// <summary>\n        /// Return the ACL and stat of the node of the given path.\n        /// </summary>\n        /// <param name=\"path\">the given path for the node</param>\n        /// <returns>the ACL array of the given node</returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task<ACLResult> getACLAsync(string path)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.getACL);\n            GetACLRequest request = new GetACLRequest();\n            request.setPath(serverPath);\n            GetACLResponse response = new GetACLResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, null).ConfigureAwait(false);\n            if (r.getErr() != 0)\n            {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n            return new ACLResult(response.getAcl(), response.getStat());\n        }\n\n        /// <summary>\n        /// Set the ACL for the node of the given path if such a node exists and the\n        /// given aclVersion matches the acl version of the node. Return the stat of the\n        /// node.\n        /// </summary>\n        /// <param name=\"path\">the given path for the node</param>\n        /// <param name=\"acl\">the given acl for the node</param>\n        /// <param name=\"aclVersion\">the given acl version of the node</param>\n        /// <returns></returns>\n        /// <exception cref=\"KeeperException.BadVersionException\">the given aclVersion does not match the node's aclVersion</exception>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception> \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception> \n        public async Task<Stat> setACLAsync(string path, List<ACL> acl, int aclVersion = -1) {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int) ZooDefs.OpCode.setACL);\n            SetACLRequest request = new SetACLRequest();\n            request.setPath(serverPath);\n            if (acl != null && acl.size() == 0) {\n                throw new KeeperException.InvalidACLException(clientPath);\n            }\n            request.setAcl(acl);\n            request.setVersion(aclVersion);\n            SetACLResponse response = new SetACLResponse();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, null).ConfigureAwait(false);\n            if (r.getErr() != 0) {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n            return response.getStat();\n        }\n\n        /// <summary>\n        /// For the given znode path return the stat and children list.\n        /// If the watch is non-null and the call is successful (no exception is thrown),\n        /// a watch will be left on the node with the given path. The watch will be\n        /// triggered by a successful operation that deletes the node of the given\n        /// path or creates/delete a child under the node.\n        /// The list of children returned is not sorted and no guarantee is provided\n        /// as to its natural or lexical order.\n        /// @since 3.3.0\n        /// </summary>\n        /// <param name=\"path\">path</param>\n        /// <param name=\"watcher\">explicit watcher</param>\n        /// <returns>an unordered children of the node with the given path</returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\" /> is invalid</exception>\n        public async Task<ChildrenResult> getChildrenAsync(string path, Watcher watcher)\n        {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n\n            // the watch contains the un-chroot path\n            WatchRegistration wcb = null;\n            if (watcher != null)\n            {\n                wcb = new ChildWatchRegistration(watchManager, watcher, clientPath);\n            }\n\n            string serverPath = prependChroot(clientPath);\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int)ZooDefs.OpCode.getChildren2);\n            GetChildren2Request request = new GetChildren2Request();\n            request.setPath(serverPath);\n            request.setWatch(watcher != null);\n            GetChildren2Response response = new GetChildren2Response();\n            ReplyHeader r = await cnxn.submitRequest(h, request, response, wcb).ConfigureAwait(false);\n            if (r.getErr() != 0)\n            {\n                throw KeeperException.create(r.getErr(), clientPath);\n            }\n\n            return new ChildrenResult(response.getChildren(), response.getStat());\n        }\n        /// <summary>\n        /// For the given znode path return the stat and children list.\n        /// If the watch is true and the call is successful (no exception is thrown),\n        /// a watch will be left on the node with the given path. The watch will be\n        /// triggered by a successful operation that deletes the node of the given\n        /// path or creates/delete a child under the node.\n        /// The list of children returned is not sorted and no guarantee is provided\n        /// as to its natural or lexical order.\n        /// @since 3.3.0\n        /// </summary>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"watch\">watch</param>\n        /// <returns>an unordered children of the node with the given path</returns>\n        /// <exception cref=\"KeeperException.NoNodeException\">if no node with the given path exists.</exception>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception>\n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\" /> is invalid</exception>\n        public Task<ChildrenResult> getChildrenAsync(string path, bool watch = false) {\n            return getChildrenAsync(path, watch ? watchManager.defaultWatcher : null);\n        }\n\n        /// <summary>\n        /// Asynchronous sync. Flushes channel between process and leader.\n        /// </summary>\n        /// <param name=\"path\">path</param>\n        /// <exception cref=\"KeeperException.ConnectionLossException\">the connection has been lost, you should retry</exception>\n        /// <exception cref=\"KeeperException.SessionExpiredException\">the server says the session has expired, you should create a new client</exception>\n        /// <exception cref=\"KeeperException\">the server signals an error with a non-zero error code</exception>  \n        /// <exception cref=\"ArgumentException\">when <paramref name=\"path\"/> is invalid</exception>\n        public async Task sync(string path) {\n            string clientPath = path;\n            PathUtils.validatePath(clientPath);\n            string serverPath = prependChroot(clientPath);\n            RequestHeader h = new RequestHeader();\n            h.set_Type((int) ZooDefs.OpCode.sync);\n            SyncRequest request = new SyncRequest();\n            SyncResponse response = new SyncResponse();\n            request.setPath(serverPath);\n            await cnxn.queuePacket(h, new ReplyHeader(), request, response, clientPath, serverPath, null).Task.ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Gets the current state of the connection\n        /// </summary>\n        public States getState() {\n            return cnxn.getState();\n        }\n\n        /// <summary>\n        /// string representation of this ZooKeeper client. Suitable for things\n        /// like logging.\n        /// \n        /// Do NOT count on the format of this string, it may change without\n        /// warning.\n        /// \n        /// @since 3.3.0\n        /// </summary>\n        public override string ToString() {\n            States state = getState();\n            return (\"State:\" + state + (cnxn.getState().isConnected() ? \" Timeout:\" + getSessionTimeout() + \" \" : \" \") + cnxn);\n        }\n        /// <summary>\n        /// Should ZooKeeper log be written to a file named <see cref=\"LogFileName\"/>\n        /// </summary>\n        public static bool LogToFile\n        {\n            get { return ZooKeeperLogger.Instance.LogToFile; }\n            set { ZooKeeperLogger.Instance.LogToFile = value; }\n        }\n        /// <summary>\n        /// Should ZooKeeper log be written to trace.\n        /// The log level is controlled by <see cref=\"LogLevel\"/>\n        /// </summary>\n        public static bool LogToTrace\n        {\n            get { return ZooKeeperLogger.Instance.LogToTrace; }\n            set { ZooKeeperLogger.Instance.LogToTrace = value; }\n        }\n\n        /// <summary>\n        /// The file name of the log used when <see cref=\"LogToFile\"/> is true.\n        /// The log level is controlled by <see cref=\"LogLevel\"/>\n        /// </summary>\n        public static string LogFileName\n        {\n            get { return ZooKeeperLogger.Instance.LogFileName; }\n        }\n\n        /// <summary>\n        /// The minimum log level that should be written to the output. The output can be set via the\n        /// <see cref=\"LogToTrace\"/>, <see cref=\"LogToFile\"/> and <see cref=\"CustomLogConsumer\"/>\n        /// </summary>\n        public static TraceLevel LogLevel\n        {\n            get { return ZooKeeperLogger.Instance.LogLevel; }\n            set { ZooKeeperLogger.Instance.LogLevel = value; }\n        }\n\n        /// <summary>\n        /// This is for providing an external logger. \n        /// The log level is controlled by <see cref=\"LogLevel\"/>\n        /// </summary>\n        public static ILogConsumer CustomLogConsumer\n        {\n            get { return ZooKeeperLogger.Instance.CustomLogConsumer; }\n            set { ZooKeeperLogger.Instance.CustomLogConsumer = value; }\n        }\n\n        #region Using        \n        /// <summary>\n        /// Creates a ZK with <see cref=\"ZooKeeper(string,int,Watcher,long,byte[],bool)\"/> and pass it to <paramref name=\"zkMethod\"/>\n        /// </summary>\n        public static Task Using(string connectstring, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd,\n           Func<ZooKeeper, Task> zkMethod, bool canBeReadOnly = false)\n        {\n            return Using(new ZooKeeper(connectstring, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly), zkMethod);\n        }\n\n        /// <summary>\n        /// Creates a ZK with <see cref=\"ZooKeeper(string,int,Watcher,long,byte[],bool)\"/> and pass it to <paramref name=\"zkMethod\"/>\n        /// </summary>\n        public static Task<T> Using<T>(string connectstring, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd,\n            Func<ZooKeeper, Task<T>> zkMethod, bool canBeReadOnly = false)\n        {\n            return Using(new ZooKeeper(connectstring, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly), zkMethod);\n        }\n\n        /// <summary>\n        /// Creates a ZK with <see cref=\"ZooKeeper(string,int,Watcher,bool)\"/> and pass it to <paramref name=\"zkMethod\"/>\n        /// </summary>\n        public static Task Using(string connectstring, int sessionTimeout, Watcher watcher,\n           Func<ZooKeeper, Task> zkMethod, bool canBeReadOnly = false)\n        {\n            return Using(new ZooKeeper(connectstring, sessionTimeout, watcher, canBeReadOnly), zkMethod);\n        }\n\n        /// <summary>\n        /// Creates a ZK with <see cref=\"ZooKeeper(string,int,Watcher,bool)\"/> and pass it to <paramref name=\"zkMethod\"/>\n        /// </summary>\n        public static Task<T> Using<T>(string connectstring, int sessionTimeout, Watcher watcher,\n            Func<ZooKeeper, Task<T>> zkMethod, bool canBeReadOnly = false)\n        {\n            return Using(new ZooKeeper(connectstring, sessionTimeout, watcher, canBeReadOnly), zkMethod);\n        }\n\n        private static Task Using(ZooKeeper zooKeeper, Func<ZooKeeper, Task> zkMethod) {\n            return Using(zooKeeper,\n                async zk =>\n                {\n                    await zkMethod(zk).ConfigureAwait(false);\n                    return 0;\n                });\n        }\n\n        private static async Task<T> Using<T>(ZooKeeper zk, Func<ZooKeeper, Task<T>> zkMethod) {\n\n            return await (await TryOperation(zk,zkMethod).ContinueWith(async zkTask =>\n            {\n                await zk.closeAsync().ConfigureAwait(false);\n                return await zkTask.ConfigureAwait(false);\n            }).ConfigureAwait(false)).ConfigureAwait(false);\n        }\n\n        private static async Task<T> TryOperation<T>(ZooKeeper zk, Func<ZooKeeper, Task<T>> zkMethod) \n        {\n            Task<T> zkMethodTask;\n            Task timeoutTask = null;\n            do {\n                zkMethodTask = zkMethod(zk);\n                try {\n                    return await zkMethodTask.ConfigureAwait(false);\n                }\n                catch (KeeperException.ConnectionLossException) {\n                }\n                if (timeoutTask == null)\n                    timeoutTask = Task.Delay(zk.userDefinedSessionTimeout);\n\n                await Task.WhenAny(zk.connectedSignal.Task, timeoutTask).ConfigureAwait(false);\n            } while (!timeoutTask.IsCompleted);\n            return await zkMethodTask.ConfigureAwait(false);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/ConnectStringParser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing org.apache.zookeeper.common;\n\nnamespace org.apache.zookeeper.client\n{\n    /// <summary>\n\t/// A parser for ZooKeeper Client connect strings.\n\t/// \n\t/// This class is not meant to be seen or used outside of ZooKeeper itself.\n\t/// \n\t/// The chrootPath member should be replaced by a Path object in issue\n\t/// ZOOKEEPER-849.\n\t/// </summary>\n    internal sealed class ConnectStringParser\n\t{\n\t\tprivate const int DEFAULT_PORT = 2181;\n\n\t\tprivate readonly string chrootPath;\n\n        private readonly List<HostAndPort> serverAddresses = new List<HostAndPort>();\n\n        private static readonly char[] splitter = {','};\n\n\t\tpublic ConnectStringParser(string connectString)\n\t\t{\n\t\t\t// parse out chroot, if any\n\t\t\tint off = connectString.IndexOf('/');\n\t\t\tif (off >= 0)\n\t\t\t{\n\t\t\t\tstring chPath = connectString.Substring(off);\n\t\t\t\t// ignore \"/\" chroot spec, same as null\n\t\t\t\tif (chPath.Length == 1)\n\t\t\t\t{\n\t\t\t\t\tchrootPath = null;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tPathUtils.validatePath(chPath);\n\t\t\t\t\tchrootPath = chPath;\n\t\t\t\t}\n\t\t\t\tconnectString = connectString.Substring(0, off);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tchrootPath = null;\n\t\t\t}\n\n\t\t    string[] hostsList = connectString.Split(splitter, StringSplitOptions.RemoveEmptyEntries);\n\t\t\tforeach (string host in hostsList)\n\t\t\t{\n\t\t\t\tint port = DEFAULT_PORT;\n\t\t\t\tint pidx = host.LastIndexOf(':');\n\t\t\t    string parsedHost = host;\n\t\t\t\tif (pidx >= 0)\n\t\t\t\t{\n\t\t\t\t\t// otherwise : is at the end of the string, ignore\n\t\t\t\t\tif (pidx < host.Length - 1) \n                    {\n\t\t\t\t\t    port = int.Parse(host.Substring(pidx + 1));\n\t\t\t\t\t}\n                    parsedHost = host.Substring(0, pidx);\n\t\t\t\t}\n\t\t\t    serverAddresses.Add(new HostAndPort(parsedHost, port));\n\t\t\t}\n\t\t}\n\n        public string getChrootPath()\n        {\n            return chrootPath;\n        }\n\n        public List<HostAndPort> getServerAddresses()\n        {\n                return serverAddresses.Distinct().ToList();\n        }\n\t}\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/DnsResolver.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing org.apache.utils;\n// ReSharper disable PossibleMultipleEnumeration\n\nnamespace org.apache.zookeeper.client\n{\n    internal class DnsResolver : IDnsResolver\n    {\n        private const int DNS_TIMEOUT = 10000;\n        private readonly ILogProducer log;\n\n        public DnsResolver(ILogProducer log)\n        {\n            this.log = log;\n        }\n\n        private static void IgnoreTask(Task task)\n        {\n            if (task.IsCompleted)\n            {\n                var ignored = task.Exception;\n            }\n            else\n            {\n                task.ContinueWith(\n                    t => { var ignored = t.Exception; },\n                    CancellationToken.None,\n                    TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously,\n                    TaskScheduler.Default);\n            }\n        }\n\n        private async Task<IEnumerable<ResolvedEndPoint>> Resolve(HostAndPort hostAndPort)\n        {\n            string host = hostAndPort.Host;\n            log.debug($\"Resolving Host={host}\");\n            var dnsTimeoutTask = Task.Delay(DNS_TIMEOUT);\n            var dnsResolvingTask = Dns.GetHostAddressesAsync(host);\n            await Task.WhenAny(dnsResolvingTask, dnsTimeoutTask).ConfigureAwait(false);\n            if (dnsTimeoutTask.IsCompleted)\n            {\n                \n                IgnoreTask(dnsResolvingTask);\n                log.warn($\"Timeout of {DNS_TIMEOUT}ms elapsed when resolving Host={host}\");\n            }\n            else\n            {\n                try\n                {\n                    var allResolvedIPs = await dnsResolvingTask.ConfigureAwait(false);\n                    log.debug($\"Resolved Host={host} to {{{allResolvedIPs.ToCommaDelimited()}}}\");\n                    return allResolvedIPs.Select(ip => new ResolvedEndPoint(ip, hostAndPort));\n                }\n                catch (Exception e)\n                {\n                    log.error($\"Failed resolving Host={host}\", e);\n                }\n            }\n            return Enumerable.Empty<ResolvedEndPoint>();\n        }\n\n        public async Task<IEnumerable<ResolvedEndPoint>> Resolve(IEnumerable<HostAndPort> unresolvedHosts)\n        {\n            var unresolvedForLog = unresolvedHosts.ToCommaDelimited();\n            log.debug($\"Resolving Hosts={{{unresolvedForLog}}}\");\n            var resolved = new List<ResolvedEndPoint>();\n            var resolvingTasks = new List<Task<IEnumerable<ResolvedEndPoint>>>();\n            foreach (var hostAndPort in unresolvedHosts)\n            {\n                IPAddress ip;\n                if (IPAddress.TryParse(hostAndPort.Host, out ip))\n                {\n                    resolved.Add(new ResolvedEndPoint(ip, hostAndPort.Port));\n                }\n                else\n                {\n                    resolvingTasks.Add(Resolve(hostAndPort));\n                }\n            }\n            var resolvedTasks = (await Task.WhenAll(resolvingTasks).ConfigureAwait(false)).SelectMany(i => i);\n            resolved.AddRange(resolvedTasks);\n            var res = resolved.Distinct();\n            log.debug($\"Resolved Hosts={{{unresolvedForLog}}} to {{{res.ToCommaDelimited()}}}\");\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/DynamicHostProvider.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\nusing org.apache.utils;\n\n// ReSharper disable PossibleMultipleEnumeration\nnamespace org.apache.zookeeper.client\n{\n    /// <summary>\n    /// This HostProvider resolves its hosts on first call to next(). Then, after \n    /// returning all resolved IPs, it resolves again.\n    /// </summary>\n    internal sealed class DynamicHostProvider : HostProvider\n\t{\n        private readonly List<HostAndPort> m_UnresolvedEndPoints;\n\n        private List<ResolvedEndPoint> m_ResolvedEndPoints;\n\n        internal ResolvedEndPoint LastIP { get; private set; }\n\n        internal int CurrentIndex { get; private set; } = -1;\n\n        internal bool ResolvingInBackground => m_ResolvingTask != null && !m_ResolvingTask.IsCompleted;\n\n        internal bool FirstDnsTry { get; private set; } = true;\n\n        private Task<List<ResolvedEndPoint>> m_ResolvingTask;\n\n\t    private readonly ILogProducer m_Log;\n\n\t    private readonly IDnsResolver m_DnsResolver;\n\n        public DynamicHostProvider(List<HostAndPort> serverAddresses, IDnsResolver dnsResolver = null,\n            ILogProducer log = null)\n        {\n            if (serverAddresses.Count == 0)\n            {\n                throw new ArgumentException(\"A HostProvider may not be empty!\");\n            }\n            m_Log = log ?? new TypeLogger<DynamicHostProvider>();\n            m_DnsResolver = dnsResolver ?? new DnsResolver(m_Log);\n            m_UnresolvedEndPoints = serverAddresses;\n        }\n\n        public int size()\n\t\t{\n\t\t\treturn m_ResolvedEndPoints.Count;\n\t\t}\n\n\t    public async Task<ResolvedEndPoint> next(int spinDelay)\n\t    {\n\t        ResolvedEndPoint nextEndPoint;\n\t        if (m_ResolvedEndPoints == null)\n\t        {\n\t            m_ResolvedEndPoints = await ResolveAtLeastOneAndShuffle(m_UnresolvedEndPoints, spinDelay).ConfigureAwait(false);\n\t            nextEndPoint = m_ResolvedEndPoints[0];\n\t        }\n\t        else\n\t        {\n\t            ++CurrentIndex;\n\t            if (CurrentIndex == m_ResolvedEndPoints.Count)\n\t            {\n\t                CurrentIndex = 0;\n\t            }\n\t            if (m_ResolvingTask != null && m_ResolvingTask.IsCompleted)\n\t            {\n\t                var resolved = await m_ResolvingTask.ConfigureAwait(false);\n\t                m_ResolvingTask = null;\n\t                if (resolved.Count > 0)\n\t                {\n                        if (resolved.Contains(LastIP))\n\t                    {\n\t                        resolved.Remove(LastIP);\n\t                        resolved.Add(LastIP);\n\t                    }\n\t                    else\n\t                    {\n\t                        LastIP = null;\n\t                    }\n                        CurrentIndex = 0;\n                        m_ResolvedEndPoints = resolved;\n\t                }\n\t                else\n\t                {\n\t                    m_Log.debug(\"Keeping the current resolved IPs since background resolution failed\");\n\t                }\n\t            }\n\t            nextEndPoint = m_ResolvedEndPoints[CurrentIndex];\n\t            if (nextEndPoint == LastIP && spinDelay > 0)\n\t            {\n\t                if (m_ResolvingTask == null)\n\t                {\n\t                    m_ResolvingTask = ResolveAndShuffle(m_UnresolvedEndPoints);\n\t                }\n                    await Task.Delay(spinDelay).ConfigureAwait(false);\n\t            }\n\t            else if (LastIP == null)\n\t            {\n\t                LastIP = m_ResolvedEndPoints[0];\n\t            }\n\t        }\n\t        return nextEndPoint;\n\t    }\n\n\t    public void onConnected()\n\t\t{\n\t\t    LastIP = m_ResolvedEndPoints[CurrentIndex];\n\t\t}\n\n\t    private async Task<List<ResolvedEndPoint>> ResolveAtLeastOneAndShuffle(IEnumerable<HostAndPort> unresolvedEndPoints, int spinDelay)\n        {\n            var unresolvedForLog = unresolvedEndPoints.ToCommaDelimited();\n\t        if (FirstDnsTry)\n\t        {\n\t            FirstDnsTry = false;\n\t        }\n\t        else\n\t        {\n\t            m_Log.debug(\"Since we couldn't resolve any IPs yet, we sleep for a second before retying\");\n\t            await Task.Delay(spinDelay).ConfigureAwait(false);\n\t        }\n\t        m_Log.debug($\"Trying to resolve at least one IP from hosts:{{{unresolvedForLog}}}\");\n            var resolved = await ResolveAndShuffle(unresolvedEndPoints).ConfigureAwait(false);\n            if (!resolved.Any())\n            {\n                m_Log.debug($\"Failed to resolve any IP from hosts:{{{unresolvedForLog}}}\");\n                throw new SocketException((int) SocketError.HostUnreachable);\n            }\n            return resolved;\n        }\n\n\t    private async Task<List<ResolvedEndPoint>> ResolveAndShuffle(IEnumerable<HostAndPort> unresolvedEndPoints)\n        {\n            var resolvedEndPoints = await m_DnsResolver.Resolve(unresolvedEndPoints).ConfigureAwait(false);\n            return resolvedEndPoints.OrderBy(i => Guid.NewGuid()).ToList();\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/HostAndPort.cs",
    "content": "using System;\n\nnamespace org.apache.zookeeper.client\n{\n    internal class HostAndPort : IEquatable<HostAndPort>\n    {\n        public readonly string Host;\n        public readonly int Port;\n\n        public HostAndPort(string host, int port)\n        {\n            Host = host;\n            Port = port;\n        }\n\n        public override string ToString()\n        {\n            return $\"{Host}:{Port}\";\n        }\n\n        public bool Equals(HostAndPort other)\n        {\n            if (ReferenceEquals(null, other)) return false;\n            if (ReferenceEquals(this, other)) return true;\n            return string.Equals(Host, other.Host) && Port == other.Port;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            if (ReferenceEquals(this, obj)) return true;\n            return obj.GetType() == GetType() && Equals((HostAndPort) obj);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                return (Host.GetHashCode()*397) ^ Port;\n            }\n        }\n\n        public static bool operator ==(HostAndPort left, HostAndPort right)\n        {\n            return Equals(left, right);\n        }\n\n        public static bool operator !=(HostAndPort left, HostAndPort right)\n        {\n            return !Equals(left, right);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/HostProvider.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace org.apache.zookeeper.client\n{\n\n\t/// <summary>\n\t/// A set of hosts a ZooKeeper client should connect to.\n\t/// \n\t/// Classes implementing this interface must guarantee the following:\n\t/// \n    /// * Every call to next() returns an IPEndPoint. So the iterator never\n\t/// ends.\n\t/// \n\t/// * The size() of a HostProvider may never be zero.\n\t/// \n    /// A HostProvider must return resolved IPEndPoint instances on next(),\n\t/// but it's up to the HostProvider, when it wants to do the resolving.\n\t/// \n\t/// Different HostProvider could be imagined:\n\t/// \n\t/// * A HostProvider that loads the list of Hosts from an URL or from DNS \n    /// * A HostProvider that re-resolves the IPEndPoint after a timeout. \n\t/// * A HostProvider that prefers nearby hosts.\n\t/// </summary>\n\tinternal interface HostProvider\n\t{\n\t\tint size();\n\n\t    /// <summary>\n\t    /// The next host to try to connect to.\n\t    /// \n\t    /// For a spinDelay of 0 there should be no wait.\n\t    /// </summary>\n\t    /// <param name=\"spinDelay\">\n\t    ///     Milliseconds to wait if all hosts have been tried once. </param>\n\t    Task<ResolvedEndPoint> next(int spinDelay);\n\n\t\t/// <summary>\n\t\t/// Notify the HostProvider of a successful connection.\n\t\t/// \n\t\t/// The HostProvider may use this notification to reset it's inner state.\n\t\t/// </summary>\n\t\tvoid onConnected();\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/IDnsResolver.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace org.apache.zookeeper.client\n{\n    internal interface IDnsResolver\n    {\n        Task<IEnumerable<ResolvedEndPoint>> Resolve(IEnumerable<HostAndPort> unresolvedHosts);\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/client/ResolvedEndPoint.cs",
    "content": "﻿using System;\nusing System.Net;\n\nnamespace org.apache.zookeeper.client\n{\n    internal class ResolvedEndPoint : IPEndPoint, IEquatable<ResolvedEndPoint>\n    {\n        private readonly string host;\n\n        public ResolvedEndPoint(IPAddress ip, HostAndPort hostAndPort) : this(ip, hostAndPort.Port)\n        {\n            host = hostAndPort.Host;\n        }\n\n        public ResolvedEndPoint(IPAddress ip, int port) : base(ip, port)\n        {\n        }\n\n        public override string ToString()\n        {\n            return $\"{{{(host == null ? null : $\"{host}=>\")}{base.ToString()}}}\";\n        }\n\n        public bool Equals(ResolvedEndPoint other)\n        {\n            return base.Equals(other);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            if (ReferenceEquals(this, obj)) return true;\n            return obj.GetType() == GetType() && Equals((ResolvedEndPoint) obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n\n        public static bool operator ==(ResolvedEndPoint left, ResolvedEndPoint right)\n        {\n            return Equals(left, right);\n        }\n\n        public static bool operator !=(ResolvedEndPoint left, ResolvedEndPoint right)\n        {\n            return !Equals(left, right);\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx/zookeeper/common/PathUtils.cs",
    "content": "using System;\n\nnamespace org.apache.zookeeper.common\n{\n\t/// <summary>\n\t/// Path related utilities\n\t/// </summary>\n\tpublic static class PathUtils\n\t{\n\n\t\t/// <summary>\n\t\t/// validate the provided znode path string </summary>\n\t\t/// <param name=\"path\"> znode path string </param>\n\t\t/// <param name=\"isSequential\"> if the path is being created\n\t\t/// with a sequential flag </param>\n        /// <exception cref=\"ArgumentException\"> if the path is invalid </exception>\n\t\tpublic static void validatePath(string path, bool isSequential)\n\t\t{\n\t\t\tvalidatePath(isSequential? path + \"1\": path);\n\t\t}\n\n        /// <summary>\n        /// Validate the provided znode path string </summary>\n        /// <param name=\"path\"> znode path string </param>\n        /// <exception cref=\"ArgumentException\"> if the path is invalid </exception>\n        public static void validatePath(string path)\n\t\t{\n\t\t\tif (path == null) \n            {\n\t\t\t    throw new ArgumentException(\"Path cannot be null\", \"path\");\n\t\t\t}\n\t\t\tif (path.Length == 0)\n\t\t\t{\n                throw new ArgumentException(\"Path length must be > 0\", \"path\");\n\t\t\t}\n\t\t\tif (path[0] != '/')\n\t\t\t{\n                throw new ArgumentException(\"Path must start with / character\", \"path\");\n\t\t\t}\n\t\t\tif (path.Length == 1)\n\t\t\t{ // done checking - it's the root\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (path[path.Length - 1] == '/')\n\t\t\t{\n                throw new ArgumentException(\"Path must not end with / character\", \"path\");\n\t\t\t}\n\n\t\t\tstring reason = null;\n\t\t\tchar lastc = '/';\n\t\t\tchar[] chars = path.ToCharArray();\n\t\t\tchar c;\n\t\t\tfor (int i = 1; i < chars.Length; lastc = chars[i], i++)\n\t\t\t{\n\t\t\t\tc = chars[i];\n\n\t\t\t\tif (c == 0)\n\t\t\t\t{\n\t\t\t\t\treason = \"null character not allowed @\" + i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t    if (c == '/' && lastc == '/')\n\t\t\t    {\n\t\t\t        reason = \"empty node name specified @\" + i;\n\t\t\t        break;\n\t\t\t    }\n\t\t\t    if (c == '.' && lastc == '.')\n\t\t\t    {\n\t\t\t        if (chars[i - 2] == '/' && ((i + 1 == chars.Length) || chars[i + 1] == '/'))\n\t\t\t        {\n\t\t\t            reason = \"relative paths not allowed @\" + i;\n\t\t\t            break;\n\t\t\t        }\n\t\t\t    }\n\t\t\t    else if (c == '.')\n\t\t\t    {\n\t\t\t        if (chars[i - 1] == '/' && ((i + 1 == chars.Length) || chars[i + 1] == '/'))\n\t\t\t        {\n\t\t\t            reason = \"relative paths not allowed @\" + i;\n\t\t\t            break;\n\t\t\t        }\n\t\t\t    }\n\t\t\t    else if (c <= '\\u001f' || c >= '\\u007f' && c <= '\\u009F' || c >= '\\ud800' && c <= '\\uf8ff' || c >= '\\ufff0')\n\t\t\t    {\n\t\t\t        reason = \"invalid character @\" + i;\n\t\t\t        break;\n\t\t\t    }\n\t\t\t}\n\n\t\t\tif (reason != null)\n\t\t\t{\n                throw new ArgumentException(\"Invalid path string \\\"\" + path + \"\\\" caused by \" + reason, \"path\");\n\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/AsyncLock.cs",
    "content": "namespace System.Threading.Tasks\n{\n    //http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx\n    //http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx\n    internal sealed class AsyncLock\n    {\n        private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);\n        private readonly Task<IDisposable> m_releaser;\n\n        public AsyncLock()\n        {\n            m_releaser = Task.FromResult((IDisposable)new Releaser(this));\n        }\n\n        public Task<IDisposable> LockAsync()\n        {\n            var wait = m_semaphore.WaitAsync();\n            return wait.IsCompleted ?\n                        m_releaser : wait.ContinueWith(\n                        (_, state) => (IDisposable)state,\n                               m_releaser.Result\n                        ,CancellationToken.None, \n                        TaskContinuationOptions.ExecuteSynchronously, \n                        TaskScheduler.Default);\n        }\n\n        private sealed class Releaser : IDisposable\n        {\n            private readonly AsyncLock m_toRelease;\n            internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }\n            public void Dispose() { m_toRelease.m_semaphore.Release(); }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Lock/LockListener.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// This class has two methods which are call\n\t/// back methods when a lock is acquired and \n\t/// when the lock is released.\n\t/// \n\t/// </summary>\n\tpublic interface LockListener\n\t{\n\t\t/// <summary>\n\t\t/// call back called when the lock \n\t\t/// is acquired\n\t\t/// </summary>\n\t\tTask lockAcquired();\n\n\t\t/// <summary>\n\t\t/// call back called when the lock is \n\t\t/// released.\n\t\t/// </summary>\n\t\tTask lockReleased();\n\t}\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Lock/ProtocolSupport.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nusing org.apache.utils;\nusing org.apache.zookeeper.data;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n    /// <summary>\n    /// A base class for protocol implementations which provides a number of higher \n    /// level helper methods for working with ZooKeeper along with retrying synchronous\n    ///  operations if the connection to ZooKeeper closes such as \n    ///  <seealso cref=\"retryOperation(ZooKeeperOperation)\"/>\n    /// \n    /// </summary>\n    public class ProtocolSupport \n    {\n        private static readonly ILogProducer LOG = TypeLogger<ProtocolSupport>.Instance;\n\n        internal readonly ZooKeeper zookeeper;\n        private const int retryDelayInMs = 500;\n        private const int retryCount = 10;\n        internal List<ACL> m_acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;\n\n        internal  ProtocolSupport(ZooKeeper zookeeper) \n        {\n            this.zookeeper = zookeeper;\n        }\n\n        /// <summary>\n        /// return zookeeper client instance </summary>\n        /// <returns> zookeeper client instance </returns>\n        public ZooKeeper getZookeeper() {\n            return zookeeper;\n        }\n\n        /// <summary>\n        /// return the acl its using </summary>\n        /// <returns> the acl. </returns>\n        public List<ACL> Acl \n        {\n            get \n            {\n                return m_acl;\n            }\n        }\n        /// <summary>\n        /// Perform the given operation, retrying if the connection fails </summary>\n        /// <returns> object. it needs to be cast to the callee's expected \n        /// return type. </returns>\n        protected async Task<bool> retryOperation(ZooKeeperOperation operation) \n        {\n            KeeperException exception = null;\n            for (int i = 0; i < retryCount; i++) \n            {\n                try \n                {\n                    return await operation.execute().ConfigureAwait(false);\n                }\n                catch (KeeperException.SessionExpiredException e) \n                {\n                    LOG.warn(\"Session expired for: \" + zookeeper + \" so reconnecting due to: \" + e, e);\n                    throw;\n                }\n                catch (KeeperException.ConnectionLossException e) \n                {\n                    if (exception == null) \n                    {\n                        exception = e;\n                    }\n                    LOG.debug(\"Attempt \" + i + \" failed with connection loss so \" + \"attempting to reconnect: \" + e, e);\n                }\n                await retryDelay(i).ConfigureAwait(false);\n            }\n            throw exception;\n        }\n\n        /// <summary>\n        /// Ensures that the given path exists with no data, the current\n        /// ACL and no flags </summary>\n        /// <param name=\"path\"> </param>\n        protected Task ensurePathExists(string path) \n        {\n            return ensureExists(path, null, m_acl, CreateMode.PERSISTENT);\n        }\n\n        /// <summary>\n        /// Ensures that the given path exists with the given data, ACL and flags </summary>\n        /// <param name=\"path\"> </param>\n        /// <param name=\"data\"></param>\n        /// <param name=\"acl\"> </param>\n        /// <param name=\"flags\"> </param>\n        private async Task ensureExists(string path, byte[] data, List<ACL> acl, CreateMode flags) {\n            try \n\t\t\t{\n                await retryOperation(new EnsureExists(zookeeper, path, data, acl, flags)).ConfigureAwait(false);\n            }\n            catch (KeeperException e) \n            {\n                LOG.warn(\"Caught: \" + e, e);\n            }\n        }\n\n        private sealed class EnsureExists : ZooKeeperOperation\n        {\n            private readonly ZooKeeper zookeeper;\n\n            private readonly string path;\n            private readonly byte[] data;\n            private readonly List<ACL> acl;\n            private readonly CreateMode flags;\n\n            public EnsureExists(ZooKeeper zookeeper, string path, byte[] data, List<ACL> acl, CreateMode flags) \n            {\n                this.zookeeper = zookeeper;\n                this.path = path;\n                this.data = data;\n                this.acl = acl;\n                this.flags = flags;\n            }\n\n            public async Task<bool> execute() \n            {\n                Stat stat = await zookeeper.existsAsync(path).ConfigureAwait(false);\n                if (stat != null) \n                {\n                    return true;\n                }\n                await zookeeper.createAsync(path, data, acl, flags).ConfigureAwait(false);\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Performs a retry delay if this is not the first attempt </summary>\n        /// <param name=\"attemptCount\"> the number of the attempts performed so far </param>\n        private static async Task retryDelay(int attemptCount) \n        {\n            if (attemptCount > 0) \n            {\n                await Task.Delay(attemptCount*retryDelayInMs).ConfigureAwait(false);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Lock/WriteLock.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\nusing org.apache.utils;\nusing ZooKeeperNetEx.utils;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// A <a href=\"package.html\">protocol to implement an exclusive\n\t///  write lock or to elect a leader</a>. <p/> You invoke <seealso cref=\"Lock()\"/> to \n\t///  start the process of grabbing the lock; you may get the lock then or it may be \n\t///  some time later. <p/> You can register a listener so that you are invoked \n\t///  when you get the lock; otherwise you can ask if you have the lock\n\t///  by calling <seealso cref=\"Owner\"/>\n\t/// \n\t/// </summary>\n\tpublic sealed class WriteLock : ProtocolSupport\n\t{\n\t\tprivate static readonly ILogProducer LOG = TypeLogger<WriteLock>.Instance;\n\n\t    private readonly AsyncLock lockable = new AsyncLock();\n\n\t\tprivate readonly string dir;\n\t    private ZNodeName idName;\n\t\tprivate string ownerId;\n\t\tprivate string lastChildId;\n\t\tprivate readonly byte[] data = {0x12, 0x34};\n\t    private readonly VolatileReference<LockListener> callback = new VolatileReference<LockListener>(null);\n\t\tprivate readonly LockZooKeeperOperation zop;\n\n\t\t/// <summary>\n\t\t/// zookeeper contructor for writelock </summary>\n\t\t/// <param name=\"zookeeper\"> zookeeper client instance </param>\n\t\t/// <param name=\"dir\"> the parent path you want to use for locking </param>\n\t\t/// <param name=\"acls\"> the acls that you want to use for all the paths, \n\t\t/// if null world read/write is used. </param>\n\t\tpublic WriteLock(ZooKeeper zookeeper, string dir, List<ACL> acls) : base(zookeeper)\n\t\t{\n\t\t\tthis.dir = dir;\n\t\t\tif (acls != null)\n\t\t\t{\n\t\t\t\tm_acl = acls;\n\t\t\t}\n\t\t\tzop = new LockZooKeeperOperation(this);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// zookeeper contructor for writelock with callback </summary>\n\t\t/// <param name=\"zookeeper\"> the zookeeper client instance </param>\n\t\t/// <param name=\"dir\"> the parent path you want to use for locking </param>\n\t\t/// <param name=\"acl\"> the acls that you want to use for all the paths </param>\n\t\t/// <param name=\"callback\"> the call back instance </param>\n\t\tpublic WriteLock(ZooKeeper zookeeper, string dir, List<ACL> acl, LockListener callback) : this(zookeeper, dir, acl)\n\t\t{\n\t\t    setLockListener(callback);\n\t\t}\n\n\t    /// <summary>\n\t    /// return the current locklistener </summary>\n\t    /// <returns> the locklistener </returns>\n\t    public void setLockListener(LockListener lockListener) {\n\t            callback.Value = lockListener;\n\t    }\n\n\n\t    /// <summary>\n\t\t/// Removes the lock or associated znode if \n\t\t/// you no longer require the lock. this also \n\t\t/// removes your request in the queue for locking\n\t\t/// in case you do not already hold the lock. </summary>\n\t\tpublic async Task unlock()\n\t\t{\n\t\t\tusing(await lockable.LockAsync().ConfigureAwait(false))\n\t\t\t{\n\t\t\t\tif (Id != null)\n\t\t\t\t{\n\t\t\t\t\t// we don't need to retry this operation in the case of failure\n\t\t\t\t\t// as ZK will remove ephemeral files and we don't wanna hang\n\t\t\t\t\t// this process when closing if we cannot reconnect to ZK\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tZooKeeperOperation zopdel = new DeleteNode(this);\n\t\t\t\t\t\tawait zopdel.execute().ConfigureAwait(false);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t\t{\n\t\t\t\t\t\t// do nothing\n\t\t\t\t\t}\n\t\t\t\t\tcatch (KeeperException e)\n\t\t\t\t\t{\n\t\t\t\t\t\tLOG.warn(\"Caught: \" + e, e);\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t\tfinally\n\t\t\t\t\t{\n\t\t\t\t\t    var tempCallback = callback.Value;\n\t\t\t\t\t\tif (tempCallback != null)\n\t\t\t\t\t\t{\n                            await tempCallback.lockReleased().ConfigureAwait(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tId = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate sealed class DeleteNode : ZooKeeperOperation\n\t\t{\n\t\t\tprivate readonly WriteLock writeLock;\n\n\t\t\tpublic DeleteNode(WriteLock writeLock)\n\t\t\t{\n\t\t\t\tthis.writeLock = writeLock;\n\t\t\t}\n\n\t\t\tpublic async Task<bool> execute()\n\t\t\t{\n\t\t\t\tawait writeLock.zookeeper.deleteAsync(writeLock.Id).ConfigureAwait(false);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// the watcher called on  \n\t\t/// getting watch while watching \n\t\t/// my predecessor\n\t\t/// </summary>\n\t\tprivate class LockWatcher : Watcher\n\t\t{\n\t\t\tprivate readonly WriteLock outerInstance;\n\n\t\t\tpublic LockWatcher(WriteLock outerInstance)\n\t\t\t{\n\t\t\t\tthis.outerInstance = outerInstance;\n\t\t\t}\n\n\t\t\tpublic override async Task process(WatchedEvent @event)\n\t\t\t{\n\t\t\t\t// lets either become the leader or watch the new/updated node\n\t\t\t\tLOG.debug(\"Watcher fired on path: \" + @event.getPath() + \" state: \" + @event.getState() + \" type \" + @event.get_Type());\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait outerInstance.Lock().ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\tcatch (Exception e)\n\t\t\t\t{\n\t\t\t\t\tLOG.warn(\"Failed to acquire lock: \" + e, e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// a zoookeeper operation that is mainly responsible\n\t\t/// for all the magic required for locking.\n\t\t/// </summary>\n\t\tprivate sealed class LockZooKeeperOperation : ZooKeeperOperation\n\t\t{\n\t\t\tprivate readonly WriteLock writeLock;\n\n\t\t\tpublic LockZooKeeperOperation(WriteLock writeLock)\n\t\t\t{\n\t\t\t\tthis.writeLock = writeLock;\n\t\t\t}\n\n\n\t\t\t/// <summary>\n\t\t\t/// find if we have been created earler if not create our node\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"prefix\"> the prefix node </param>\n\t\t\t/// <param name=\"zookeeper\"> teh zookeeper client </param>\n\t\t\t/// <param name=\"dir\"> the dir paretn </param>\n\t\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\t\tprivate async Task findPrefixInChildren(string prefix, ZooKeeper zookeeper, string dir)\n\t\t\t{\n\t\t\t\tIList<string> names = (await zookeeper.getChildrenAsync(dir).ConfigureAwait(false)).Children;\n\t\t\t\tforeach (string name in names)\n\t\t\t\t{\n\t\t\t\t\tif (name.StartsWith(prefix, StringComparison.Ordinal))\n\t\t\t\t\t{\n                        writeLock.Id = name;\n\t\t\t\t\t\tif (LOG.isDebugEnabled())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLOG.debug(\"Found id created last time: \" + writeLock.Id);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (writeLock.Id == null)\n\t\t\t\t{\n                    writeLock.Id = await zookeeper.createAsync(dir + \"/\" + prefix, writeLock.data, writeLock.Acl, CreateMode.EPHEMERAL_SEQUENTIAL).ConfigureAwait(false);\n\n                    if (LOG.isDebugEnabled())\n\t\t\t\t\t{\n\t\t\t\t\t\tLOG.debug(\"Created id: \" + writeLock.Id);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// the command that is run and retried for actually \n\t\t\t/// obtaining the lock </summary>\n\t\t\t/// <returns> if the command was successful or not </returns>\n\t\t\tpublic async Task<bool> execute()\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tif (writeLock.Id == null)\n\t\t\t\t\t{\n\t\t\t\t\t\tlong sessionId = writeLock.zookeeper.getSessionId();\n\t\t\t\t\t\tstring prefix = \"x-\" + sessionId + \"-\";\n\t\t\t\t\t\t// lets try look up the current ID if we failed \n\t\t\t\t\t\t// in the middle of creating the znode\n\t\t\t\t\t\tawait findPrefixInChildren(prefix, writeLock.zookeeper, writeLock.dir).ConfigureAwait(false);\n                        writeLock.idName = new ZNodeName(writeLock.Id);\n\t\t\t\t\t}\n\t\t\t\t\tif (writeLock.Id != null)\n\t\t\t\t\t{\n\t\t\t\t\t\tList<string> names = (await writeLock.zookeeper.getChildrenAsync(writeLock.dir).ConfigureAwait(false)).Children;\n\t\t\t\t\t\tif (names.Count == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLOG.warn(\"No children in: \" + writeLock.dir + \" when we've just \" + \"created one! Lets recreate it...\");\n                            // lets force the recreation of the id\n                            writeLock.Id = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// lets sort them explicitly (though they do seem to come back in order ususally :)\n\t\t\t\t\t\t\tSortedSet<ZNodeName> sortedNames = new SortedSet<ZNodeName>();\n\t\t\t\t\t\t\tforeach (string name in names)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsortedNames.Add(new ZNodeName(writeLock.dir + \"/\" + name));\n\t\t\t\t\t\t\t}\n                            writeLock.ownerId = sortedNames.Min.Name;\n                            SortedSet<ZNodeName> lessThanMe = new SortedSet<ZNodeName>();\n\n\t\t\t\t\t\t    foreach (ZNodeName name in sortedNames) {\n\t\t\t\t\t\t        if (writeLock.idName.CompareTo(name) > 0) lessThanMe.Add(name);\n                                else break;\n\t\t\t\t\t\t    }\n\n\t\t\t\t\t\t    if (lessThanMe.Count > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tZNodeName lastChildName = lessThanMe.Max;\n                                writeLock.lastChildId = lastChildName.Name;\n\t\t\t\t\t\t\t\tif (LOG.isDebugEnabled())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLOG.debug(\"watching less than me node: \" + writeLock.lastChildId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tStat stat = await writeLock.zookeeper.existsAsync(writeLock.lastChildId, new LockWatcher(writeLock)).ConfigureAwait(false);\n\t\t\t\t\t\t\t\tif (stat != null)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t    LOG.warn(\"Could not find the\" + \" stats for less than me: \" + lastChildName.Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (writeLock.Owner)\n\t\t\t\t\t\t\t\t{\n                                    var tempCallback = writeLock.callback.Value;\n                                    if (tempCallback != null) {\n                                        await tempCallback.lockAcquired().ConfigureAwait(false);\n                                    }\n                                    return true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} while (writeLock.Id == null);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Attempts to acquire the exclusive write lock returning whether or not it was\n\t\t/// acquired. Note that the exclusive lock may be acquired some time later after\n\t\t/// this method has been invoked due to the current lock owner going away.\n\t\t/// </summary>\n\t\tpublic async Task<bool> Lock()\n\t\t{\n            using(await lockable.LockAsync().ConfigureAwait(false))\n\t\t\t{\n\t\t\t\tawait ensurePathExists(dir).ConfigureAwait(false);\n        \n\t\t\t\treturn await retryOperation(zop).ConfigureAwait(false);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// return the parent dir for lock </summary>\n\t\t/// <returns> the parent dir used for locks. </returns>\n\t\tpublic string Dir\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn dir;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns true if this node is the owner of the\n\t\t///  lock (or the leader)\n\t\t/// </summary>\n\t\tpublic bool Owner\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn Id != null && ownerId != null && Id.Equals(ownerId);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// return the id for this lock </summary>\n\t\t/// <returns> the id for this lock </returns>\n\t\tpublic string Id { get; private set; }\n\t}\n\n\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Lock/ZNodeName.cs",
    "content": "﻿using System;\nusing org.apache.utils;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// Represents an ephemeral znode name which has an ordered sequence number\n\t/// and can be sorted in order\n\t/// \n\t/// </summary>\n\tinternal sealed class ZNodeName : IComparable<ZNodeName> {\n\t\tpublic readonly string Name;\n\t    private readonly string prefix;\n\t    private readonly int sequence = -1;\n\t    private static readonly ILogProducer LOG = TypeLogger<ZNodeName>.Instance;\n\n\t    public ZNodeName(string name) {\n\t        if (name == null) {\n\t            throw new NullReferenceException(\"id cannot be null\");\n\t        }\n\n\t        this.Name = name;\n\t        this.prefix = name;\n\t        int idx = name.LastIndexOf('-');\n\t        if (idx >= 0) {\n\t            this.prefix = name.Substring(0, idx);\n\t            if (idx + 1 >= name.Length) {\n\t                LOG.info(\"Array out of bounds for \" + idx);\n\t            }\n\t            else if (!int.TryParse(name.Substring(idx + 1), out sequence)) {\n                    // If an exception occurred we misdetected a sequence suffix,\n\t                // so return -1.\n\t                LOG.info(\"Number format exception for \" + idx);\n\t            }\n\t        }\n\t    }\n\n\t    public override string ToString() {\n\t\t\treturn Name.ToString();\n\t\t}\n\n\t    public override bool Equals(object obj) {\n\t        if (ReferenceEquals(null, obj)) return false;\n\t        if (ReferenceEquals(this, obj)) return true;\n\t        return obj is ZNodeName nodeName && string.Equals(Name, nodeName.Name);\n\t    }\n\t\tpublic override int GetHashCode() {\n\t\t    return Name.GetHashCode();\n\t\t}\n\n\t    /// <summary>\n        /// Compare znodes based on their sequence number\n        /// </summary>\n        /// <param name=\"that\">other znode to compare to</param>\n        /// <returns>\n        /// the difference between their sequence numbers: a positive value if this\n        /// znode has a larger sequence number, 0 if they have the same sequence number\n        /// or a negative number if this znode has a lower sequence number\n        /// </returns>\n        public int CompareTo(ZNodeName that) {\n\t        int answer = this.sequence - that.sequence;\n\t        if (answer == 0) {\n\t            return String.Compare(this.prefix, that.prefix, StringComparison.Ordinal);\n\t        }\n\t        return answer;\n\t    }\n\t}\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Lock/ZooKeeperOperation.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// A callback object which can be used for implementing retry-able operations in the \n\t/// <seealso cref=\"ProtocolSupport\"/> class\n\t/// \n\t/// </summary>\n\tpublic interface ZooKeeperOperation\n\t{\n\n\t\t/// <summary>\n\t\t/// Performs the operation - which may be involved multiple times if the connection\n\t\t/// to ZooKeeper closes during this operation\n\t\t/// </summary>\n\t\t/// <returns> the result of the operation or null </returns>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tTask<bool> execute();\n\t}\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/Properties/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ZooKeeperNetEx.Recipes.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100416f66004a1fd058e5d6d0756c8bcc429965b3fd20c74901d5a4b0d69c53885a32cfd82343f0452145534caa6ee14074f885f173dddda29ab9bdad17e32e2ae1306d3b651a087e030b70caefcf6f2c91a3e1930c519507638581c5d06612a953ca879111b5383aebc452067a800b014cae8c6a4bf2c9ed71f6159d04620d1ad5\")]"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/ZooKeeperNetEx.Recipes.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <Description>.NET async Distributed Recipes For ZooKeeper: Queue, Lock and Leader Election.</Description>\r\n    <Summary>$(Description)</Summary>\r\n\t\r\n\t<AssemblyTitle>Apache ZooKeeper .NET async Recipes</AssemblyTitle>\r\n\t<Product>$(AssemblyTitle)</Product>\r\n    <Title>$(AssemblyTitle)</Title>\r\n\t\r\n    <PackageId>ZooKeeperNetEx.Recipes</PackageId>\r\n    <AssemblyName>$(PackageId)</AssemblyName>\r\n  \r\n    <PackageTags>ZooKeeper;Recipes;.NET;Lock;Leader Election;Queue</PackageTags>\r\n  </PropertyGroup>\r\n\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\ZooKeeperNetEx\\ZooKeeperNetEx.csproj\" />\r\n  </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/leader/LeaderElectionAware.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace org.apache.zookeeper.recipes.leader {\n    /// <summary>\n    ///     An interface to be implemented by clients that want to receive election\n    ///     events.\n    /// </summary>\n    public interface LeaderElectionAware {\n        /// <summary>\n        ///     Called during each state transition. Current, low level events are provided\n        ///     at the beginning and end of each state. For instance, START may be followed\n        ///     by OFFER_START, OFFER_COMPLETE, DETERMINE_START, DETERMINE_COMPLETE, and so\n        ///     on.\n        /// </summary>\n        /// <param name=\"eventType\"> </param>\n        Task onElectionEvent(ElectionEventType eventType);\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/leader/LeaderElectionSupport.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.utils;\n\nnamespace org.apache.zookeeper.recipes.leader {\n    /// <summary>\n    ///     <para>\n    ///         A leader election support library implementing the ZooKeeper election recipe.\n    ///     </para>\n    ///     <para>\n    ///         This support library is meant to simplify the construction of an exclusive\n    ///         leader system on top of Apache ZooKeeper. Any application that can become the\n    ///         leader (usually a process that provides a service, exclusively) would\n    ///         configure an instance of this class with their hostname, at least one\n    ///         listener (an implementation of <seealso cref=\"LeaderElectionAware\" />), and either an\n    ///         instance of <seealso cref=\"ZooKeeper\" /> or the proper connection information. Once\n    ///         configured, invoking <seealso cref=\"start()\" /> will cause the client to connect to\n    ///         ZooKeeper and create a leader offer. The library then determines if it has\n    ///         been elected the leader using the algorithm described below. The client\n    ///         application can follow all state transitions via the listener callback.\n    ///     </para>\n    ///     <para>\n    ///         Leader election algorithm\n    ///     </para>\n    ///     <para>\n    ///         The library starts in a START state. Through each state transition, a state\n    ///         start and a state complete event are sent to all listeners. When\n    ///         <seealso cref=\"start()\" /> is called, a leader offer is created in ZooKeeper. A leader\n    ///         offer is an ephemeral sequential node that indicates a process that can act\n    ///         as a leader for this service. A read of all leader offers is then performed.\n    ///         The offer with the lowest sequence number is said to be the leader. The\n    ///         process elected leader will transition to the leader state. All other\n    ///         processes will transition to a ready state. Internally, the library creates a\n    ///         ZooKeeper watch on the leader offer with the sequence ID of N - 1 (where N is\n    ///         the process's sequence ID). If that offer disappears due to a process\n    ///         failure, the watching process will run through the election determination\n    ///         process again to see if it should become the leader. Note that sequence ID\n    ///         may not be contiguous due to failed processes. A process may revoke its offer\n    ///         to be the leader at any time by calling <seealso cref=\"stop()\" />.\n    ///     </para>\n    ///     <para>\n    ///         Guarantees (not) Made and Caveats\n    ///     </para>\n    ///     <para>\n    ///         <ul>\n    ///             <li>\n    ///                 It is possible for a (poorly implemented) process to create a leader\n    ///                 offer, get the lowest sequence ID, but have something terrible occur where it\n    ///                 maintains its connection to ZK (and thus its ephemeral leader offer node) but\n    ///                 doesn't actually provide the service in question. It is up to the user to\n    ///                 ensure any failure to become the leader - and whatever that means in the\n    ///                 context of the user's application - results in a revocation of its leader\n    ///                 offer (i.e. that <seealso cref=\"stop()\" /> is called).\n    ///             </li>\n    ///             <li>\n    ///                 It is possible for ZK timeouts and retries to play a role in service\n    ///                 liveliness. In other words, if process A has the lowest sequence ID but\n    ///                 requires a few attempts to read the other leader offers' sequence IDs,\n    ///                 election can seem slow. Users should apply timeouts during the determination\n    ///                 process if they need to hit a specific SLA.\n    ///             </li>\n    ///             <li>\n    ///                 The library makes a \"best effort\" to detect catastrophic failures of the\n    ///                 process. It is possible that an unforeseen event results in (for instance) an\n    ///                 unchecked exception that propagates passed normal error handling code. This\n    ///                 normally doesn't matter as the same exception would almost certain destroy\n    ///                 the entire process and thus the connection to ZK and the leader offer\n    ///                 resulting in another round of leader determination.\n    ///             </li>\n    ///         </ul>\n    ///     </para>\n    /// </summary>\n    public sealed class LeaderElectionSupport {\n        private readonly AsyncLock lockable = new AsyncLock();\n  \n        private static readonly ILogProducer logger = TypeLogger<LeaderElectionSupport>.Instance;\n        private readonly ConcurrentDictionary<LeaderElectionAware, byte> listeners;\n        private readonly ElectionWatcher electionWatcher;\n        private byte dummy;\n        private LeaderOffer leaderOffer;\n        private State state;\n\n        /// <summary>\n        /// Create a new instance of leader election recipe.\n        /// </summary>\n        /// <param name=\"zooKeeper\">the zookeeper instance to use</param>\n        /// <param name=\"rootNodeName\">the root node to perform elections on</param>\n        /// <param name=\"hostName\">the name of the current host</param>\n        public LeaderElectionSupport(ZooKeeper zooKeeper, string rootNodeName, string hostName) {\n            ZooKeeper = zooKeeper;\n            RootNodeName = rootNodeName;\n            HostName = hostName;\n            state = State.STOP;\n            electionWatcher = new ElectionWatcher(this);\n            listeners = new ConcurrentDictionary<LeaderElectionAware, byte>();\n        }\n\n        /// <summary>\n        ///     Fetch the (user supplied) hostname of the current leader. Note that by the\n        ///     time this method returns, state could have changed so do not depend on this\n        ///     to be strongly consistent. This method has to read all leader offers from\n        ///     ZooKeeper to deterime who the leader is (i.e. there is no caching) so\n        ///     consider the performance implications of frequent invocation. If there are\n        ///     no leader offers this method returns null.\n        /// </summary>\n        /// <returns> hostname of the current leader </returns>\n        /// <exception cref=\"KeeperException\"> </exception>\n        public async Task<string> getLeaderHostName() {\n            var leaderOffers = await toLeaderOffers((await ZooKeeper.getChildrenAsync(RootNodeName).ConfigureAwait(false)).Children).ConfigureAwait(false);\n\n            if (leaderOffers.Count > 0) {\n                return leaderOffers[0].HostName;\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        ///     <para>\n        ///         Gets the ZooKeeper root node to use for this service.\n        ///     </para>\n        ///     <para>\n        ///         For instance, a root node of {@code /mycompany/myservice} would be the\n        ///         parent of all leader offers for this service. Obviously all processes that\n        ///         wish to contend for leader status need to use the same root node. Note: We\n        ///         assume this node already exists.\n        ///     </para>\n        /// </summary>\n        /// <returns> a znode path </returns>\n        private readonly string RootNodeName;\n\n        /// <summary>\n        ///     The <seealso cref=\"ZooKeeper\" /> instance to use for all operations. Provided this\n        ///     overrides any connectString or sessionTimeout set.\n        /// </summary>\n        private readonly ZooKeeper ZooKeeper;\n\n        /// <summary>\n        ///     The hostname of this process. Mostly used as a convenience for logging and\n        ///     to respond to <seealso cref=\"getLeaderHostName()\" /> requests.\n        /// </summary>\n        private readonly string HostName;\n\n        /// <summary>\n        ///     <para>\n        ///         Start the election process. This method will create a leader offer,\n        ///         determine its status, and either become the leader or become ready. If an\n        ///         instance of <seealso cref=\"ZooKeeper\" /> has not yet been configured by the user, a\n        ///         new instance is created using the connectString and sessionTime specified.\n        ///     </para>\n        ///     <para>\n        ///         Any (anticipated) failures result in a failed event being sent to all\n        ///         listeners.\n        ///     </para>\n        /// </summary>\n        public async Task start() {\n            using (await lockable.LockAsync().ConfigureAwait(false))\n             {\n                state = State.START;\n                await dispatchEvent(ElectionEventType.START).ConfigureAwait(false);\n\n                logger.info(\"Starting leader election support\");\n\n                if (ZooKeeper == null) {\n                    throw new InvalidOperationException(\"No instance of zookeeper provided. Hint: use setZooKeeper()\");\n                }\n\n                if (HostName == null) {\n                    throw new InvalidOperationException(\"No hostname provided. Hint: use setHostName()\");\n                }\n                KeeperException ke = null;\n                try {\n                    await makeOffer().ConfigureAwait(false);\n                    await determineElectionStatus().ConfigureAwait(false);\n                }\n                catch (KeeperException e) {\n                    ke = e;\n                }\n                if (ke != null) {\n                    await becomeFailed(ke).ConfigureAwait(false);\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Stops all election services, revokes any outstanding leader offers, and\n        ///     disconnects from ZooKeeper.\n        /// </summary>\n        public async Task stop()\n        {\n            using (await lockable.LockAsync().ConfigureAwait(false))\n             {\n                state = State.STOP;\n                await dispatchEvent(ElectionEventType.STOP_START).ConfigureAwait(false);\n\n                logger.info(\"Stopping leader election support\");\n\n                if (leaderOffer != null) {\n                    KeeperException ke = null;\n                    try {\n                        await ZooKeeper.deleteAsync(leaderOffer.NodePath).ConfigureAwait(false);\n                        logger.debugFormat(\"Removed leader offer {0}\", leaderOffer.NodePath);\n                    }\n                    catch (KeeperException e)\n                    {\n                        ke = e;\n                    }\n                    if (ke != null)\n                    {\n                        await becomeFailed(ke).ConfigureAwait(false);\n                    }\n                }\n\n                await dispatchEvent(ElectionEventType.STOP_COMPLETE).ConfigureAwait(false);\n            }\n        }\n\n        private async Task makeOffer() {\n            state = State.OFFER;\n            await dispatchEvent(ElectionEventType.OFFER_START).ConfigureAwait(false);\n\n            leaderOffer = new LeaderOffer();\n\n            leaderOffer.HostName = HostName;\n            leaderOffer.NodePath = await ZooKeeper.createAsync(RootNodeName + \"/\" + \"n_\", HostName.UTF8getBytes(),\n                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL).ConfigureAwait(false);\n\n            logger.debugFormat(\"Created leader offer {0}\", leaderOffer);\n\n            await dispatchEvent(ElectionEventType.OFFER_COMPLETE).ConfigureAwait(false);\n        }\n\n        private async Task determineElectionStatus() {\n            state = State.DETERMINE;\n            await dispatchEvent(ElectionEventType.DETERMINE_START).ConfigureAwait(false);\n\n            var components = leaderOffer.NodePath.Split('/');\n\n            leaderOffer.Id = int.Parse(components[components.Length - 1].Substring(\"n_\".Length));\n\n            var leaderOffers = await toLeaderOffers((await ZooKeeper.getChildrenAsync(RootNodeName).ConfigureAwait(false)).Children).ConfigureAwait(false);\n\n            /*\n\t\t * For each leader offer, find out where we fit in. If we're first, we\n\t\t * become the leader. If we're not elected the leader, attempt to stat the\n\t\t * offer just less than us. If they exist, watch for their failure, but if\n\t\t * they don't, become the leader.\n\t\t */\n            for (var i = 0; i < leaderOffers.Count; i++) {\n                if (leaderOffers[i].Id.Equals(leaderOffer.Id)) {\n                    logger.debugFormat(\"There are {0} leader offers. I am {1} in line.\", leaderOffers.Count, i);\n\n                    await dispatchEvent(ElectionEventType.DETERMINE_COMPLETE).ConfigureAwait(false);\n\n                    if (i == 0) {\n                        await becomeLeader().ConfigureAwait(false);\n                    }\n                    else {\n                        await becomeReady(leaderOffers[i - 1]).ConfigureAwait(false);\n                    }\n\n                    /* Once we've figured out where we are, we're done. */\n                    break;\n                }\n            }\n        }\n\n        private async Task becomeReady(LeaderOffer neighborLeaderOffer) {\n            await dispatchEvent(ElectionEventType.READY_START).ConfigureAwait(false);\n\n            logger.debugFormat(\"{0} not elected leader. Watching node:{1}\", leaderOffer.NodePath,\n                neighborLeaderOffer.NodePath);\n\n            /*\n\t\t * Make sure to pass an explicit Watcher because we could be sharing this\n\t\t * zooKeeper instance with someone else.\n\t\t */\n            var stat = await ZooKeeper.existsAsync(neighborLeaderOffer.NodePath, electionWatcher).ConfigureAwait(false);\n\n            if (stat != null) {\n                logger.debugFormat(\"We're behind {0} in line and they're alive. Keeping an eye on them.\",\n                    neighborLeaderOffer.NodePath);\n                state = State.READY;\n                await dispatchEvent(ElectionEventType.READY_COMPLETE).ConfigureAwait(false);\n            }\n            else {\n                /*\n\t\t   * If the stat fails, the node has gone missing between the call to\n\t\t   * getChildren() and exists(). We need to try and become the leader.\n\t\t   */\n                logger.debugFormat(\"We were behind {0} but it looks like they died. Back to determination.\",\n                    neighborLeaderOffer.NodePath);\n                await determineElectionStatus().ConfigureAwait(false);\n            }\n        }\n\n        private async Task becomeLeader()\n        {\n            state = State.ELECTED;\n            await dispatchEvent(ElectionEventType.ELECTED_START).ConfigureAwait(false);\n\n            logger.debugFormat(\"Becoming leader with node:{0}\", leaderOffer.NodePath);\n\n            await dispatchEvent(ElectionEventType.ELECTED_COMPLETE).ConfigureAwait(false);\n        }\n\n        private Task becomeFailed(Exception e) {\n            logger.debugFormat(\"Failed in state {0} - Exception:{1}\", state, e);\n\n            state = State.FAILED;\n            return dispatchEvent(ElectionEventType.FAILED);\n        }\n\n        private async Task<List<LeaderOffer>> toLeaderOffers(List<string> strings) {\n            var leaderOffers = new List<LeaderOffer>(strings.Count);\n\n            /*\n\t\t * Turn each child of rootNodeName into a leader offer. This is a tuple of\n\t\t * the sequence number and the node name.\n\t\t */\n            foreach (var offer in strings) {\n                var currentHostName = (await ZooKeeper.getDataAsync(RootNodeName + \"/\" + offer).ConfigureAwait(false)).Data.UTF8bytesToString();\n\n                leaderOffers.Add(new LeaderOffer(int.Parse(offer.Substring(\"n_\".Length)),\n                    RootNodeName + \"/\" + offer, currentHostName));\n            }\n\n            /*\n\t\t * We sort leader offers by sequence number (which may not be zero-based or\n\t\t * contiguous) and keep their paths handy for setting watches.\n\t\t */\n            leaderOffers.Sort(new LeaderOffer.IdComparator());\n\n            return leaderOffers;\n        }\n        private class ElectionWatcher:Watcher\n        {\n            private readonly LeaderElectionSupport les;\n\n            public ElectionWatcher(LeaderElectionSupport leaderElectionSupport)\n            {\n                les = leaderElectionSupport;\n            }\n\n            public async override Task process(WatchedEvent @event) {\n                if (@event.get_Type().Equals(Event.EventType.NodeDeleted)) {\n                    if (!@event.get_Type().ToString().Equals(les.leaderOffer.NodePath) && les.state != State.STOP) {\n                        logger.debugFormat(\"Node {0} deleted. Need to run through the election process.\", @event.getPath());\n                        KeeperException ke = null;\n                        try {\n                            await les.determineElectionStatus().ConfigureAwait(false);\n                        }\n                        catch (KeeperException e) {\n                            ke = e;\n                        }\n                        if (ke != null) {\n                            await les.becomeFailed(ke).ConfigureAwait(false);\n                        }\n                    }\n                }\n            }\n        }\n\n        private readonly AsyncLock listenersLock = new AsyncLock();\n\n        private async Task dispatchEvent(ElectionEventType eventType) {\n            logger.debugFormat(\"Dispatching event:{0}\", eventType);\n\n            using (await listenersLock.LockAsync().ConfigureAwait(false)) {\n                if (listeners.Count > 0) {\n                    foreach (var observer in listeners.Keys) {\n                        try {\n                            await observer.onElectionEvent(eventType).ConfigureAwait(false);\n                        }\n                        catch (Exception e) {\n                            logger.warn(\"error while calling observer\", e);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Adds {@code listener} to the list of listeners who will receive events.\n        /// </summary>\n        /// <param name=\"listener\"> </param>\n        public void addListener(LeaderElectionAware listener) {\n            listeners[listener] = dummy;\n        }\n\n        /// <summary>\n        ///     Remove {@code listener} from the list of listeners who receive events.\n        /// </summary>\n        /// <param name=\"listener\"> </param>\n        public void removeListener(LeaderElectionAware listener) {\n            listeners.TryRemove(listener, out dummy);\n        }\n\n        /// <summary>\n        /// </summary>\n        public override string ToString() {\n            return \"{ state:\" + state + \" leaderOffer:\" + leaderOffer + \" zooKeeper:\" + ZooKeeper + \" hostName:\" +\n                   HostName + \" listeners:\" + listeners.Keys.ToCommaDelimited() +\" }\";\n        }\n\n        /// <summary>\n        ///     The internal state of the election support service.\n        /// </summary>\n        private enum State {\n            START,\n            OFFER,\n            DETERMINE,\n            ELECTED,\n            READY,\n            FAILED,\n            STOP\n        }\n    }\n    /// <summary>\n    ///     The type of election event.\n    /// </summary>\n    public enum ElectionEventType\n    {\n#pragma warning disable 1591\n        START,\n        OFFER_START,\n        OFFER_COMPLETE,\n        DETERMINE_START,\n        DETERMINE_COMPLETE,\n        ELECTED_START,\n        ELECTED_COMPLETE,\n        READY_START,\n        READY_COMPLETE,\n        FAILED,\n        STOP_START,\n        STOP_COMPLETE\n#pragma warning restore 1591\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/leader/LeaderOffer.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace org.apache.zookeeper.recipes.leader \n{\n    /// <summary>\n    ///     A leader offer is a numeric id / path pair. The id is the sequential node id\n    ///     assigned by ZooKeeper where as the path is the absolute path to the ZNode.\n    /// </summary>\n    internal sealed class LeaderOffer {\n        public string HostName;\n        public int Id;\n        public string NodePath;\n\n        public LeaderOffer() {\n            // Default constructor\n        }\n\n        public LeaderOffer(int id, string nodePath, string hostName) {\n            Id = id;\n            NodePath = nodePath;\n            HostName = hostName;\n        }\n\n        public override string ToString() {\n            return \"{ id:\" + Id + \" nodePath:\" + NodePath + \" hostName:\" + HostName + \" }\";\n        }\n\n        /// <summary>\n        ///     Compare two instances of <seealso cref=\"LeaderOffer\" /> using only the {code}id{code}\n        ///     member.\n        /// </summary>\n        internal sealed class IdComparator : IComparer<LeaderOffer>\n        {\n            public int Compare(LeaderOffer o1, LeaderOffer o2) {\n                return o1.Id.CompareTo(o2.Id);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/src/ZooKeeperNetEx.Recipes/queue/DistributedQueue.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\nusing org.apache.utils;\n\nnamespace org.apache.zookeeper.recipes.queue\n{\n\t/// \n\t/// <summary>\n\t/// A <a href=\"package.html\">protocol to implement a distributed queue</a>.\n\t/// </summary>\n\n\tpublic sealed class DistributedQueue\n\t{\n\t\tprivate static readonly ILogProducer LOG = TypeLogger<DistributedQueue>.Instance;\n\n\t\tprivate readonly string dir;\n\n\t\tprivate readonly ZooKeeper zookeeper;\n\t\tprivate readonly List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;\n\n\t    private const string prefix = \"qn-\";\n\n        /// <summary>\n        /// Create an instance of distributed queue recipe\n        /// </summary>\n        /// <param name=\"zookeeper\">the zookeeper instance to use</param>\n        /// <param name=\"dir\">the node to use for the queue</param>\n        /// <param name=\"acl\">the acl for the queue</param>\n\t    public DistributedQueue(ZooKeeper zookeeper, string dir, List<ACL> acl=null)\n\t\t{\n\t\t\tthis.dir = dir;\n\n\t\t\tif (acl != null)\n\t\t\t{\n\t\t\t\tthis.acl = acl;\n\t\t\t}\n\t\t\tthis.zookeeper = zookeeper;\n\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a Map of the children, ordered by id. </summary>\n\t\t/// <param name=\"watcher\"> optional watcher on getChildren() operation. </param>\n\t\t/// <returns> map from id to child name for all children </returns>\n\t\tprivate async Task<SortedDictionary<long, string>> getOrderedChildren(Watcher watcher)\n\t\t{\n\t\t\tSortedDictionary<long, string> orderedChildren = new SortedDictionary<long, string>();\n\n            List<string> childNames = (await zookeeper.getChildrenAsync(dir, watcher).ConfigureAwait(false)).Children;\n            \n\t\t\tforeach (string childName in childNames)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t//Check format\n\t\t\t\t    if (!childName.StartsWith(prefix, StringComparison.Ordinal))\n                    {\n\t\t\t\t        LOG.warn(\"Found child node with improper name: \" + childName);\n\t\t\t\t        continue;\n\t\t\t\t    }\n\t\t\t\t    string suffix = childName.Substring(prefix.Length);\n\t\t\t\t    long childId = long.Parse(suffix);\n\t\t\t\t\torderedChildren[childId] = childName;\n\t\t\t\t}\n\t\t\t\tcatch (FormatException e)\n\t\t\t\t{\n\t\t\t\t\tLOG.warn(\"Found child node with improper format : \" + childName + \" \" + e,e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn orderedChildren;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Return the head of the queue without modifying the queue. </summary>\n\t\t/// <returns> the data at the head of the queue. </returns>\n\t\t/// <exception cref=\"InvalidOperationException\"> </exception>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tpublic async Task<byte[]> element()\n\t\t{\n\t\t    // element, take, and remove follow the same pattern.\n\t\t\t// We want to return the child node with the smallest sequence number.\n\t\t\t// Since other clients are remove()ing and take()ing nodes concurrently, \n\t\t\t// the child with the smallest sequence number in orderedChildren might be gone by the time we check.\n\t\t\t// We don't call getChildren again until we have tried the rest of the nodes in sequence order.\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t    SortedDictionary<long, string> orderedChildren;\n\t\t\t    try\n\t\t\t\t{\n                    orderedChildren = await getOrderedChildren(null).ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException();\n\t\t\t\t}\n\t\t\t\tif (orderedChildren.Count == 0)\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException();\n\t\t\t\t}\n\n\t\t\t\tforeach (string headNode in orderedChildren.Values)\n\t\t\t\t{\n\t\t\t\t\tif (headNode != null)\n\t\t\t\t\t{\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n                            return (await zookeeper.getDataAsync(dir + \"/\" + headNode).ConfigureAwait(false)).Data;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Another client removed the node first, try next\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\n\t\t/// <summary>\n\t\t/// Attempts to remove the head of the queue and return it. </summary>\n\t\t/// <returns> The former head of the queue </returns>\n\t\t/// <exception cref=\"InvalidOperationException\"> </exception>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tpublic async Task<byte[]> remove()\n\t\t{\n\t\t    // Same as for element.  Should refactor this.\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t    SortedDictionary<long, string> orderedChildren;\n\t\t\t    try\n\t\t\t\t{\n                    orderedChildren = await getOrderedChildren(null).ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException();\n\t\t\t\t}\n\t\t\t\tif (orderedChildren.Count == 0)\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException();\n\t\t\t\t}\n\n\t\t\t\tforeach (string headNode in orderedChildren.Values)\n\t\t\t\t{\n\t\t\t\t\tstring path = dir + \"/\" + headNode;\n\t\t\t\t\ttry\n\t\t\t\t\t{\n                        byte[] data = (await zookeeper.getDataAsync(path).ConfigureAwait(false)).Data;\n                        await zookeeper.deleteAsync(path).ConfigureAwait(false);\n\t\t\t\t\t\treturn data;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Another client deleted the node first.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\tprivate sealed class LatchChildWatcher : Watcher\n\t\t{\n\t\t    private readonly TaskCompletionSource<bool> latch = new TaskCompletionSource<bool>();\n            \n\t\t\tpublic override Task process(WatchedEvent @event)\n\t\t\t{\n\t\t\t\tLOG.debug(\"Watcher fired on path: \" + @event.getPath() + \" state: \" + @event.getState() + \" type \" + @event.get_Type());\n\t\t\t    latch.TrySetResult(true);\n\t\t\t    return Task.CompletedTask;\n\t\t\t}\n\n\t\t\tpublic Task getTask()\n\t\t\t{\n\t\t\t\treturn latch.Task;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Removes the head of the queue and returns it, blocks until it succeeds. </summary>\n\t\t/// <returns> The former head of the queue </returns>\n\t\t/// <exception cref=\"InvalidOperationException\"> </exception>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tpublic async Task<byte[]> take()\n\t\t{\n\t\t    // Same as for element.  Should refactor this.\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tLatchChildWatcher childWatcher = new LatchChildWatcher();\n\t\t\t    SortedDictionary<long, string> orderedChildren = null;\n\t\t\t    bool isNoNode = false;\n\t\t\t    try\n\t\t\t\t{\n                    orderedChildren = await getOrderedChildren(childWatcher).ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoNodeException) {\n\t\t\t\t    isNoNode = true;\n\t\t\t\t}\n\t\t\t    if (isNoNode) {\n                    await zookeeper.createAsync(dir, new byte[0], acl, CreateMode.PERSISTENT).ConfigureAwait(false);\n                    continue;\n\t\t\t    }\n\t\t\t\tif (orderedChildren.Count == 0)\n\t\t\t\t{\n                    await childWatcher.getTask().ConfigureAwait(false);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tforeach (string headNode in orderedChildren.Values)\n\t\t\t\t{\n\t\t\t\t\tstring path = dir + \"/\" + headNode;\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tbyte[] data = (await zookeeper.getDataAsync(path).ConfigureAwait(false)).Data;\n                        await zookeeper.deleteAsync(path).ConfigureAwait(false);\n\t\t\t\t\t\treturn data;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (KeeperException.NoNodeException)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Another client deleted the node first.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Inserts data into queue. </summary>\n\t\t/// <param name=\"data\"> </param>\n\t\t/// <returns> true if data was successfully added </returns>\n\t\tpublic async Task<bool> offer(byte[] data)\n\t\t{\n\t\t\tfor (;;)\n            {\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zookeeper.createAsync(dir + \"/\" + prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL).ConfigureAwait(false);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoNodeException) \n                {\n\t\t\t\t\n\t\t\t\t}\n\t\t\t    await zookeeper.createAsync(dir, new byte[0], acl, CreateMode.PERSISTENT).ConfigureAwait(false);\n\t\t\t}\n\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns the data at the first element of the queue, or null if the queue is empty. </summary>\n\t\t/// <returns> data at the first element of the queue, or null. </returns>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tpublic async Task<byte[]> peek()\n\t\t{\n\t\t\ttry\n\t\t\t{\n                return await element().ConfigureAwait(false);\n\t\t\t}\n\t\t\tcatch (InvalidOperationException)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\n\t\t/// <summary>\n\t\t/// Attempts to remove the head of the queue and return it. Returns null if the queue is empty. </summary>\n\t\t/// <returns> Head of the queue or null. </returns>\n\t\t/// <exception cref=\"KeeperException\"> </exception>\n\t\tpublic async Task<byte[]> poll()\n\t\t{\n\t\t\ttry\n\t\t\t{\n                return await remove().ConfigureAwait(false);\n\t\t\t}\n\t\t\tcatch (InvalidOperationException)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "src/csharp/test/Directory.Build.props",
    "content": "﻿<Project>\n  <Import Project=\"..\\Directory.Build.props\" />\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.3.0\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"12.0.2\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)xunit.runner.json\" Link=\"xunit.runner.json\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Recipes.Tests/ZooKeeperNetEx.Recipes.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <AssemblyName>ZooKeeperNetEx.Recipes.Tests</AssemblyName>\r\n  </PropertyGroup>\r\n\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\ZooKeeperNetEx.Tests\\ZooKeeperNetEx.Tests.csproj\" />\r\n    <ProjectReference Include=\"..\\..\\src\\ZooKeeperNetEx.Recipes\\ZooKeeperNetEx.Recipes.csproj\" />\r\n  </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Recipes.Tests/leader/LeaderElectionSupportTest.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.recipes.leader {\n    public sealed class LeaderElectionSupportTest : ClientBase {\n        private static int globalCounter;\n        private readonly string root = \"/\" + Interlocked.Increment(ref globalCounter);\n        private ZooKeeper zooKeeper;\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            zooKeeper = await createClient();\n\n            await zooKeeper.createAsync(root, new byte[0],\n                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n\n        [Fact]\n        public async Task testNode() {\n            var electionSupport = createLeaderElectionSupport();\n\n            await electionSupport.start();\n            await Task.Delay(3000);\n            await electionSupport.stop();\n        }\n\n        private async Task CreateTestNodesTask(int testIterations, int millisecondsDelay)\n        {\n            Assert.assertTrue(await Task.WhenAll(Enumerable.Repeat(runElectionSupportTask(), testIterations))\n                        .WithTimeout(millisecondsDelay));\n        }\n\n        [Fact]\n        public Task testNodes3() {\n            return CreateTestNodesTask(3, 10 * 1000);\n        }\n\n        [Fact]\n        public Task testNodes9() {\n            return CreateTestNodesTask(9, 10 * 1000);\n        }\n\n        [Fact]\n        public Task testNodes20() {\n            return CreateTestNodesTask(20, 10 * 1000);\n        }\n\n        [Fact]\n        public Task testNodes100() {\n            return CreateTestNodesTask(100, 20 * 1000);\n        }\n\n        [Fact]\n        public async Task testOfferShuffle() {\n            const int testIterations = 10;\n\n            var elections = Enumerable.Range(1, testIterations)\n                .Select(i => runElectionSupportTask(Math.Min(i*1200, 10000)));\n            Assert.assertTrue(await Task.WhenAll(elections).WithTimeout(60*1000));\n        }\n\n        [Fact]\n        public async Task testGetLeaderHostName() {\n            var electionSupport = createLeaderElectionSupport();\n\n            await electionSupport.start();\n\n            // Sketchy: We assume there will be a leader (probably us) in 3 seconds.\n            await Task.Delay(3000);\n\n            var leaderHostName = await electionSupport.getLeaderHostName();\n\n            Assert.assertNotNull(leaderHostName);\n            Assert.assertEquals(\"foohost\", leaderHostName);\n\n            await electionSupport.stop();\n        }\n\n        private LeaderElectionSupport createLeaderElectionSupport()\n        {\n            return new LeaderElectionSupport(zooKeeper, root, \"foohost\");\n        }\n\n        private async Task runElectionSupportTask(int sleepDuration = 3000)\n        {\n            var electionSupport = createLeaderElectionSupport();\n\n            await electionSupport.start();\n            await Task.Delay(sleepDuration);\n            await electionSupport.stop();\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Recipes.Tests/lock/WriteLockTest.cs",
    "content": "using System.Threading.Tasks;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// test for writelock\n\t/// </summary>\n\tpublic sealed class WriteLockTest : ClientBase\n\t{\n        private static readonly ILogProducer LOG = TypeLogger<WriteLockTest>.Instance;\n\n\t    [Fact]\n\t\tpublic Task testRun()\n\t\t{\n\t\t\treturn runTest(3);\n\t\t}\n\n\t    private sealed class LockCallback : LockListener\n\t    {\n\t        public TaskCompletionSource<bool> TaskCompletionSource = new TaskCompletionSource<bool>();\n            \n\t\t\tpublic Task lockAcquired()\n\t\t\t{\n                TaskCompletionSource.TrySetResult(true);\n\t\t\t    return Task.FromResult(0);\n\t\t\t}\n\n\t\t\tpublic Task lockReleased()\n\t\t\t{\n                return Task.FromResult(0);\n            }\n\n\t\t}\n\n\t    private async Task runTest(int count)\n\t\t{\n\t\t\tvar nodes = new WriteLock[count];\n            var lockCallback=new LockCallback();\n\t\t\tfor (int i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tZooKeeper keeper = await createClient();\n\t\t\t\tWriteLock leader = new WriteLock(keeper, \"/test\", null);\n\t\t\t\tleader.setLockListener(lockCallback);\n\t\t\t\tnodes[i] = leader;\n\n\t\t\t\tawait leader.Lock();\n\t\t\t}\n\n\t\t\t// lets wait for any previous leaders to die and one of our new\n\t\t\t// nodes to become the new leader\n            Assert.assertTrue(await lockCallback.TaskCompletionSource.Task.WithTimeout(30*1000));\n            \n\t\t\tWriteLock first = nodes[0];\n\t\t\tdumpNodes(nodes,count);\n\n\t\t\t// lets assert that the first election is the leader\n\t\t\tAssert.assertTrue(\"The first znode should be the leader \" + first.Id, first.Owner);\n\n\t\t\tfor (int i = 1; i < count; i++)\n\t\t\t{\n\t\t\t\tWriteLock node = nodes[i];\n\t\t\t\tAssert.assertFalse(\"Node should not be the leader \" + node.Id, node.Owner);\n\t\t\t}\n\n\t\t\tif (count > 1)\n\t\t\t{\n\t\t\t    LOG.debug(\"Now killing the leader\");\n                // now lets kill the leader\n\t\t\t    lockCallback.TaskCompletionSource = new TaskCompletionSource<bool>();\n\t\t\t    await first.unlock();\n                Assert.assertTrue(await lockCallback.TaskCompletionSource.Task.WithTimeout(30 * 1000));\n                WriteLock second = nodes[1];\n\t\t\t    dumpNodes(nodes, count);\n\t\t\t    // lets assert that the first election is the leader\n\t\t\t    Assert.assertTrue(\"The second znode should be the leader \" + second.Id, second.Owner);\n\n\t\t\t    for (int i = 2; i < count; i++)\n\t\t\t    {\n\t\t\t        WriteLock node = nodes[i];\n\t\t\t        Assert.assertFalse(\"Node should not be the leader \" + node.Id, node.Owner);\n\t\t\t    }\n\t\t\t}\n\t\t}\n\n\t    private static void dumpNodes(WriteLock[] nodes, int count)\n\t\t{\n\t\t\tfor (int i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tWriteLock node = nodes[i];\n                LOG.debug(\"node: \" + i + \" id: \" + node.Id + \" is leader: \" + node.Owner);\n\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Recipes.Tests/lock/ZNodeNameTest.cs",
    "content": "﻿using System.Collections.Generic;\nusing Xunit;\n\nnamespace org.apache.zookeeper.recipes.@lock\n{\n\t/// <summary>\n\t/// test for znodenames\n\t/// </summary>\n\tpublic sealed class ZNodeNameTest \n\t{\n        [Fact]\n\t\tpublic void testOrderWithSamePrefix()\n\t\t{\n\t\t\tstring[] names = {\"x-3\", \"x-5\", \"x-11\", \"x-1\"};\n\t\t\tstring[] expected = {\"x-1\", \"x-3\", \"x-5\", \"x-11\"};\n\t\t\tassertOrderedNodeNames(names, expected);\n\t\t}\n\n        [Fact]\n        public void testOrderWithDifferentPrefixes()\n        {\n            string[] names = { \"r-3\", \"r-2\", \"r-1\", \"w-2\", \"w-1\" };\n            string[] expected = { \"r-1\", \"w-1\", \"r-2\", \"w-2\", \"r-3\" };\n            assertOrderedNodeNames(names, expected);\n        }\n\n        [Fact]\n        public void testOrderWithDifferentPrefixIncludingSessionId()\n        {\n            string [] names = { \"x-242681582799028564-0000000002\", \"x-170623981976748329-0000000003\", \"x-98566387950223723-0000000001\" };\n            string [] expected = { \"x-98566387950223723-0000000001\", \"x-242681582799028564-0000000002\", \"x-170623981976748329-0000000003\" };\n            assertOrderedNodeNames(names, expected);\n        }\n\n        [Fact]\n        public void testOrderWithExtraPrefixes() {\n            string[] names = { \"r-1-3-2\", \"r-2-2-1\", \"r-3-1-3\" };\n            string[] expected = { \"r-2-2-1\", \"r-1-3-2\", \"r-3-1-3\" };\n            assertOrderedNodeNames(names, expected);\n        }\n\n\t    private static void assertOrderedNodeNames(string[] names, string[] expected) {\n\n\t\t\tSortedSet<ZNodeName> nodeNames = new SortedSet<ZNodeName>();\n\t\t\tforeach (string name in names) {\n\t\t\t\tnodeNames.Add(new ZNodeName(name));\n\t\t\t}\n\t        Assert.assertEquals(\"The SortedSet does not have the expected size!\", nodeNames.size(), expected.Length);\n\n\t\t\tint index = 0;\n\t\t\tforeach (ZNodeName nodeName in nodeNames) {\n\t\t\t\tstring name = nodeName.Name;\n                Assert.assertEquals(\"Node \" + index, expected[index++], name);\n\t\t\t}\n\t\t}\n\n\t}\n\n    [CollectionDefinition(\"Setup\")]\n    public class SetupCollection : ICollectionFixture<TestsSetup>\n    {\n        // This class has no code, and is never created. Its purpose is simply\n        // to be the place to apply [CollectionDefinition] and all the\n        // ICollectionFixture<> interfaces.\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Recipes.Tests/queue/DistributedQueueTest.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.recipes.queue {\n    public sealed class DistributedQueueTest : ClientBase {\n\n        [Fact]\n        public async Task testOffer1() {\n            const string dir = \"/testOffer1\";\n            const string testString = \"Hello World\";\n            const int num_clients = 1;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            await queueHandles[0].offer(testString.UTF8getBytes());\n\n            byte[] dequeuedBytes = await queueHandles[0].remove();\n            Assert.assertEquals(dequeuedBytes.UTF8bytesToString(), testString);\n        }\n\n        [Fact]\n        public async Task testOffer2() {\n            const string dir = \"/testOffer2\";\n            const string testString = \"Hello World\";\n            const int num_clients = 2;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            await queueHandles[0].offer(testString.UTF8getBytes());\n\n            byte[] dequeuedBytes = await queueHandles[1].remove();\n            Assert.assertEquals(dequeuedBytes.UTF8bytesToString(), testString);\n        }\n\n        [Fact]\n        public async Task testTake1() {\n            const string dir = \"/testTake1\";\n            const string testString = \"Hello World\";\n            const int num_clients = 1;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            await queueHandles[0].offer(testString.UTF8getBytes());\n\n            byte[] dequeuedBytes = await queueHandles[0].take();\n            Assert.assertEquals(dequeuedBytes.UTF8bytesToString(), testString);\n        }\n\n        [Fact]\n        public async Task testRemove1() {\n            const string dir = \"/testRemove1\";\n            const int num_clients = 1;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            try {\n                await queueHandles[0].remove();\n            }\n            catch (InvalidOperationException) {\n                return;\n            }\n            Assert.assertTrue(false);\n        }\n\n        private async Task createNremoveMtest(string dir, int n, int m) {\n            const string testString = \"Hello World\";\n            const int num_clients = 2;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            for (int i = 0; i < n; i++) {\n                string offerString = testString + i;\n                await queueHandles[0].offer(offerString.UTF8getBytes());\n            }\n\n            byte[] data = null;\n            for (int i = 0; i < m; i++) {\n                data = await queueHandles[1].remove();\n            }\n            // ReSharper disable once AssignNullToNotNullAttribute\n            Assert.assertEquals(data.UTF8bytesToString(), testString + (m - 1));\n        }\n\n        [Fact]\n        public Task testRemove2() {\n            return createNremoveMtest(\"/testRemove2\", 10, 2);\n        }\n\n        [Fact]\n        public Task testRemove3() {\n            return createNremoveMtest(\"/testRemove3\", 1000, 1000);\n        }\n\n        private async Task createNremoveMelementTest(string dir, int n, int m) {\n            const string testString = \"Hello World\";\n            const int num_clients = 2;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            for (int i = 0; i < n; i++) {\n                string offerString = testString + i;\n                await queueHandles[0].offer(offerString.UTF8getBytes());\n            }\n\n            for (int i = 0; i < m; i++) {\n                await queueHandles[1].remove();\n            }\n            Assert.assertEquals((await queueHandles[1].element()).UTF8bytesToString(), testString + m);\n        }\n\n        [Fact]\n        public Task testElement1() {\n            return createNremoveMelementTest(\"/testElement1\", 1, 0);\n        }\n\n        [Fact]\n        public Task testElement2() {\n            return createNremoveMelementTest(\"/testElement2\", 10, 2);\n        }\n\n        [Fact]\n        public Task testElement3() {\n            return createNremoveMelementTest(\"/testElement3\", 1000, 500);\n        }\n\n        [Fact]\n        public Task testElement4() {\n            return createNremoveMelementTest(\"/testElement4\", 1000, 1000 - 1);\n        }\n\n        [Fact]\n        public async Task testTakeWait1() {\n            const string dir = \"/testTakeWait1\";\n            const string testString = \"Hello World\";\n            const int num_clients = 1;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n\n            byte[][] takeResult = new byte[1][];\n            Task takeTask = Task.Run(async ()=>{try {\n                  takeResult[0] = await queueHandles[0].take();\n                }\n                catch (KeeperException) {\n\n                }});\n            await Task.Delay(1000);\n            Task offerTask = Task.Run(async ()=>{\n                try {\n                    await queueHandles[0].offer(testString.UTF8getBytes());\n                }\n                catch (KeeperException) {\n\n                }});\n            await offerTask;\n\n            await takeTask;\n\n            Assert.assertTrue(takeResult[0] != null);\n            // ReSharper disable once AssignNullToNotNullAttribute\n            Assert.assertEquals(takeResult[0].UTF8bytesToString(), testString);\n        }\n\n        [Fact]\n        public async Task testTakeWait2() {\n            const string dir = \"/testTakeWait2\";\n            const string testString = \"Hello World\";\n            const int num_clients = 1;\n            ZooKeeper[] clients = new ZooKeeper[num_clients];\n            DistributedQueue[] queueHandles = new DistributedQueue[num_clients];\n            for (int i = 0; i < clients.Length; i++) {\n                clients[i] = await createClient();\n                queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n            }\n            const int num_attempts = 2;\n            for (int i = 0; i < num_attempts; i++) {\n                byte[][] takeResult = new byte[1][];\n                string threadTestString = testString + i;\n                Task takeTask = Task.Run(async() =>\n                {\n                    try {\n                        takeResult[0] = await queueHandles[0].take();\n                    }\n                    catch (KeeperException) {\n\n                    }\n                });\n\n                await Task.Delay(1000);\n                Task offerTask = Task.Run(async () =>\n                {\n                    try {\n                        await queueHandles[0].offer(threadTestString.UTF8getBytes());\n                    }\n                    catch (KeeperException) {\n\n                    }\n                });\n                await offerTask;\n\n                await takeTask;\n\n                Assert.assertTrue(takeResult[0] != null);\n                // ReSharper disable once AssignNullToNotNullAttribute\n                Assert.assertEquals(takeResult[0].UTF8bytesToString(), threadTestString);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/Assert.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing AssertXunit=Xunit.Assert;\n\nnamespace org.apache.zookeeper \n{\n    internal static class Assert\n    {\n        public static void assertTrue(bool test)\n        {\n            AssertXunit.True(test);\n        }\n        public static void assertTrue(string msg, bool test)\n        {\n            AssertXunit.True(test, msg);\n        }\n\n        public static void assertFalse(bool test)\n        {\n            AssertXunit.False(test);\n        }\n        public static void assertFalse(string msg, bool test)\n        {\n            AssertXunit.False(test, msg);\n        }\n\n        public static void assertNull(object obj)\n        {\n            AssertXunit.Null(obj);\n        }\n        public static void assertNull(string msg, object obj)\n        {\n            AssertXunit.True(obj == null, msg);\n        }\n\n        public static void assertNotNull(object obj)\n        {\n            AssertXunit.NotNull(obj);\n        }\n        public static void assertNotNull(string msg, object obj)\n        {\n            AssertXunit.True(obj != null, msg);\n        }\n\n        public static void fail()\n        {\n            AssertXunit.True(false);\n        }\n        public static void fail(string msg)\n        {\n            AssertXunit.True(false, msg);\n        }\n\n        public static void assertEquals(object a, object b)\n        {\n            string aJson = JsonConvert.SerializeObject(a);\n            string bJson = JsonConvert.SerializeObject(b);\n            AssertXunit.Equal(aJson, bJson);\n        }\n        public static void assertEquals(string msg, object a, object b)\n        {\n            string aJson = JsonConvert.SerializeObject(a);\n            string bJson = JsonConvert.SerializeObject(b);\n            AssertXunit.True(aJson == bJson, msg);\n        }\n        \n        public static void assertNotEquals<T>(T a, T b)\n        {\n            string aJson = JsonConvert.SerializeObject(a);\n            string bJson = JsonConvert.SerializeObject(b);\n            AssertXunit.NotEqual(aJson, bJson);\n        }\n\n        public static T poll<T>(this BlockingCollection<T> blockingCollection, int milliSeconds)\n        {\n            T item;\n            blockingCollection.TryTake(out item, milliSeconds);\n            return item;\n        }\n\n        public static async Task<bool> WithTimeout(this Task task, int millisecondsTimeout)\n        {\n            Task delayTask = Task.Delay(millisecondsTimeout);\n            await Task.WhenAny(task, delayTask).ConfigureAwait(false);\n            return !delayTask.IsCompleted;\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/BinaryInputArchiveTest.cs",
    "content": "using System.IO;\nusing org.apache.jute;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper\n{\n    public class BinaryInputArchiveTest\n    {\n\n        [Fact]\n        public void testReadStringCheckLength()\n        {\n            byte[] buf = {byte.MaxValue >> 1, byte.MaxValue, byte.MaxValue, byte.MaxValue};\n            BigEndianBinaryReader isz = new BigEndianBinaryReader(new MemoryStream(buf));\n            BinaryInputArchive ia = BinaryInputArchive.getArchive(isz);\n            try\n            {\n                ia.readString(\"\");\n                Assert.fail(\"Should have thrown an IOException\");\n            }\n            catch (IOException e)\n            {\n                Assert.assertTrue(\"Not 'Unreasonable length' exception: \" + e,\n                    e.Message.StartsWith(BinaryInputArchive.UNREASONBLE_LENGTH));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/ClientBase.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper \n{\n    [Collection(\"Setup\")]\n    public abstract class ClientBase:IAsyncLifetime {\n\n        protected static class Arrays {\n            public static List<T> asList<T>(params T[]objs) {\n                return new List<T>(objs);\n            }\n        }\n\n        public const int CONNECTION_TIMEOUT = 4000;\n        private string m_currentRoot;\n        private ZooKeeper m_rootZK;\n\n        private const string hostPort = \"127.0.0.1,localhost\";\n\n        private readonly ConcurrentBag<ZooKeeper> allClients = new ConcurrentBag<ZooKeeper>();\n        \n        protected Task<ZooKeeper> createClient(string chroot = null)\n        {\n            return createClient(NullWatcher.Instance, chroot);\n        }\n\n        protected async Task<ZooKeeper> createClient(Watcher watcher, string chroot=null)\n        {\n            if (watcher == null) watcher = NullWatcher.Instance;\n            var zk = new ZooKeeper(hostPort + m_currentRoot + chroot, CONNECTION_TIMEOUT, watcher);\n            allClients.Add(zk);\n            if (!await zk.connectedSignal.Task.WithTimeout(CONNECTION_TIMEOUT)) {\n                Assert.fail(\"Unable to connect to server\");\n            }\n\n            return zk;\n        }\n\n        public virtual async Task InitializeAsync()\n        {\n            m_rootZK = await createClient();\n            m_currentRoot = await m_rootZK.createAsync(\"/\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n        }\n        \n        public virtual async Task DisposeAsync()\n        {\n            await ZKUtil.deleteRecursiveAsync(m_rootZK, m_currentRoot);\n            await Task.WhenAll(allClients.Select(c => c.closeAsync()));\n        }\n\n        /// <summary>\n        ///     In general don't use this. Only use in the special case that you\n        ///     want to ignore results (for whatever reason) in your test. Don't\n        ///     use empty watchers in real code!\n        /// </summary>\n        public class NullWatcher : Watcher\n        {\n            public static readonly NullWatcher Instance = new NullWatcher();\n            private NullWatcher() { }\n            public override Task process(WatchedEvent @event)\n            {\n                return Task.CompletedTask;\n                // nada\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/LogAndConfigTests.cs",
    "content": "﻿using System;\nusing Xunit;\nusing org.apache.utils;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper;\nusing Assert = Xunit.Assert;\n\nnamespace ZooKeeperNetEx.Tests\n{\n    public class LogAndConfigTests\n    {\n        [Fact]\n        public async Task TestFileWriter()\n        {\n            string filename = Guid.NewGuid().ToString();\n            NonBlockingFileWriter writer = new NonBlockingFileWriter(filename);\n            await AssertInTimeout(() => File.Exists(filename) == false);\n            await AssertInTimeout(() => writer.HasFailed == false);\n            await AssertInTimeout(() => writer.IsEnabled);\n            await AssertInTimeout(() => writer.IsDisposed);\n            await AssertInTimeout(() => writer.IsEmpty);\n            for (int j = 0; j < 3; j++)\n            {\n                writer.IsEnabled = true;\n\n                for (int i = 0; i < 50; i++) writer.Write(\"test\" + i);\n                await AssertInTimeout(() => File.Exists(filename));\n                await AssertInTimeout(() => writer.HasFailed == false);\n                await AssertInTimeout(() => writer.IsEnabled);\n                await AssertInTimeout(() => writer.IsDisposed == false);\n                await AssertInTimeout(() => writer.IsEmpty);\n                \n                writer.IsEnabled = false;\n\n                for (int i = 0; i < 50; i++) writer.Write(\"test\" + i);\n                await AssertInTimeout(() => writer.HasFailed == false);\n                await AssertInTimeout(() => writer.IsEnabled == false);\n                await AssertInTimeout(() => writer.IsDisposed);\n                await AssertInTimeout(() => writer.IsEmpty);\n\n                File.Delete(filename);\n\n                writer.Write(\"should not write\");\n                await AssertInTimeout(() => writer.HasFailed == false);\n                await AssertInTimeout(() => writer.IsEnabled == false);\n                await AssertInTimeout(() => writer.IsDisposed);\n                await AssertInTimeout(() => writer.IsEmpty);\n            }\n            var cancellationTokenSource = new CancellationTokenSource();\n            var token = cancellationTokenSource.Token;\n            var concurrentWrites = new[]\n            {\n                CreateWriteTask(token, writer), CreateWriteTask(token, writer), CreateWriteTask(token, writer),\n                CreateWriteTask(token, writer)\n            };\n\n            for (int i = 0; i < 3; i++)\n            {\n                writer.IsEnabled = true;\n                await Task.Delay(50);\n                writer.IsEnabled = false;\n                await AssertInTimeout(() => writer.HasFailed == false);\n                await AssertInTimeout(() => writer.IsEnabled == false);\n                await AssertInTimeout(() => writer.IsDisposed);\n                await AssertInTimeout(() => writer.IsEmpty);\n            }\n\n            writer.IsEnabled = true;\n            writer.ThrowWrite = true;\n            await AssertInTimeout(() => writer.HasFailed);\n            await AssertInTimeout(() => writer.IsEnabled);\n            await AssertInTimeout(() => writer.IsDisposed);\n            cancellationTokenSource.Cancel();\n            await Task.WhenAll(concurrentWrites);\n            await AssertInTimeout(() => writer.IsEmpty);\n\n            File.Delete(filename);\n            writer.Write(\"should not write\");\n            Assert.False(File.Exists(filename));\n        }\n\n        private async Task AssertInTimeout(Func<bool> assertion)\n        {\n            for (int i = 0; i < 300 && !assertion(); i++)\n                await Task.Delay(100);\n\n            Assert.True(assertion());\n        }\n\n        private Task CreateWriteTask(CancellationToken cancellationToken, NonBlockingFileWriter writer)\n        {\n            return Task.Run(async () =>\n            {\n                int i = 0;\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    writer.Write(\"test\" + i);\n                    await Task.Delay(i%50 + 10);\n                    i++;\n                }\n            });\n        }\n\n        [Fact]\n        public void TestCustomConsumer()\n        {\n            bool logToFile = ZooKeeper.LogToFile;\n            ZooKeeper.LogToFile = false;\n            var dummy = new DummyConsumer();\n            ILogProducer log = TypeLogger<LogAndConfigTests>.Instance;\n            ZooKeeper.CustomLogConsumer = dummy;\n            log.warn(\"test\");\n            Assert.True(dummy.called);\n            dummy.called = false;\n            ZooKeeper.CustomLogConsumer = null;\n            log.warn(\"test\");\n            Assert.False(dummy.called);\n            ZooKeeper.LogToFile = logToFile;\n        }\n\n        private class DummyConsumer : ILogConsumer\n        {\n            public bool called;\n            public void Log(TraceLevel severity, string className, string message, Exception exception)\n            {\n                if (className == \"LogAndConfigTests\")\n                    called = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/MultiResponseTest.cs",
    "content": "using System.IO;\nusing org.apache.jute;\nusing org.apache.utils;\nusing org.apache.zookeeper.data;\nusing Xunit;\n\nnamespace org.apache.zookeeper\n{\n    public sealed class MultiResponseTest : ClientBase\n\t{\n        [Fact]\n\t\tpublic void testRoundTrip()\n\t\t{\n\t\t\tMultiResponse response = new MultiResponse();\n\n\t\t\tresponse.add(new OpResult.CheckResult());\n\t\t\tresponse.add(new OpResult.CreateResult(\"foo-bar\"));\n\t\t\tresponse.add(new OpResult.DeleteResult());\n\n\t\t\tStat s = new Stat();\n\t\t\ts.setCzxid(546);\n\t\t\tresponse.add(new OpResult.SetDataResult(s));\n\n\t\t\tMultiResponse decodedResponse = codeDecode(response);\n\n\t\t\tAssert.assertEquals(response, decodedResponse);\n\t\t}\n\n        [Fact]\n\t\tpublic void testEmptyRoundTrip()\n\t\t{\n\t\t\tMultiResponse result = new MultiResponse();\n\t\t\tMultiResponse decodedResult = codeDecode(result);\n\n            Assert.assertEquals(result, decodedResult);\n\t\t}\n\n\t\tprivate static MultiResponse codeDecode(MultiResponse request)\n\t\t{\n            var ms = new MemoryStream();\n            BigEndianBinaryWriter baos = new BigEndianBinaryWriter(ms);\n\t\t\tBinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n            request.serialize(boa, \"result\");\n\t\t    ms.Position = 0;\n\n\t\t    BinaryInputArchive bia = BinaryInputArchive.getArchive(new BigEndianBinaryReader(ms));\n            MultiResponse decodedRequest = new MultiResponse();\n            decodedRequest.deserialize(bia, \"result\");\n\t\t\treturn decodedRequest;\n\t\t}\n\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/MultiTransactionRecordTest.cs",
    "content": "using System.IO;\nusing org.apache.jute;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper\n{\n    public sealed class MultiTransactionRecordTest : ClientBase\n\t{\n        [Fact]\n\t\tpublic void testRoundTrip()\n\t\t{\n\t\t\tMultiTransactionRecord request = new MultiTransactionRecord();\n\t\t\trequest.add(Op.check(\"check\", 1));\n\t\t\trequest.add(Op.create(\"create\", \"create data\".UTF8getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, (int) ZooDefs.Perms.ALL));\n\t\t\trequest.add(Op.delete(\"delete\", 17));\n\t\t\trequest.add(Op.setData(\"setData\", \"set data\".UTF8getBytes(), 19));\n\n\t\t\tMultiTransactionRecord decodedRequest = codeDecode(request);\n\n\t\t\tAssert.assertEquals(request, decodedRequest);\n\t\t}\n\n        [Fact]\n\t\tpublic void testEmptyRoundTrip()\n\t\t{\n\t\t\tMultiTransactionRecord request = new MultiTransactionRecord();\n\t\t\tMultiTransactionRecord decodedRequest = codeDecode(request);\n\n            Assert.assertEquals(request, decodedRequest);\n\t\t}\n\n\t\tprivate MultiTransactionRecord codeDecode(MultiTransactionRecord request) {\n\t\t    var ms = new MemoryStream();\n            BigEndianBinaryWriter baos = new BigEndianBinaryWriter(ms);\n\t\t\tBinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n\t\t\trequest.serialize(boa, \"request\");\n\t\t    ms.Position = 0;\n\n\t\t    BinaryInputArchive bia = BinaryInputArchive.getArchive(new BigEndianBinaryReader(ms));\n\t\t\tMultiTransactionRecord decodedRequest = new MultiTransactionRecord();\n\t\t\tdecodedRequest.deserialize(bia, \"request\");\n\t\t\treturn decodedRequest;\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ZooKeeperNetEx.Recipes.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100416f66004a1fd058e5d6d0756c8bcc429965b3fd20c74901d5a4b0d69c53885a32cfd82343f0452145534caa6ee14074f885f173dddda29ab9bdad17e32e2ae1306d3b651a087e030b70caefcf6f2c91a3e1930c519507638581c5d06612a953ca879111b5383aebc452067a800b014cae8c6a4bf2c9ed71f6159d04620d1ad5\")]"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/TestsSetup.cs",
    "content": "using Xunit;\n\nnamespace org.apache.zookeeper\n{\n    public class TestsSetup\n    {\n        static TestsSetup()\n        {\n            ZooKeeper.LogToFile = false;\n            ZooKeeper.LogToTrace = false;\n        }\n    }\n\n    [CollectionDefinition(\"Setup\")]\n    public class SetupCollection : ICollectionFixture<TestsSetup>\n    {\n        // This class has no code, and is never created. Its purpose is simply\n        // to be the place to apply [CollectionDefinition] and all the\n        // ICollectionFixture<> interfaces.\n    }\n}\n"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/ZooKeeperNetEx.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <AssemblyName>ZooKeeperNetEx.Tests</AssemblyName>\r\n  </PropertyGroup>\r\n\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\..\\src\\ZooKeeperNetEx\\ZooKeeperNetEx.csproj\" />\r\n  </ItemGroup>\r\n\r\n  <ProjectExtensions><VisualStudio><UserProperties __JSONSchema=\"https://xunit.github.io/schema/v2.4-beta1/xunit.runner.schema.json\" /></VisualStudio></ProjectExtensions>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/ZooKeeperTest.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper\n{\n\t/// <summary>\n\t/// Testing Zookeeper public methods\n\t/// </summary>\n\tpublic class ZooKeeperTest : ClientBase\n\t{\n        [Fact]\n\t\tpublic async Task testDeleteRecursive()\n\t\t{\n\t\t\tZooKeeper zk = await createClient();\n\t\t\t// making sure setdata works on /\n            await zk.setDataAsync(\"/\", \"some\".UTF8getBytes(), -1);\n            await zk.createAsync(\"/a\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk.createAsync(\"/a/b\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk.createAsync(\"/a/b/v\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk.createAsync(\"/a/b/v/1\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk.createAsync(\"/a/c\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk.createAsync(\"/a/c/v\", \"some\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n\t\t\tIList<string> children = (await zk.getChildrenAsync(\"/a\", false)).Children;\n\n            Assert.assertEquals(\"2 children - b & c should be present \", children.Count, 2);\n            Assert.assertTrue(children.Contains(\"b\"));\n            Assert.assertTrue(children.Contains(\"c\"));\n\n            ZKUtil.deleteRecursiveAsync(zk, \"/a\").GetAwaiter().GetResult();\n            Assert.assertNull(await zk.existsAsync(\"/a\", null));\n\t\t}\n\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ACLCountTest.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class ACLCountTest : ClientBase\n\t{\n\t\t/// \n\t\t/// <summary>\n\t\t/// Create a node and add 4 ACL values to it, but there are only 2 unique ACL values,\n\t\t/// and each is repeated once:\n\t\t/// \n\t\t///   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);\n\t\t///   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);\n\t\t///   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);\n\t\t///   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);\n\t\t/// \n\t\t/// Even though we've added 4 ACL values, there should only be 2 ACLs for that node,\n\t\t/// since there are only 2 *unique* ACL values.\n\t\t/// </summary>\n\n        [Fact]\n\t\tpublic async Task testAclCount() {\n\n\t\t    List<ACL> CREATOR_ALL_AND_WORLD_READABLE = new List<ACL>\n\t\t    {\n\t\t        new ACL((int) ZooDefs.Perms.READ, ZooDefs.Ids.ANYONE_ID_UNSAFE),\n\t\t        new ACL((int) ZooDefs.Perms.ALL, ZooDefs.Ids.AUTH_IDS),\n\t\t        new ACL((int) ZooDefs.Perms.READ, ZooDefs.Ids.ANYONE_ID_UNSAFE),\n\t\t        new ACL((int) ZooDefs.Perms.ALL, ZooDefs.Ids.AUTH_IDS)\n\t\t    };\n\t\t        var zk = await createClient();\n\n\t\t        zk.addAuthInfo(\"digest\", \"pat:test\".UTF8getBytes());\n\t\t        await zk.setACLAsync(\"/\", ZooDefs.Ids.CREATOR_ALL_ACL, -1);\n\n\t\t        await zk.createAsync(\"/path\", \"/path\".UTF8getBytes(), CREATOR_ALL_AND_WORLD_READABLE, CreateMode.PERSISTENT);\n\t\t        IList<ACL> acls = (await zk.getACLAsync(\"/path\")).Acls;\n\t\t        Assert.assertEquals(2, acls.Count);\n\t\t        await zk.setACLAsync(\"/\", ZooDefs.Ids.OPEN_ACL_UNSAFE, -1);\n                await zk.setACLAsync(\"/path\", ZooDefs.Ids.OPEN_ACL_UNSAFE, -1);\n\t\t}\n\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ACLRootTest.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class ACLRootTest : ClientBase\n\t{\n        [Fact]\n\t\tpublic async Task testRootAcl()\n\t\t{\n\t\t\tvar zk = await createClient();\n\t\t\t\t// set auth using digest\n\t\t\t\tzk.addAuthInfo(\"digest\", \"pat:test\".UTF8getBytes());\n\t\t\t\tawait zk.setACLAsync(\"/\", ZooDefs.Ids.CREATOR_ALL_ACL, -1);\n\t\t\t\tawait zk.getDataAsync(\"/\", false);\n                await zk.closeAsync();\n\t\t\t\t// verify no access\n\t\t\t\tzk = await createClient();\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zk.getDataAsync(\"/\", false);\n\t\t\t\t\tAssert.fail(\"validate auth\");\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoAuthException)\n\t\t\t\t{\n\t\t\t\t\t// expected\n\t\t\t\t}\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n\t\t\t\t\tAssert.fail(\"validate auth\");\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.InvalidACLException)\n\t\t\t\t{\n\t\t\t\t\t// expected\n\t\t\t\t}\n\t\t\t\tzk.addAuthInfo(\"digest\", \"world:anyone\".UTF8getBytes());\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n\t\t\t\t\tAssert.fail(\"validate auth\");\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoAuthException)\n\t\t\t\t{\n\t\t\t\t\t// expected\n\t\t\t\t}\n                await zk.closeAsync();\n\t\t\t\t// verify access using original auth\n\t\t\t\tzk = await createClient();\n\t\t\t\tzk.addAuthInfo(\"digest\", \"pat:test\".UTF8getBytes());\n\t\t\t\tawait zk.getDataAsync(\"/\", false);\n\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n\t\t\t\tawait zk.deleteAsync(\"/apps\", -1);\n\t\t\t\t// reset acl (back to open) and verify accessible again\n\t\t\t\tawait zk.setACLAsync(\"/\", ZooDefs.Ids.OPEN_ACL_UNSAFE, -1);\n                await zk.closeAsync();\n\n                zk = await createClient();\n\t\t\t\tawait zk.getDataAsync(\"/\", false);\n\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n\t\t\t\t\tAssert.fail(\"validate auth\");\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.InvalidACLException)\n\t\t\t\t{\n\t\t\t\t\t// expected\n\t\t\t\t}\n\t\t\t\tawait zk.deleteAsync(\"/apps\", -1);\n\t\t\t\tzk.addAuthInfo(\"digest\", \"world:anyone\".UTF8getBytes());\n\t\t\t\tawait zk.createAsync(\"/apps\", null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n                await zk.closeAsync();\n\n                zk = await createClient();\n\t\t\t\tawait zk.deleteAsync(\"/apps\", -1);\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ChrootTest.cs",
    "content": "using System.Threading.Tasks;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class ChrootTest : ClientBase\n\t{\n\t\tprivate sealed class MyWatcher : Watcher\n\t\t{\n            private static readonly ILogProducer LOG = TypeLogger<Watcher>.Instance;\n            private readonly string path;\n\t\t    private string eventPath;\n\t\t    private readonly TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();\n\n\t\t\tpublic MyWatcher(string path)\n\t\t\t{\n\t\t\t\tthis.path = path;\n\t\t\t}\n\t\t\tpublic override Task process(WatchedEvent @event)\n\t\t\t{\n                LOG.debug(\"latch:\" + path + \" \" + @event.getPath());\n\t\t\t\teventPath = @event.getPath();\n                taskCompletionSource.TrySetResult(true);\n\t\t\t    return Task.CompletedTask;\n\t\t\t}\n\n\n\t\t    public async Task<bool> matches()\n\t\t    {\n\t\t        if (await taskCompletionSource.Task.WithTimeout(CONNECTION_TIMEOUT) == false)\n\t\t        {\n\t\t            Assert.fail(\"No watch received within timeout period \" + path);\n\t\t        }\n\t\t        return path.Equals(eventPath);\n\t\t    }\n\t\t}\n\n\n\n        [Fact]\n\t\tpublic async Task testChrootSynchronous()\n\t\t{\n\t\t\tZooKeeper zk1 = await createClient();\n\n\t\t\t\tawait zk1.createAsync(\"/ch1\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            await zk1.closeAsync();\n\n            ZooKeeper zk2 = await createClient(\"/ch1\");\n\n\t\t\t\tAssert.assertEquals(\"/ch2\", await zk2.createAsync(\"/ch2\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT));\n\n            await zk2.closeAsync();\n\n            zk1 = await createClient();\n\t\t\tzk2 = await createClient(\"/ch1\");\n\n\t\t\t\t// check get\n\t\t\t\tMyWatcher w1 = new MyWatcher(\"/ch1\");\n\t\t\t\tAssert.assertNotNull(await zk1.existsAsync(\"/ch1\", w1));\n\t\t\t\tMyWatcher w2 = new MyWatcher(\"/ch1/ch2\");\n\t\t\t\tAssert.assertNotNull(await zk1.existsAsync(\"/ch1/ch2\", w2));\n\n\t\t\t\tMyWatcher w3 = new MyWatcher(\"/ch2\");\n\t\t\t\tAssert.assertNotNull(await zk2.existsAsync(\"/ch2\", w3));\n\n\t\t\t\t// set watches on child\n\t\t\t\tMyWatcher w4 = new MyWatcher(\"/ch1\");\n\t\t\t\tawait zk1.getChildrenAsync(\"/ch1\",w4);\n\t\t\t\tMyWatcher w5 = new MyWatcher(\"/\");\n\t\t\t\tawait zk2.getChildrenAsync(\"/\",w5);\n\n\t\t\t\t// check set\n\t\t\t\tawait zk1.setDataAsync(\"/ch1\", \"1\".UTF8getBytes(), -1);\n\t\t\t\tawait zk2.setDataAsync(\"/ch2\", \"2\".UTF8getBytes(), -1);\n\n\t\t\t\t// check watches\n\t\t\t\tAssert.assertTrue(await w1.matches());\n\t\t\t\tAssert.assertTrue(await w2.matches());\n\t\t\t\tAssert.assertTrue(await w3.matches());\n\n\t\t\t\t// check exceptions\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tawait zk2.setDataAsync(\"/ch3\", \"3\".UTF8getBytes(), -1);\n\t\t\t\t}\n\t\t\t\tcatch (KeeperException.NoNodeException e)\n\t\t\t\t{\n\t\t\t\t\tAssert.assertEquals(\"/ch3\", e.getPath());\n\t\t\t\t}\n\n                Assert.assertEquals(\"1\".UTF8getBytes(), (await zk1.getDataAsync(\"/ch1\", false)).Data);\n\t\t\t\tAssert.assertEquals(\"2\".UTF8getBytes(), (await zk1.getDataAsync(\"/ch1/ch2\", false)).Data);\n\t\t\t\tAssert.assertEquals(\"2\".UTF8getBytes(), (await zk2.getDataAsync(\"/ch2\", false)).Data);\n\n                // check delete\n                await zk2.deleteAsync(\"/ch2\", -1);\n\t\t\t\tAssert.assertTrue(await w4.matches());\n\t\t\t\tAssert.assertTrue(await w5.matches());\n\n\t\t\t\tawait zk1.deleteAsync(\"/ch1\", -1);\n\t\t\t\tAssert.assertNull(await zk1.existsAsync(\"/ch1\", false));\n\t\t\t\tAssert.assertNull(await zk1.existsAsync(\"/ch1/ch2\", false));\n\t\t\t\tAssert.assertNull(await zk2.existsAsync(\"/ch2\", false));\n\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ClientHammerTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class ClientHammerTest : ClientBase\n\t{\n\t\tprivate static readonly ILogProducer LOG = TypeLogger<ClientHammerTest>.Instance;\n        private static readonly byte[] b = new byte[256];\n\n        private const int HAMMERTHREAD_LATENCY = 5;\n\n        private async Task GetBasicHammerTask(string prefix, int count)\n        {\n            ZooKeeper zk = await createClient();\n            for (int current = 0; current < count; current++)\n            {\n                // Simulate a bit of network latency...\n                await Task.Delay(HAMMERTHREAD_LATENCY);\n                await zk.createAsync(prefix + current, b, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                LOG.warn(\"created:\" + prefix + current);\n            }\n            await zk.closeAsync();\n        }\n\n        private async Task GetSuperHammerTask(string prefix, int count)\n        {\n            for (int current = 0; current < count; current++)\n            {\n                ZooKeeper zk = await createClient();\n                await zk.createAsync(prefix + current, b, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                await zk.closeAsync();\n                LOG.warn(\"created:\" + prefix + current);\n            }\n        }\n\n\n        // <summary>\n\t\t// Separate tasks each creating a number of nodes. Each task\n\t\t// is using a non-shared (owned by task) client for all node creations. </summary>\n        [Fact]\n        public async Task testHammerBasic()\n        {\n            int threadCount = 10;\n            int childCount = 1000;\n            Task[] tasks = new Task[threadCount];\n            for (int i = 0; i < tasks.Length; i++)\n            {\n                ZooKeeper zk = await createClient();\n                string prefix = \"/test-\" + i;\n                await zk.createAsync(prefix, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                await zk.closeAsync();\n                LOG.warn(\"created:\" + prefix);\n                prefix += \"/\";\n                tasks[i] = GetBasicHammerTask(prefix, childCount);\n            }\n\n            await verifyHammer(tasks, childCount);\n        }\n\n        // <summary>\n\t\t// Separate tasks each creating a number of nodes. Each task\n\t\t// is creating a new client for each node creation. </summary>\n        [Fact]\n        public async Task testHammerSuper()\n        {\n            const int threadCount = 5;\n            const int childCount = 10;\n\n            Task[] tasks = new Task[threadCount];\n            for (int i = 0; i < tasks.Length; i++)\n            {\n                string prefix = \"/test-\" + i;\n                ZooKeeper zk = await createClient();\n                await zk.createAsync(prefix, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                await zk.closeAsync();\n                LOG.warn(\"created:\" + prefix);\n                prefix += \"/\";\n                tasks[i] = GetSuperHammerTask(prefix, childCount);\n            }\n\n            await verifyHammer(tasks, childCount);\n        }\n\n\n        private async Task verifyHammer(Task[] tasks, int childCount)\n\t\t{\n\t\t\t// look for the clients to finish their create operations\n\t\t\tLOG.warn(\"Starting check for completed hammers\");\n\t\t\tAssert.assertTrue(await Task.WhenAll(tasks).WithTimeout(40000));\n            \n\t\t\tZooKeeper zk = await createClient();\n\t        for (int i = 0; i < tasks.Length; i++)\n\t        {\n\t            LOG.info(\"Doing task: \" + i + \" \" + DateTime.Now);\n\t            IList<string> children = (await zk.getChildrenAsync(\"/test-\" + i, false)).Children;\n\t            Assert.assertEquals(childCount, children.Count);\n\t        }\n            LOG.warn(\"Done\");\n        }\n\t}\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ClientTest.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing org.apache.zookeeper.data;\nusing org.apache.zookeeper.proto;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test {\n   \n    public sealed class ClientTest : ClientBase {\n        private static readonly ILogProducer LOG = TypeLogger<ClientTest>.Instance;\n\n        /// <summary>\n        /// Verify that pings are sent, keeping the \"idle\" client alive </summary>\n        [Fact]\n        public async Task testPing() {\n                ZooKeeper zkIdle = await createClient();\n\n                ZooKeeper zkWatchCreator = await createClient();\n\n                for (int i = 0; i < 10; i++) {\n                    await zkWatchCreator.createAsync(\"/\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, \n                        CreateMode.PERSISTENT);\n            }\n                for (int i = 0; i < 10; i++) {\n                    await zkIdle.existsAsync(\"/\" + i, true);\n                }\n                for (int i = 0; i < 10; i++) {\n                    await Task.Delay(1000);\n                    await zkWatchCreator.deleteAsync(\"/\" + i, -1);\n                }\n                // The bug will manifest itself here because zkIdle will expire\n                await zkIdle.existsAsync(\"/0\", false);\n        }\n\n\n\n        [Fact]\n        public Task testClientwithoutWatcherObj() {\n            return performClientTest(false);\n        }\n\n\n\n        [Fact]\n        public Task testClientWithWatcherObj() {\n            return performClientTest(true);\n        }\n        \n\n        [Fact]\n        public async Task testACLs() {\n            ZooKeeper zk = await createClient();\n                try {\n                    await zk.createAsync(\"/acltest\", new byte[0], ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n                    Assert.fail(\"Should have received an invalid acl error\");\n                } catch (KeeperException.InvalidACLException e) {\n                    LOG.info(\"Test successful, invalid acl received : \" \n                        + e.Message);\n            \t}\n                try {\n                    List<ACL> testACL = new List<ACL>();\n                    testACL.Add(new ACL((int) (ZooDefs.Perms.ALL | ZooDefs.Perms.ADMIN), ZooDefs.Ids.AUTH_IDS));\n                    testACL.Add(new ACL((int) (ZooDefs.Perms.ALL | ZooDefs.Perms.ADMIN), new Id(\"ip\", \"127.0.0.1/8\")));\n                    await zk.createAsync(\"/acltest\", new byte[0], testACL, CreateMode.PERSISTENT);\n                    Assert.fail(\"Should have received an invalid acl error\");\n                } catch (KeeperException.InvalidACLException e) {\n                    LOG.info(\"Test successful, invalid acl received : \" \n                        + e.Message);\n            }\n                zk.addAuthInfo(\"digest\", \"ben:passwd\".UTF8getBytes());\n                await zk.createAsync(\"/acltest\", new byte[0], ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n                await zk.closeAsync();\n\n                zk = await createClient();\n                zk.addAuthInfo(\"digest\", \"ben:passwd2\".UTF8getBytes());\n                try {\n                    await zk.getDataAsync(\"/acltest\", false);\n                    Assert.fail(\"Should have received a permission error\");\n                } catch (KeeperException e) {\n                    Assert.assertEquals(KeeperException.Code.NOAUTH, e.getCode());\n                }\n                zk.addAuthInfo(\"digest\", \"ben:passwd\".UTF8getBytes());\n                await zk.getDataAsync(\"/acltest\", false);\n                await zk.setACLAsync(\"/acltest\", ZooDefs.Ids.OPEN_ACL_UNSAFE, -1);\n                await zk.closeAsync();\n\n                zk = await createClient();\n                await zk.getDataAsync(\"/acltest\", false);\n                IList<ACL> acls = (await zk.getACLAsync(\"/acltest\")).Acls;\n                Assert.assertEquals(1, acls.Count);\n                Assert.assertEquals(ZooDefs.Ids.OPEN_ACL_UNSAFE, acls);\n\n                // The stat parameter should be optional.\n                acls = (await zk.getACLAsync(\"/acltest\")).Acls;\n                Assert.assertEquals(1, acls.Count);\n                Assert.assertEquals(ZooDefs.Ids.OPEN_ACL_UNSAFE, acls);\n        }\n\n        private class MyWatcher : Watcher {\n            internal readonly BlockingCollection<WatchedEvent> events = new BlockingCollection<WatchedEvent>();\n\n            public override Task process(WatchedEvent @event) {\n                if (@event.get_Type() != Event.EventType.None) {\n                    events.Add(@event);\n                }\n                return Task.CompletedTask;\n            }\n        }\n\n        /// <summary>\n        /// Register multiple watchers and verify that they all get notified and\n        /// in the right order.\n        /// </summary>\n        [Fact]\n        public async Task testMutipleWatcherObjs() \n\t\t{\n            ZooKeeper zk = await createClient();\n                MyWatcher[] watchers = new MyWatcher[100];\n                MyWatcher[] watchers2 = new MyWatcher[watchers.Length];\n                for (int i = 0; i < watchers.Length; i++) {\n                    watchers[i] = new MyWatcher();\n                    watchers2[i] = new MyWatcher();\n                    await zk.createAsync(\"/foo-\" + i, (\"foodata\" + i).UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n                }\n\n                //\n                // test get/exists with single set of watchers\n                //   get all, then exists all\n                //\n                for (int i = 0; i < watchers.Length; i++) {\n                    Assert.assertNotNull((await zk.getDataAsync(\"/foo-\" + i, watchers[i])).Data);\n            }\n                for (int i = 0; i < watchers.Length; i++) {\n                    Assert.assertNotNull(await zk.existsAsync(\"/foo-\" + i, watchers[i]));\n                }\n                // trigger the watches\n                for (int i = 0; i < watchers.Length; i++) {\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata2-\" + i).UTF8getBytes(), -1);\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata3-\" + i).UTF8getBytes(), -1);\n                }\n                for (int i = 0; i < watchers.Length; i++) {\n                    WatchedEvent @event = \n\t\t\t\t\t    watchers[i].events.poll(10 * 1000);\n                    Assert.assertEquals(\"/foo-\" + i, @event.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, @event.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n\n                    // small chance that an unexpected message was delivered\n                    //  after this check, but we would catch that next time\n                    //  we check events\n                    Assert.assertEquals(0, watchers[i].events.size());\n                }\n\n                //\n                // test get/exists with single set of watchers\n                //  get/exists together\n                //\n                for (int i = 0; i < watchers.Length; i++) {\n                    Assert.assertNotNull((await zk.getDataAsync(\"/foo-\" + i, watchers[i])).Data);\n                Assert.assertNotNull(await zk.existsAsync(\"/foo-\" + i, watchers[i]));\n                }\n                // trigger the watches\n                for (int i = 0; i < watchers.Length; i++) {\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata4-\" + i).UTF8getBytes(), -1);\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata5-\" + i).UTF8getBytes(), -1);\n                }\n                for (int i = 0; i < watchers.Length; i++) {\n                    WatchedEvent @event = \n\t\t\t\t\t    watchers[i].events.poll(10 * 1000);\n                    Assert.assertEquals(\"/foo-\" + i, @event.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, @event.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n\n                    // small chance that an unexpected message was delivered\n                    //  after this check, but we would catch that next time\n                    //  we check events\n                    Assert.assertEquals(0, watchers[i].events.size());\n                }\n\n                //\n                // test get/exists with two sets of watchers\n                //\n                for (int i = 0; i < watchers.Length; i++) {\n                    Assert.assertNotNull((await zk.getDataAsync(\"/foo-\" + i, watchers[i])).Data);\n                Assert.assertNotNull(await zk.existsAsync(\"/foo-\" + i, watchers2[i]));\n                }\n                // trigger the watches\n                for (int i = 0; i < watchers.Length; i++) {\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata6-\" + i).UTF8getBytes(), -1);\n                    await zk.setDataAsync(\"/foo-\" + i, (\"foodata7-\" + i).UTF8getBytes(), -1);\n                }\n                for (int i = 0; i < watchers.Length; i++) {\n                    WatchedEvent @event = \n\t\t\t\t\t    watchers[i].events.poll(10 * 1000);\n                    Assert.assertEquals(\"/foo-\" + i, @event.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, @event.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n\n                    // small chance that an unexpected message was delivered\n                    //  after this check, but we would catch that next time\n                    //  we check events\n                    Assert.assertEquals(0, watchers[i].events.size());\n\n                    // watchers2\n                    WatchedEvent event2 = \n\t\t\t\t\t    watchers2[i].events.poll(10 * 1000);\n                    Assert.assertEquals(\"/foo-\" + i, event2.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, event2.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, event2.getState());\n\n                    // small chance that an unexpected message was delivered\n                    //  after this check, but we would catch that next time\n                    //  we check events\n                    Assert.assertEquals(0, watchers2[i].events.size());\n                }\n        }\n\n\n        private async Task performClientTest(bool withWatcherObj) \n\t\t{\n            ZooKeeper zk = null;\n                MyWatcher watcher = new MyWatcher();\n                zk = await createClient(watcher);\n                LOG.info(\"Before create /benwashere\");\n                await zk.createAsync(\"/benwashere\", \"\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                LOG.info(\"After create /benwashere\");\n                try {\n                    await zk.setDataAsync(\"/benwashere\", \"hi\".UTF8getBytes(), 57);\n                    Assert.fail(\"Should have gotten BadVersion exception\");\n                } catch (KeeperException.BadVersionException) {\n                    // expected that\n                } catch (KeeperException) {\n                    Assert.fail(\"Should have gotten BadVersion exception\");\n                }\n                LOG.info(\"Before delete /benwashere\");\n                await zk.deleteAsync(\"/benwashere\", 0);\n                LOG.info(\"After delete /benwashere\");\n                //LOG.info(\"Closed client: \" + zk.describeCNXN());\n                await Task.Delay(2000);\n\n                zk = await createClient(watcher);\n                //LOG.info(\"Created a new client: \" + zk.describeCNXN());\n                LOG.info(\"Before delete /\");\n\n                try {\n                    await zk.deleteAsync(\"/\", -1);\n                    Assert.fail(\"deleted root!\");\n                } catch (KeeperException.BadArgumentsException) {\n                    // good, expected that\n                }\n\n                // Test basic create, ls, and getData\n                await zk.createAsync(\"/pat\", \"Pat was here\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                LOG.info(\"Before create /ben\");\n                await zk.createAsync(\"/pat/ben\", \"Ben was here\".UTF8getBytes(), \n\t\t\t\t      ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                LOG.info(\"Before getChildren /pat\");\n                List<string> children = (await zk.getChildrenAsync(\"/pat\", false)).Children;\n                Assert.assertEquals(1, children.Count);\n                Assert.assertEquals(\"ben\", children[0]);\n                IList<string> children2 = (await zk.getChildrenAsync(\"/pat\", false)).Children;\n                Assert.assertEquals(children, children2);\n                Assert.assertEquals(\"Ben was here\", (await zk.getDataAsync(\"/pat/ben\", false)).Data.UTF8bytesToString());\n                // Test stat and watch of non existent node\n\n                try {\n                    if (withWatcherObj) {\n                        Assert.assertEquals(null, await zk.existsAsync(\"/frog\", watcher));\n                    } else {\n                        Assert.assertEquals(null, await zk.existsAsync(\"/frog\", true));\n                    }\n                    LOG.info(\"Comment: asseting passed for frog setting /\");\n                } catch (KeeperException.NoNodeException) {\n                    // OK, expected that\n                }\n                await zk.createAsync(\"/frog\", \"hi\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                // the first poll is just a session delivery\n                LOG.info(\"Comment: checking for events length \" \n\t\t\t\t\t\t + watcher.events.size());\n                WatchedEvent @event = watcher.events.poll(10 * 1000);\n                Assert.assertEquals(\"/frog\", @event.getPath());\n                Assert.assertEquals(Watcher.Event.EventType.NodeCreated, @event.get_Type());\n                Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n                // Test child watch and create with sequence\n                await zk.getChildrenAsync(\"/pat/ben\", true);\n                for (int i = 0; i < 10; i++) {\n                    await zk.createAsync(\"/pat/ben/\" + i + \"-\", Convert.ToString(i).UTF8getBytes(), \n\t\t\t\t\t\t\t\t  ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                }\n                children = (await zk.getChildrenAsync(\"/pat/ben\", false)).Children;\n                children.Sort();\n                Assert.assertEquals(10, children.Count);\n                for (int i = 0; i < 10; i++) {\n                    string name = children[i];\n                    Assert.assertTrue(\"starts with -\", name.StartsWith(i + \"-\", StringComparison.Ordinal));\n                    DataResult dataResult;\n                    if (withWatcherObj) {\n                        dataResult = await zk.getDataAsync(\"/pat/ben/\" + name, watcher);\n                    } else {\n                        dataResult = await zk.getDataAsync(\"/pat/ben/\" + name, true);\n                    }\n                    Assert.assertEquals(i, int.Parse(dataResult.Data.UTF8bytesToString()));\n                    await zk.setDataAsync(\"/pat/ben/\" + name, \"new\".UTF8getBytes(), \n\t\t\t\t\t              dataResult.Stat.getVersion());\n                    Stat stat;\n                    if (withWatcherObj) {\n                        stat = await zk.existsAsync(\"/pat/ben/\" + name, watcher);\n                    } else {\n                        stat = await zk.existsAsync(\"/pat/ben/\" + name, true);\n                    }\n                    await zk.deleteAsync(\"/pat/ben/\" + name, stat.getVersion());\n                }\n                @event = watcher.events.poll(10 * 1000);\n                Assert.assertEquals(\"/pat/ben\", @event.getPath());\n                Assert.assertEquals(Watcher.Event.EventType.NodeChildrenChanged, @event.get_Type());\n                Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n                for (int i = 0; i < 10; i++) {\n                    @event = watcher.events.poll(10 * 1000);\n                    string name = children[i];\n                    Assert.assertEquals(\"/pat/ben/\" + name, @event.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, @event.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n                    @event = watcher.events.poll(10 * 1000);\n                    Assert.assertEquals(\"/pat/ben/\" + name, @event.getPath());\n                    Assert.assertEquals(Watcher.Event.EventType.NodeDeleted, @event.get_Type());\n                    Assert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n                }\n                await zk.createAsync(\"/good\\u0040path\", \"\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n\n                await zk.createAsync(\"/duplicate\", \"\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                try {\n                    await zk.createAsync(\"/duplicate\", \"\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t\t              CreateMode.PERSISTENT);\n                    Assert.fail(\"duplicate create allowed\");\n                } catch (KeeperException.NodeExistsException) {\n                    // OK, expected that\n                }\n        }\n\n        // Test that sequential filenames are being created correctly,\n        // with 0-padding in the filename\n\n        [Fact]\n        public async Task testSequentialNodeNames() \n\t\t{\n            string path = \"/SEQUENCE\";\n            string file = \"TEST\";\n            string filepath = path + \"/\" + file;\n\n            ZooKeeper zk = await createClient();\n            await zk.createAsync(path, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            await zk.createAsync(filepath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            IList<string> children = (await zk.getChildrenAsync(path, false)).Children;\n            Assert.assertEquals(1, children.Count);\n            Assert.assertEquals(file + \"0000000000\", children[0]);\n\n            await zk.createAsync(filepath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            children = (await zk.getChildrenAsync(path, false)).Children;\n            Assert.assertEquals(2, children.Count);\n            Assert.assertTrue(\"contains child 1\", children.Contains(file + \"0000000001\"));\n\n            await zk.createAsync(filepath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            children = (await zk.getChildrenAsync(path, false)).Children;\n            Assert.assertEquals(3, children.Count);\n            Assert.assertTrue(\"contains child 2\", \n\t\t\t           children.Contains(file + \"0000000002\"));\n\n            // The pattern is holding so far.  Let's run the counter a bit\n            // to be sure it continues to spit out the correct answer\n            for (int i = children.Count; i < 105; i++)\n                await zk.createAsync(filepath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n\n            children = (await zk.getChildrenAsync(path, false)).Children;\n            Assert.assertTrue(\"contains child 104\", \n\t\t\t           children.Contains(file + \"0000000104\"));\n        }\n\n        // Test that data provided when \n        // creating sequential nodes is stored properly\n        [Fact]\n        public async Task testSequentialNodeData() {\n            const string queue_handle = \"/queue\";\n                ZooKeeper zk = await createClient();\n\n                await zk.createAsync(queue_handle, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                await zk.createAsync(queue_handle + \"/element\", \"0\".UTF8getBytes(), \n\t\t\t\t\tZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                await zk.createAsync(queue_handle + \"/element\", \"1\".UTF8getBytes(), \n\t\t\t\t\tZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                IList<string> children = (await zk.getChildrenAsync(queue_handle, true)).Children;\n                Assert.assertEquals(children.Count, 2);\n                string child1 = children[0];\n                string child2 = children[1];\n                int compareResult = child1.CompareTo(child2);\n                Assert.assertNotEquals(compareResult, 0);\n                if (compareResult < 0) {\n                } else {\n                    string temp = child1;\n                    child1 = child2;\n                    child2 = temp;\n                }\n                string child1data = (await zk.getDataAsync(queue_handle \n\t\t\t\t        + \"/\" + child1, false)).Data.UTF8bytesToString();\n                string child2data = (await zk.getDataAsync(queue_handle \n\t\t\t\t        + \"/\" + child2, false)).Data.UTF8bytesToString();\n                Assert.assertEquals(child1data, \"0\");\n                Assert.assertEquals(child2data, \"1\");\n        }\n        \n        [Fact]\n        public async Task testLargeNodeData() {\n            ZooKeeper zk = null;\n            const string queue_handle = \"/large\";\n                zk = await createClient();\n\n                await zk.createAsync(queue_handle, new byte[500000], ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n        }\n\n\n        private async Task verifyCreateFails(string path, ZooKeeper zk) {\n            try {\n                await zk.createAsync(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            } catch (ArgumentException) {\n                // this is good\n                return;\n            }\n            Assert.fail(\"bad path \\\"\" + path + \"\\\" not caught\");\n        }\n\n        // Test that the path string is validated\n        [Fact]\n        public async Task testPathValidation() {\n            ZooKeeper zk = await createClient();\n            await Task.WhenAll(\n                verifyCreateFails(null, zk),\n                verifyCreateFails(\"\", zk),\n                verifyCreateFails(\"//\", zk),\n                verifyCreateFails(\"///\", zk),\n                verifyCreateFails(\"////\", zk),\n                verifyCreateFails(\"/.\", zk),\n                verifyCreateFails(\"/..\", zk),\n                verifyCreateFails(\"/./\", zk),\n                verifyCreateFails(\"/../\", zk),\n                verifyCreateFails(\"/foo/./\", zk),\n                verifyCreateFails(\"/foo/../\", zk),\n                verifyCreateFails(\"/foo/.\", zk),\n                verifyCreateFails(\"/foo/..\", zk),\n                verifyCreateFails(\"/./.\", zk),\n                verifyCreateFails(\"/../..\", zk),\n                verifyCreateFails(\"/\\u0001foo\", zk),\n                verifyCreateFails(\"/foo/bar/\", zk),\n                verifyCreateFails(\"/foo//bar\", zk),\n                verifyCreateFails(\"/foo/bar//\", zk),\n                verifyCreateFails(\"foo\", zk),\n                verifyCreateFails(\"a\", zk));\n\n            await zk.createAsync(\"/createseqpar\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t              CreateMode.PERSISTENT);\n            // next two steps - related to sequential processing\n            // 1) verify that empty child name Assert.fails if not sequential\n            try {\n                await zk.createAsync(\"/createseqpar/\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT);\n                Assert.assertTrue(false);\n            } catch (ArgumentException) {\n                // catch this.\n            }\n\n            // 2) verify that empty child name success if sequential \n            await zk.createAsync(\"/createseqpar/\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t\t\t  CreateMode.PERSISTENT_SEQUENTIAL);\n            await zk.createAsync(\"/createseqpar/.\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t              CreateMode.PERSISTENT_SEQUENTIAL);\n            await zk.createAsync(\"/createseqpar/..\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t              CreateMode.PERSISTENT_SEQUENTIAL);\n            try {\n                await zk.createAsync(\"/createseqpar//\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t\t          CreateMode.PERSISTENT_SEQUENTIAL);\n                Assert.assertTrue(false);\n            } catch (ArgumentException) {\n                // catch this.\n            }\n            try {\n                await zk.createAsync(\"/createseqpar/./\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT_SEQUENTIAL);\n                Assert.assertTrue(false);\n            } catch (ArgumentException) {\n                // catch this.\n            }\n            try {\n                await zk.createAsync(\"/createseqpar/../\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, \n\t\t\t\t              CreateMode.PERSISTENT_SEQUENTIAL);\n                Assert.assertTrue(false);\n            } catch (ArgumentException) {\n                // catch this.\n            }\n        }\n\n        [Fact]\n        public async Task testDeleteWithChildren() {\n            ZooKeeper zk = await createClient();\n            await zk.createAsync(\"/parent\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            await zk.createAsync(\"/parent/child\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            try {\n                await zk.deleteAsync(\"/parent\", -1);\n                Assert.fail(\"Should have received a not equals message\");\n            } catch (KeeperException e) {\n                Assert.assertEquals(KeeperException.Code.NOTEMPTY, e.getCode());\n            }\n            await zk.deleteAsync(\"/parent/child\", -1);\n            await zk.deleteAsync(\"/parent\", -1);\n        }\n        \n        private class DisconnectedWatcher : Watcher {\n            private readonly TaskCompletionSource<bool> latch = new TaskCompletionSource<bool>();\n\n            public override Task process(WatchedEvent @event) {\n                if (@event.getState() == Event.KeeperState.Disconnected) {\n                    latch.TrySetResult(true);\n                }\n                return Task.CompletedTask;\n            }\n\n            public Task getTask()\n            {\n                return latch.Task;\n            }\n        }\n\n        /// <summary>\n        /// We create a perfectly valid 'exists' request, except that the opcode is wrong.\n        /// @return </summary>\n        /// <exception cref=\"Exception\"> </exception>\n        [Fact]\n        public async Task testNonExistingOpCode() {\n            DisconnectedWatcher disconnectedWatcher = new DisconnectedWatcher();\n            ZooKeeper zk = await createClient(disconnectedWatcher);\n\n            const string path = \"/m1\";\n\n            RequestHeader h = new RequestHeader();\n            h.set_Type(888); // This code does not exists\n            ExistsRequest request = new ExistsRequest();\n            request.setPath(path);\n            request.setWatch(false);\n            ExistsResponse response = new ExistsResponse();\n\n            ReplyHeader r = await zk.cnxn.submitRequest(h, request, response, null);\n\n            Assert.assertEquals(r.getErr(), (int) KeeperException.Code.UNIMPLEMENTED);\n\n            // Sending a nonexisting opcode should cause the server to disconnect\n            Assert.assertTrue(\"failed to disconnect\",\n                await disconnectedWatcher.getTask().WithTimeout(5000));\n        }\n    }\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/ConnectStringParserTest.cs",
    "content": "using org.apache.zookeeper.client;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public class ConnectStringParserTest\n\t{\n        [Fact]\n\t\tpublic void testSingleServerChrootPath()\n\t\t{\n\t\t\tconst string chrootPath = \"/hallo/welt\";\n\t\t\tconst string servers = \"10.10.10.1\";\n\t\t\tassertChrootPath(chrootPath, new ConnectStringParser(servers + chrootPath));\n\t\t}\n\n        [Fact]\n\t\tpublic void testMultipleServersChrootPath()\n\t\t{\n\t\t\tconst string chrootPath = \"/hallo/welt\";\n\t\t\tconst string servers = \"10.10.10.1,10.10.10.2\";\n\t\t\tassertChrootPath(chrootPath, new ConnectStringParser(servers + chrootPath));\n\t\t}\n\n        [Fact]\n\t\tpublic void testParseServersWithoutPort()\n\t\t{\n\t\t\tconst string servers = \"10.10.10.1,10.10.10.2\";\n\t\t\tConnectStringParser parser = new ConnectStringParser(servers);\n\n\t\t\tAssert.assertEquals(\"10.10.10.1\", parser.getServerAddresses()[0].Host);\n            Assert.assertEquals(\"10.10.10.2\", parser.getServerAddresses()[1].Host);\n\t\t}\n\n        [Fact]\n\t\tpublic void testParseServersWithPort()\n\t\t{\n\t\t\tconst string servers = \"10.10.10.1:112,10.10.10.2:110\";\n\t\t\tConnectStringParser parser = new ConnectStringParser(servers);\n\n            Assert.assertEquals(\"10.10.10.1\", parser.getServerAddresses()[0].Host);\n            Assert.assertEquals(\"10.10.10.2\", parser.getServerAddresses()[1].Host);\n\n            Assert.assertEquals(112, parser.getServerAddresses()[0].Port);\n            Assert.assertEquals(110, parser.getServerAddresses()[1].Port);\n\t\t}\n\n\t\tprivate void assertChrootPath(string expected, ConnectStringParser parser)\n\t\t{\n\t\t\tAssert.assertEquals(expected, parser.getChrootPath());\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/CreateModeTest.cs",
    "content": "using System.Collections.Generic;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class CreateModeTest\n\t{\n        [Fact]\n\t\tpublic void testBasicCreateMode()\n\t\t{\n\t\t\tCreateMode cm = CreateMode.PERSISTENT;\n\t\t\tAssert.assertEquals(cm.toFlag(), 0);\n\t\t\tAssert.assertFalse(cm.isEphemeral());\n\t\t\tAssert.assertFalse(cm.isSequential());\n\n\t\t\tcm = CreateMode.EPHEMERAL;\n\t\t\tAssert.assertEquals(cm.toFlag(), 1);\n\t\t\tAssert.assertTrue(cm.isEphemeral());\n\t\t\tAssert.assertFalse(cm.isSequential());\n\n\t\t\tcm = CreateMode.PERSISTENT_SEQUENTIAL;\n\t\t\tAssert.assertEquals(cm.toFlag(), 2);\n\t\t\tAssert.assertFalse(cm.isEphemeral());\n\t\t\tAssert.assertTrue(cm.isSequential());\n\n\t\t\tcm = CreateMode.EPHEMERAL_SEQUENTIAL;\n\t\t\tAssert.assertEquals(cm.toFlag(), 3);\n\t\t\tAssert.assertTrue(cm.isEphemeral());\n\t\t\tAssert.assertTrue(cm.isSequential());\n\t\t}\n\n        [Fact]\n        public void testFlagConversion() {\n            // Ensure we get the same value back after round trip conversion\n            IEnumerable<CreateMode> allModes = new List<CreateMode>\n            {\n                CreateMode.EPHEMERAL,\n                CreateMode.EPHEMERAL_SEQUENTIAL,\n                CreateMode.PERSISTENT,\n                CreateMode.PERSISTENT_SEQUENTIAL\n            };\n\n            foreach (CreateMode cm in allModes) {\n                Assert.assertEquals(cm, CreateMode.fromFlag(cm.toFlag()));\n            }\n        }\n\n        [Fact]\n\t\tpublic void testInvalidFlagConversion()\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tCreateMode cm = CreateMode.fromFlag(99);\n\t\t\t\tAssert.fail(\"Shouldn't be able to convert 99 to a CreateMode.\");\n\t\t\t}\n\t\t\tcatch (KeeperException ke)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.BADARGUMENTS, ke.getCode());\n\t\t\t}\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tCreateMode cm = CreateMode.fromFlag(-1);\n\t\t\t\tAssert.fail(\"Shouldn't be able to convert -1 to a CreateMode.\");\n\t\t\t}\n\t\t\tcatch (KeeperException ke)\n\t\t\t{\n                Assert.assertEquals(KeeperException.Code.BADARGUMENTS, ke.getCode());\n\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/DynamicHostProviderTest.cs",
    "content": "﻿using System.Collections.Generic;\n﻿using System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing org.apache.zookeeper.client;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class DynamicHostProviderTest\n    {\n        [Fact]\n        public async Task testNextGoesRound()\n        {\n            HostProvider hostProvider = getHostProvider(1);\n            await hostProvider.next(0);\n            var first = await hostProvider.next(0);\n            var second = await hostProvider.next(0);\n            Xunit.Assert.Equal(first, second);\n        }\n\n        [Fact]\n        public async Task testNextGoesRoundAndSleeps()\n        {\n            byte size = 2;\n            HostProvider hostProvider = getHostProvider(size);\n            await hostProvider.next(0);\n            while (size > 0)\n            {\n                await hostProvider.next(0);\n                --size;\n            }\n            long start = TimeHelper.ElapsedMiliseconds;\n            await hostProvider.next(1000);\n            long stop = TimeHelper.ElapsedMiliseconds;\n            Assert.assertTrue(900 <= stop - start);\n        }\n\n        [Fact]\n        public async Task testNextDoesNotSleepForZero()\n        {\n            byte size = 2;\n            HostProvider hostProvider = getHostProvider(size);\n            await hostProvider.next(0);\n            while (size > 0)\n            {\n                await hostProvider.next(0);\n                --size;\n            }\n            long start = TimeHelper.ElapsedMiliseconds;\n            await hostProvider.next(0);\n            long stop = TimeHelper.ElapsedMiliseconds;\n            Assert.assertTrue(5 > stop - start);\n        }\n\n        [Fact]\n        public async Task testTwoConsequitiveCallsToNextReturnDifferentElement()\n        {\n            HostProvider hostProvider = getHostProvider(2);\n            await hostProvider.next(0);\n            Assert.assertNotEquals((await hostProvider.next(0)).ToString(), (await hostProvider.next(0)).ToString());\n        }\n\n        [Fact]\n        public async Task testOnConnectDoesNotReset()\n        {\n            HostProvider hostProvider = getHostProvider(2);\n            await hostProvider.next(0);\n            var first = await hostProvider.next(0);\n            hostProvider.onConnected();\n            var second = await hostProvider.next(0);\n            Assert.assertNotEquals(first.ToString(), second.ToString());\n        }\n\n        private static readonly TypeLogger<DynamicHostProviderTest> log = new TypeLogger<DynamicHostProviderTest>();\n\n        [Fact]\n        public async Task testResetAfterConnectPutsFirst()\n        {\n            HostProvider hostProvider = getHostProvider(20);\n            await hostProvider.next(0);\n            var endpoint = await hostProvider.next(0);\n            hostProvider.onConnected();\n            for (int i = 0; i < 19; i++) await hostProvider.next(0);\n            Assert.assertEquals(endpoint.ToString(), (await hostProvider.next(0)).ToString());\n        }\n\n        [Fact]\n        public async Task TestFirstAndSecondAreSame()\n        {\n            HostProvider hostProvider = getHostProvider(20);\n            Assert.assertEquals((await hostProvider.next(0)).ToString(), (await hostProvider.next(0)).ToString());\n        }\n\n        [Fact]\n        public async Task testOnlyOneAvailable()\n        {\n            log.debug(\"START - testOnlyOneAvailable\");\n            var connectionString = Enumerable.Range(0, 9).Select(i => Guid.NewGuid().ToString(\"N\")).ToCommaDelimited() +\n                                   \",localhost\";\n            await ZooKeeper.Using(connectionString, ClientBase.CONNECTION_TIMEOUT, ClientBase.NullWatcher.Instance, zk => zk.existsAsync(\"/\"));\n            log.debug(\"END - testOnlyOneAvailable\");\n        }\n\n        [Fact]\n        public async Task testNoOneAvailable()\n        {\n            log.debug(\"START - testNoOneAvailable\");\n            var connectionString = Enumerable.Range(0, 9).Select(i => Guid.NewGuid().ToString(\"N\")).ToCommaDelimited();\n            var zk = new ZooKeeper(connectionString, ClientBase.CONNECTION_TIMEOUT, ClientBase.NullWatcher.Instance);\n            try\n            {\n                await zk.existsAsync(\"/\");\n            }\n            catch (KeeperException.ConnectionLossException)\n            {\n                return;\n            }\n            finally\n            {\n                await zk.closeAsync();\n            }\n            log.debug(\"END - testNoOneAvailable\");\n        }\n\n        private static List<HostAndPort> getUnresolvedServerAddresses(byte size)\n        {\n            var list = new List<HostAndPort>(size);\n            while (size > 0)\n            {\n                list.Add(new HostAndPort(\"10.10.10.\" + size, 1234 + size));\n                --size;\n            }\n            return list;\n        }\n\n        private static DynamicHostProvider getHostProvider(byte size, IDnsResolver dnsResolver = null)\n        {\n            return new DynamicHostProvider(getUnresolvedServerAddresses(size), dnsResolver, log);\n        }\n\n        private class FakeDnsResolver : IDnsResolver\n        {\n            public Func<Task<IEnumerable<ResolvedEndPoint>>> ResolveFunc;\n\n            public Task<IEnumerable<ResolvedEndPoint>> Resolve(IEnumerable<HostAndPort> unresolvedHosts)\n            {\n                return ResolveFunc();\n            }\n            \n        }\n\n        [Fact]\n        public async Task TestBeforeFirstDnsSuccess()\n        {\n            var fakeDnsResolver = new FakeDnsResolver();\n            var resolvedEndPoints = new List<ResolvedEndPoint>();\n            fakeDnsResolver.ResolveFunc = () => Task.FromResult((IEnumerable<ResolvedEndPoint>) resolvedEndPoints);\n            var sw = new Stopwatch();\n\n            sw.Start();\n            var dynamicHostProvider = getHostProvider(1, fakeDnsResolver);\n            //before calling next() for the first time\n            AssertState(dynamicHostProvider, currentIndex: -1, lastIP: null, resolvingInBackground: false,\n                firstDnsTry: true);\n            //expected to fail since no IPs were returned\n            await Xunit.Assert.ThrowsAsync<SocketException>(() => dynamicHostProvider.next(1000));\n            //FirstDnsTry is now false\n            AssertState(dynamicHostProvider, currentIndex: -1, lastIP: null, resolvingInBackground: false,\n                firstDnsTry: false);\n            //should have ignored given timeouts, since it was the first dns attempt\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n\n            sw.Restart();\n            //again the dns resolution returns an empty list, we expected to fail\n            await Xunit.Assert.ThrowsAsync<SocketException>(() => dynamicHostProvider.next(1000));\n            AssertState(dynamicHostProvider, currentIndex: -1, lastIP: null, resolvingInBackground: false);\n            //we expect the timeout to be used, since it's not the first dns attempt\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 990);\n\n            //adding a resolved address to dns resolution\n            var resolvedEndPoint1 = new ResolvedEndPoint(IPAddress.Loopback, 999);\n            resolvedEndPoints.Add(resolvedEndPoint1);\n\n            sw.Restart();\n            //this is the first successful dns attempt, after a failed one. \n            var next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(resolvedEndPoint1, next);\n            AssertState(dynamicHostProvider, currentIndex: -1, lastIP: null, resolvingInBackground: false);\n            //we expect the timeout to be used, since it's not the first dns attempt\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 990);\n\n            sw.Restart();\n            //we asked for the next, knowing it would be the same address\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolvedEndPoint1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolvedEndPoint1, resolvingInBackground: false);\n            //we ignore the timeout because it's the first time we're in the main loop\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 10);\n\n            sw.Restart();\n            //Creating a new host provider, this time the dns resolve will succeed on first try\n            dynamicHostProvider = getHostProvider(1, fakeDnsResolver);\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolvedEndPoint1);\n            AssertState(dynamicHostProvider, currentIndex: -1, lastIP: null, resolvingInBackground: false);\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolvedEndPoint1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolvedEndPoint1, resolvingInBackground: false);\n            //we ignored the timeout since we have succeeded in resolving an address\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n\n            sw.Restart();\n            //we ask for the next address, but this time we expect the timeout. bcz we looped\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolvedEndPoint1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolvedEndPoint1, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 990);\n        }\n\n        [Fact]\n        public async Task TestAfterFirstDnsSuccess()\n        {\n            var fakeDnsResolver = new FakeDnsResolver();\n            var resolvedEndPoints = new List<ResolvedEndPoint>();\n            //adding a resolved address to dns resolution\n            var resolved1 = new ResolvedEndPoint(IPAddress.Loopback, 999);\n            resolvedEndPoints.Add(resolved1);\n\n            fakeDnsResolver.ResolveFunc = async () =>\n            {\n                await Task.Delay(200);\n                return resolvedEndPoints;\n            };\n\n            var dynamicHostProvider = getHostProvider(1, fakeDnsResolver);\n            await dynamicHostProvider.next(0);\n            await dynamicHostProvider.next(0);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: false);\n\n            //clearing resolveEndPoints in order to make sure background resolving is ignored when it fails\n            resolvedEndPoints.Clear();\n\n            var sw = new Stopwatch();\n            sw.Restart();\n            //this should start a background dns resolving task that's expected to fail\n            var next = await dynamicHostProvider.next(100);\n            Xunit.Assert.Equal(next, resolved1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: true);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >=99 && sw.ElapsedMilliseconds <= 200);\n\n            //the resolving runs in the background, we make sure we can still get the last ip\n            sw.Restart();\n            next = await dynamicHostProvider.next(10);\n            Xunit.Assert.Equal(next, resolved1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: true);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 9 && sw.ElapsedMilliseconds <= 200);\n\n            await Task.Delay(300);\n\n            //background resolving should have ended by now\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: false);\n\n            //add a new ip to the returned list (we only have one now) this doesn't yet affect anything yet\n            var resolved2 = new ResolvedEndPoint(IPAddress.Loopback, 998);\n            resolvedEndPoints.Add(resolved2);\n\n            sw.Restart();\n            //make sure we still have the last known ip available\n            next = await dynamicHostProvider.next(100);\n            Xunit.Assert.Equal(next, resolved1);\n            //we should start another background dns resolving which should return 'resolve2'\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: true);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 99);\n\n            await Task.Delay(300);\n\n            //background resolving should have ended by now\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved1, resolvingInBackground: false);\n\n            sw.Restart();\n            //we expect to get 'resolve2' without the timeout since it's different than 'resolve1'\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolved2);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved2, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n\n            //add back 'resolved1' to the returned list (the list is: 'resolved1','resolved2')\n            resolvedEndPoints.Add(resolved1);\n\n            sw.Restart();\n            //make sure we still have the last known ip available\n            next = await dynamicHostProvider.next(100);\n            Xunit.Assert.Equal(next, resolved2);\n            //we should start another background dns resolving which should return 'resolve1,resolve2'\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved2, resolvingInBackground: true);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 99);\n\n            await Task.Delay(300);\n\n            //background resolving should have ended by now\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved2, resolvingInBackground: false);\n            \n            sw.Restart();\n            //we expect to get 'resolve1' without the timeout since 'resolve2' was returned after a timeout\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolved1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved2, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n\n            sw.Restart();\n            //we expect to get 'resolve2' with the timeout since it's the LastIP\n            next = await dynamicHostProvider.next(400);\n            Xunit.Assert.Equal(next, resolved2);\n            AssertState(dynamicHostProvider, currentIndex: 1, lastIP: resolved2, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds >= 399);\n\n            sw.Restart();\n            //we expect to get 'resolve1' without the timeout since 'resolve2' was returned after a timeout\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolved1);\n            AssertState(dynamicHostProvider, currentIndex: 0, lastIP: resolved2, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n\n            //notify we have successfully connected with 'resolve1'\n            dynamicHostProvider.onConnected();\n\n            sw.Restart();\n            //we expect to get 'resolve2' without the timeout since it's NOT the LastIP\n            next = await dynamicHostProvider.next(1000);\n            Xunit.Assert.Equal(next, resolved2);\n            AssertState(dynamicHostProvider, currentIndex: 1, lastIP: resolved1, resolvingInBackground: false);\n            Assert.assertTrue($\"is {sw.ElapsedMilliseconds}\", sw.ElapsedMilliseconds <= 100);\n        }\n\n        private void AssertState(DynamicHostProvider dynamicHostProvider, int currentIndex, ResolvedEndPoint lastIP, bool resolvingInBackground, bool firstDnsTry=false)\n        {\n            Xunit.Assert.Equal(currentIndex, dynamicHostProvider.CurrentIndex);\n            Xunit.Assert.Equal(lastIP, dynamicHostProvider.LastIP);\n            Xunit.Assert.Equal(firstDnsTry, dynamicHostProvider.FirstDnsTry);\n            Xunit.Assert.Equal(resolvingInBackground, dynamicHostProvider.ResolvingInBackground);\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/EventTypeTest.cs",
    "content": "﻿using System;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class EventTypeTest \n\t{\n        //[Fact]\n        //public void testIntConversion()\n        //{\n        //    // Ensure that we can convert all valid integers to EventTypes\n        //    IEnumerable<Watcher.Event.EventType> allTypes = EnumUtil<Watcher.Event.EventType>.GetValues();\n\n        //    foreach (Watcher.Event.EventType et in allTypes) {\n        //        Assert.assertEquals(et, (Watcher.Event.EventType) ((int) et));\n        //    }\n        //}\n\n        [Fact]\n\t\tpublic void testInvalidIntConversion()\n\t\t{\n\t\t\ttry {\n\t\t\t    Watcher.Event.EventType et = EnumUtil<Watcher.Event.EventType>.DefinedCast(324242);\n\t\t\t\tAssert.fail(\"Was able to create an invalid EventType via an integer\");\n\t\t\t}\n\t\t\tcatch (Exception)\n\t\t\t{\n\t\t\t\t// we're good.\n\t\t\t}\n\n\t\t}\n\t}\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/GetChildren2Test.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class GetChildren2Test : ClientBase\n\t{\n\n        [Fact]\n\t\tpublic async Task testChild()\n\t\t{\n            var zk = await createClient();\n\t\t\tstring name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n\t\t\tstring childname = name + \"/bar\";\n\t\t\tawait zk.createAsync(childname, childname.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n            var childrenResult = await zk.getChildrenAsync(name, false);\n\n            Stat stat = childrenResult.Stat;\n\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid() + 1, stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(1, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(1, stat.getNumChildren());\n\t\t\tAssert.assertEquals(childrenResult.Children.Count, stat.getNumChildren());\n\n            childrenResult = await zk.getChildrenAsync(childname, false);\n            stat = childrenResult.Stat;\n\n            Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(0, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(zk.getSessionId(), stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(childname.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(0, stat.getNumChildren());\n\t\t\tAssert.assertEquals(childrenResult.Children.Count, stat.getNumChildren());\n\t\t}\n\n\n\n        [Fact]\n\t\tpublic async Task testChildren()\n        {\n            var zk = await createClient();\n\n            string name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n\t\t\tIList<string> children = new List<string>();\n\t\t\tList<string> children_s = new List<string>();\n\n\t\t\tfor (int i = 0; i < 10; i++)\n\t\t\t{\n\t\t\t\tstring childname = name + \"/bar\" + i;\n\t\t\t\tstring childname_s = \"bar\" + i;\n\t\t\t\tchildren.Add(childname);\n\t\t\t\tchildren_s.Add(childname_s);\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < children.Count; i++)\n\t\t\t{\n\t\t\t\tstring childname = children[i];\n\t\t\t\tawait zk.createAsync(childname, childname.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n\t\t\t    var childrenResult = await zk.getChildrenAsync(name, false);\n                Stat stat = childrenResult.Stat;\n\n\t\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\t\tAssert.assertEquals(stat.getCzxid() + i + 1, stat.getPzxid());\n\t\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\t\tAssert.assertEquals(i + 1, stat.getCversion());\n\t\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\t\tAssert.assertEquals(i + 1, stat.getNumChildren());\n\t\t\t\tAssert.assertEquals(childrenResult.Children.Count, stat.getNumChildren());\n\t\t\t}\n\t\t\tList<string> p = (await zk.getChildrenAsync(name, false)).Children;\n\t\t\tList<string> c_a = children_s;\n\t\t\tList<string> c_b = p;\n\t\t\tc_a.Sort();\n\t\t\tc_b.Sort();\n\t\t\tAssert.assertEquals(c_a.Count, 10);\n\t\t\tAssert.assertEquals(c_a, c_b);\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/KeeperStateTest.cs",
    "content": "﻿using System;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class KeeperStateTest\n\t{\n        //[Fact]\n        //public void testIntConversion()\n        //{\n        //    // Ensure that we can convert all valid integers to KeeperStates\n        //    EnumSet<Watcher.Event.KeeperState> allStates = EnumSet.allOf(typeof(Watcher.Event.KeeperState));\n\n        //    foreach (Watcher.Event.KeeperState @as in allStates)\n        //    {\n        //        Assert.assertEquals(@as, Watcher.Event.KeeperState.fromInt(@as.getIntValue()));\n        //    }\n        //}\n\n\n        [Fact]\n\t\tpublic void testInvalidIntConversion()\n\t\t{\n\t\t\ttry {\n\t\t\t    Watcher.Event.KeeperState ks = EnumUtil<Watcher.Event.KeeperState>.DefinedCast(324142);\n\t\t\t\tAssert.fail(\"Was able to create an invalid KeeperState via an integer\");\n\t\t\t}\n\t\t\tcatch (Exception)\n\t\t\t{\n\t\t\t\t// we're good.\n\t\t\t}\n\n\t\t}\n\n\t\t// <summary>\n\t\t// Validate that the deprecated constant still works. There were issues\n\t\t// found with switch statements - which need compile time constants.\n\t\t// </summary>\n\n\n        //public void testDeprecatedCodeOkInSwitch()\n        //{\n        //    int test = 1;\n        //    switch (test)\n        //    {\n        //    case KeeperException.Code.Ok:\n        //        Assert.assertTrue(true);\n        //        break;\n        //    }\n        //}\n\n\t\t// <summary>\n\t\t// Verify the enum works (paranoid) </summary>\n\n        [Fact]\n\t\tpublic void testCodeOKInSwitch()\n\t\t{\n\t\t\tKeeperException.Code test = KeeperException.Code.OK;\n\t\t\tswitch (test)\n\t\t\t{\n                case KeeperException.Code.OK:\n\t\t\t\tAssert.assertTrue(true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/MultiTransactionTest.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n\n    public sealed class MultiTransactionTest : ClientBase\n    {\n        private static readonly ILogProducer LOG = TypeLogger<MultiTransactionTest>.Instance;\n\n        private Task<List<OpResult>> multiAsync(ZooKeeper zk, List<Op> ops)\n        {\n            return zk.multiAsync(ops);\n        }\n\n        private async Task multiHavingErrors(ZooKeeper zk, List<Op> ops, List<KeeperException.Code> expectedResultCodes)\n        {\n            try\n            {\n                await multiAsync(zk, ops);\n                Assert.fail(\"Shouldn't have validated in ZooKeeper client!\");\n            }\n            catch (KeeperException e)\n            {\n                var results = e.getResults();\n                for (int i = 0; i < results.Count; i++)\n                {\n                    OpResult opResult = results[i];\n                    Assert.assertTrue(\"Did't recieve proper error response\", opResult is OpResult.ErrorResult);\n                    OpResult.ErrorResult errRes = (OpResult.ErrorResult)opResult;\n                    Assert.assertEquals(\"Did't recieve proper error code\", expectedResultCodes[i], errRes.getErr());\n                }\n            }\n        }\n\n        private Task<List<OpResult>> commitAsync(Transaction txn)\n        {\n            return txn.commitAsync();\n        }\n\n        /// <summary>\n        /// Test verifies the multi calls with invalid znode path\n        /// </summary>\n        [Fact]\n        public async Task testInvalidPath()\n        {\n            var zk = await createClient();\n            List<KeeperException.Code> expectedResultCodes = new List<KeeperException.Code>();\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n            expectedResultCodes.Add(KeeperException.Code.BADARGUMENTS);\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n            // create with CreateMode\n            List<Op> opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                                    ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                    CreateMode.PERSISTENT),\n                                          Op.create(\n                                                    \"/multi1/\", new byte[0],\n                                                    ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                    CreateMode.PERSISTENT),\n                                          Op.create(\"/multi2\", new byte[0],\n                                                    ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                    CreateMode.PERSISTENT));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n\n            // create with valid sequential flag\n            opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                             ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                             CreateMode.PERSISTENT),\n                                   Op.create(\"multi1/\", new byte[0],\n                                             ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                             CreateMode.EPHEMERAL_SEQUENTIAL.toFlag()),\n                                   Op.create(\"/multi2\",\n                                             new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                             CreateMode.PERSISTENT));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n\n            // check\n            opList = Arrays.asList(Op.check(\"/multi0\", -1),\n                                   Op.check(\"/multi1/\", 100),\n                                   Op.check(\"/multi2\", 5));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n\n            // delete\n            opList = Arrays.asList(Op.delete(\"/multi0\", -1),\n                                   Op.delete(\"/multi1/\", 100),\n                                   Op.delete(\"/multi2\", 5));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n\n            // Multiple bad arguments\n            expectedResultCodes.Add(KeeperException.Code.BADARGUMENTS);\n\n            // setdata\n            opList = Arrays.asList(Op.setData(\"/multi0\", new byte[0], -1),\n                                   Op.setData(\"/multi1/\", new byte[0], -1),\n                                   Op.setData(\"/multi2\", new byte[0], -1),\n                                   Op.setData(\"multi3\", new byte[0], -1));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n        }\n\n        /// <summary>\n        /// Test verifies the multi calls with blank znode path\n        /// </summary>:\n        [Fact]\n        public async Task testBlankPath()\n        {\n            var zk = await createClient();\n            List<KeeperException.Code> expectedResultCodes = new List<KeeperException.Code>();\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n            expectedResultCodes.Add(KeeperException.Code.BADARGUMENTS);\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n            expectedResultCodes.Add(KeeperException.Code.BADARGUMENTS);\n\n            // delete\n            List<Op> opList = Arrays.asList(Op.delete(\"/multi0\", -1),\n                                            Op.delete(null, 100),\n                                            Op.delete(\"/multi2\", 5),\n                                            Op.delete(\"\", -1));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n        }\n\n\n        /// <summary>\n        /// Test verifies the multi.create with invalid createModeFlag\n        /// </summary>\n        [Fact]\n        public async Task testInvalidCreateModeFlag()\n        {\n            var zk = await createClient();\n            List<KeeperException.Code> expectedResultCodes = new List<KeeperException.Code>();\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n            expectedResultCodes.Add(KeeperException.Code.BADARGUMENTS);\n            expectedResultCodes.Add(KeeperException.Code.RUNTIMEINCONSISTENCY);\n\n            int createModeFlag = 6789;\n            List<Op> opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                                      ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                      CreateMode.PERSISTENT),\n                                            Op.create(\"/multi1\", new byte[0],\n                                                      ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                      createModeFlag),\n                                            Op.create(\"/multi2\", new byte[0],\n                                                      ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                                                      CreateMode.PERSISTENT));\n            await multiHavingErrors(zk, opList, expectedResultCodes);\n        }\n\n        /**\n         * ZOOKEEPER-2052:\n         * Multi abort shouldn't have any side effect.\n         * We fix a bug in rollback and the following scenario should work:\n         * 1. multi delete abort because of not empty directory\n         * 2. ephemeral nodes under that directory are deleted\n         * 3. multi delete should succeed.\n         */\n        [Fact]\n        public async Task testMultiRollback()\n        {\n            var zk = await createClient();\n            await zk.createAsync(\"/foo\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            ZooKeeper epheZk = await createClient();\n            await epheZk.createAsync(\"/foo/bar\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n            List<Op> opList = Arrays.asList(Op.delete(\"/foo\", -1));\n            try\n            {\n                await multiAsync(zk, opList);\n                Assert.fail(\"multi delete should failed for not empty directory\");\n            }\n            catch (KeeperException.NotEmptyException)\n            {\n            }\n\n            var hasBeenDeleted = new HasBeenDeletedWatcher();\n\n            await zk.existsAsync(\"/foo/bar\", hasBeenDeleted);\n\n            await epheZk.closeAsync();\n\n            await hasBeenDeleted.triggered.Task;\n\n            try\n            {\n                await zk.getDataAsync(\"/foo/bar\", false);\n                Assert.fail(\"ephemeral node should have been deleted\");\n            }\n            catch (KeeperException.NoNodeException)\n            {\n            }\n\n            await multiAsync(zk, opList);\n\n            try\n            {\n                await zk.getDataAsync(\"/foo\", false);\n                Assert.fail(\"persistent node should have been deleted after multi\");\n            }\n            catch (KeeperException.NoNodeException)\n            {\n            }\n        }\n\n\n        [Fact]\n        public async Task testChRootCreateDelete()\n        {\n            var zk = await createClient();\n            // creating the subtree for chRoot clients.\n            string chRoot = await createNameSpace();\n            // Creating child using chRoot client.\n            var zk_chroot = await createClient(chRoot);\n            Op createChild = Op.create(\"/myid\", new byte[0],\n                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            await multiAsync(zk_chroot, Arrays.asList(createChild));\n\n            Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, await zk\n                    .existsAsync(chRoot + \"/myid\", false));\n            Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, await \n                    zk_chroot.existsAsync(\"/myid\", false));\n            Assert.assertNull(\"zNode is created directly under '/', ignored configured chroot\",\n                    await zk.existsAsync(\"/myid\", false));\n\n            // Deleting child using chRoot client.\n            Op deleteChild = Op.delete(\"/myid\", 0);\n            await multiAsync(zk_chroot, Arrays.asList(deleteChild));\n            Assert.assertNull(\"zNode exists under chroot:\" + chRoot, await zk.existsAsync(\n                    chRoot + \"/myid\", false));\n            Assert.assertNull(\"zNode exists under chroot:\" + chRoot, await zk_chroot\n                    .existsAsync(\"/myid\", false));\n        }\n\n        [Fact]\n        public async Task testChRootSetData()\n        {\n            // creating the subtree for chRoot clients.\n            string chRoot = await createNameSpace();\n            // setData using chRoot client.\n            var zk_chroot = await createClient(chRoot);\n            string[] names = new[] { \"/multi0\", \"/multi1\", \"/multi2\" };\n            List<Op> ops = new List<Op>();\n\n            for (int i = 0; i < names.Length; i++)\n            {\n                ops.Add(Op.create(names[i], new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT));\n                ops.Add(Op.setData(names[i], names[i].UTF8getBytes(), 0));\n            }\n\n            await multiAsync(zk_chroot, ops);\n\n            for (int i = 0; i < names.Length; i++)\n            {\n                Assert.assertEquals(\"zNode data not matching\", names[i]\n                    .UTF8getBytes(), (await zk_chroot.getDataAsync(names[i], false)).Data);\n        }\n        }\n\n        [Fact]\n        public async Task testChRootCheck()\n        {\n            var zk = await createClient();\n            // creating the subtree for chRoot clients.\n            string chRoot = await createNameSpace();\n            // checking the child version using chRoot client.\n            var zk_chroot = await createClient(chRoot);\n            string[] names = { \"/multi0\", \"/multi1\", \"/multi2\" };\n            List<Op> ops = new List<Op>();\n            for (int i = 0; i < names.Length; i++)\n            {\n                await zk.createAsync(chRoot + names[i], new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n            for (int i = 0; i < names.Length; i++)\n            {\n                ops.Add(Op.check(names[i], 0));\n            }\n            await multiAsync(zk_chroot, ops);\n        }\n\n        [Fact]\n        public async Task testChRootTransaction()\n        {\n            var zk = await createClient();\n            // creating the subtree for chRoot clients.\n            string chRoot = await createNameSpace();\n            // checking the child version using chRoot client.\n            var zk_chroot = await createClient(chRoot);\n            const string childPath = \"/myid\";\n            Transaction transaction = zk_chroot.transaction();\n            transaction.create(childPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            transaction.check(childPath, 0);\n            transaction.setData(childPath, childPath.UTF8getBytes(), 0);\n            await commitAsync(transaction);\n\n            Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, await zk\n                    .existsAsync(chRoot + childPath, false));\n            Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, await\n                    zk_chroot.existsAsync(childPath, false));\n            Assert.assertNull(\"zNode is created directly under '/', ignored configured chroot\",\n                            await zk.existsAsync(childPath, false));\n            Assert.assertEquals(\"zNode data not matching\", childPath\n            .UTF8getBytes(), (await zk_chroot.getDataAsync(childPath, false)).Data);\n\n            transaction = zk_chroot.transaction();\n            // Deleting child using chRoot client.\n            transaction.delete(childPath, 1);\n            await commitAsync(transaction);\n\n            Assert.assertNull(\"chroot:\" + chRoot + \" exists after delete\", await zk\n                    .existsAsync(chRoot + \"/myid\", false));\n            Assert.assertNull(\"chroot:\" + chRoot + \" exists after delete\", await\n                    zk_chroot.existsAsync(\"/myid\", false));\n        }\n\n        private async Task<string> createNameSpace()\n        {\n            var zk = await createClient();\n            // creating the subtree for chRoot clients.\n            string chRoot = \"/appsX\";\n            Op createChRoot = Op.create(chRoot, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            await multiAsync(zk, Arrays.asList(createChRoot));\n            return chRoot;\n        }\n\n        [Fact]\n        public async Task testCreate()\n        {\n            var zk = await createClient();\n            await multiAsync(zk, Arrays.asList(\n                    Op.create(\"/multi0\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.create(\"/multi1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.create(\"/multi2\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                    ));\n            await zk.getDataAsync(\"/multi0\", false);\n            await zk.getDataAsync(\"/multi1\", false);\n            await zk.getDataAsync(\"/multi2\", false);\n        }\n\n        [Fact]\n        public async Task testCreateDelete()\n        {\n            var zk = await createClient();\n            await multiAsync(zk, Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/multi\", 0)\n                    ));\n\n            // '/multi' should have been deleted\n            Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n        }\n\n        [Fact]\n        public async Task testInvalidVersion()\n        {\n\n            var zk = await createClient();\n            try\n            {\n                await multiAsync(zk, Arrays.asList(\n                        Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                        Op.delete(\"/multi\", 1)\n                ));\n                Assert.fail(\"delete /multi should have failed\");\n            }\n            catch (KeeperException)\n            {\n                /* PASS */\n            }\n        }\n\n        [Fact]\n        public async Task testNestedCreate()\n        {\n            var zk = await createClient();\n            await multiAsync(zk, Arrays.asList(\n                    /* Create */\n                    Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.create(\"/multi/a\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.create(\"/multi/a/1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n\n                    /* Delete */\n                    Op.delete(\"/multi/a/1\", 0),\n                    Op.delete(\"/multi/a\", 0),\n                    Op.delete(\"/multi\", 0)\n                    ));\n\n            //Verify tree deleted\n            Assert.assertNull(await zk.existsAsync(\"/multi/a/1\", null));\n            Assert.assertNull(await zk.existsAsync(\"/multi/a\", null));\n            Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n        }\n\n        [Fact]\n        public async Task testSetData()\n        {\n\n            var zk = await createClient();\n            string[] names = new string[] { \"/multi0\", \"/multi1\", \"/multi2\" };\n            List<Op> ops = new List<Op>();\n\n            for (int i = 0; i < names.Length; i++)\n            {\n                ops.Add(Op.create(names[i], new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT));\n                ops.Add(Op.setData(names[i], names[i].UTF8getBytes(), 0));\n            }\n\n            await multiAsync(zk, ops);\n\n            for (int i = 0; i < names.Length; i++)\n            {\n                Assert.assertEquals(names[i].UTF8getBytes(), (await zk.getDataAsync(names[i], false)).Data);\n            }\n        }\n\n        [Fact]\n        public async Task testUpdateConflict()\n        {\n\n            var zk = await createClient();\n            Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n\n            try\n            {\n                await multiAsync(zk, Arrays.asList(\n                        Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                        Op.setData(\"/multi\", \"X\".UTF8getBytes(), 0),\n                        Op.setData(\"/multi\", \"Y\".UTF8getBytes(), 0)\n                        ));\n                Assert.fail(\"Should have thrown a KeeperException for invalid version\");\n            }\n            catch (KeeperException e)\n            {\n                //PASS\n                LOG.error(\"STACKTRACE: \" + e);\n            }\n\n            Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n\n            //Updating version solves conflict -- order matters\n            await multiAsync(zk, Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.setData(\"/multi\", \"X\".UTF8getBytes(), 0),\n                    Op.setData(\"/multi\", \"Y\".UTF8getBytes(), 1)\n                    ));\n\n            Assert.assertEquals((await zk.getDataAsync(\"/multi\", false)).Data, \"Y\".UTF8getBytes());\n        }\n\n        [Fact]\n        public async Task TestDeleteUpdateConflict()\n        {\n\n            var zk = await createClient();\n            /* Delete of a node folowed by an update of the (now) deleted node */\n            try\n            {\n                await multiAsync(zk, Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/multi\", 0),\n                    Op.setData(\"/multi\", \"Y\".UTF8getBytes(), 0)\n                    ));\n                Assert.fail(\"/multi should have been deleted so setData should have failed\");\n            }\n            catch (KeeperException)\n            {\n                /* PASS */\n            }\n\n            // '/multi' should never have been created as entire op should fail\n            Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n        }\n\n        [Fact]\n        public async Task TestGetResults()\n        {\n            var zk = await createClient();\n            /* Delete of a node folowed by an update of the (now) deleted node */\n            var ops = Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/multi\", 0),\n                    Op.setData(\"/multi\", \"Y\".UTF8getBytes(), 0),\n                    Op.create(\"/foo\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n            );\n            List<OpResult> results = null;\n            try\n            {\n                await zk.multiAsync(ops);\n                Assert.fail(\"/multi should have been deleted so setData should have failed\");\n            }\n            catch (KeeperException e)\n            {\n                // '/multi' should never have been created as entire op should fail\n                Assert.assertNull(await zk.existsAsync(\"/multi\", null));\n                results = e.getResults();\n            }\n\n            Assert.assertNotNull(results);\n            foreach (OpResult r in results)\n            {\n                LOG.info(\"RESULT==> \" + r);\n                if (r is OpResult.ErrorResult)\n                {\n                    OpResult.ErrorResult er = (OpResult.ErrorResult)r;\n                    LOG.info(\"ERROR RESULT: \" + er + \" ERR=>\" + EnumUtil<KeeperException.Code>.DefinedCast(er.getErr()));\n                }\n            }\n        }\n\n        [Fact]\n        public async Task testWatchesTriggered()\n        {\n            var zk = await createClient();\n            HasTriggeredWatcher watcher = new HasTriggeredWatcher();\n            await zk.getChildrenAsync(\"/\", watcher);\n            await multiAsync(zk, Arrays.asList(\n                    Op.create(\"/t\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/t\", -1)\n            ));\n            Assert.assertTrue(await watcher.triggered.Task.WithTimeout(CONNECTION_TIMEOUT));\n        }\n\n        [Fact]\n        public async Task testNoWatchesTriggeredForFailedMultiRequest()\n        {\n            var zk = await createClient();\n            HasTriggeredWatcher watcher = new HasTriggeredWatcher();\n            await zk.getChildrenAsync(\"/\", watcher);\n            try\n            {\n                await multiAsync(zk, Arrays.asList(\n                        Op.create(\"/t\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                        Op.delete(\"/nonexisting\", -1)\n                ));\n                Assert.fail(\"expected previous multi op to fail!\");\n            }\n            catch (KeeperException.NoNodeException)\n            {\n                // expected\n            }\n            \n            // by waiting for the callback we're assured that the event queue is flushed\n            Assert.assertTrue(await zk.sync(\"/\").WithTimeout(CONNECTION_TIMEOUT));\n        }\n\n        [Fact]\n        public async Task testTransactionBuilder()\n        {\n            var zk = await createClient();\n            List<OpResult> results = await commitAsync(zk.transaction()\n                    .create(\"/t1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                    .create(\"/t1/child\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                    .create(\"/t2\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL));\n            Assert.assertEquals(3, results.Count);\n            foreach (OpResult r in results)\n            {\n                OpResult.CreateResult c = (OpResult.CreateResult)r;\n                Assert.assertTrue(c.getPath().Contains(\"/t\"));\n                Assert.assertNotNull(c.ToString());\n            }\n            Assert.assertNotNull(await zk.existsAsync(\"/t1\", false));\n            Assert.assertNotNull(await zk.existsAsync(\"/t1/child\", false));\n            Assert.assertNotNull(await zk.existsAsync(\"/t2\", false));\n\n            results = await commitAsync(zk.transaction()\n                    .check(\"/t1\", 0)\n                    .check(\"/t1/child\", 0)\n                    .check(\"/t2\", 0));\n            Assert.assertEquals(3, results.Count);\n            foreach (OpResult r in results)\n            {\n                OpResult.CheckResult c = (OpResult.CheckResult)r;\n                Assert.assertNotNull(c.ToString());\n            }\n\n            try\n            {\n                await commitAsync(zk.transaction()\n                        .check(\"/t1\", 0)\n                        .check(\"/t1/child\", 0)\n                        .check(\"/t2\", 1));\n                Assert.fail();\n            }\n            catch (KeeperException.BadVersionException)\n            {\n                // expected\n            }\n\n            results = await commitAsync(zk.transaction()\n                    .check(\"/t1\", 0)\n                    .setData(\"/t1\", new byte[0], 0));\n            Assert.assertEquals(2, results.Count);\n            foreach (OpResult r in results)\n            {\n                Assert.assertNotNull(r.ToString());\n            }\n\n            try\n            {\n                results = await commitAsync(zk.transaction()\n                        .check(\"/t1\", 1)\n                        .setData(\"/t1\", new byte[0], 2));\n                Assert.fail();\n            }\n            catch (KeeperException.BadVersionException)\n            {\n                // expected\n            }\n\n            results = await commitAsync(zk.transaction()\n                    .check(\"/t1\", 1)\n                    .check(\"/t1/child\", 0)\n                    .check(\"/t2\", 0));\n            Assert.assertEquals(3, results.Count);\n\n            results = await commitAsync(zk.transaction()\n                    .delete(\"/t2\", -1)\n                    .delete(\"/t1/child\", -1));\n            Assert.assertEquals(2, results.Count);\n            foreach (OpResult r in results)\n            {\n                OpResult.DeleteResult d = (OpResult.DeleteResult)r;\n                Assert.assertNotNull(d.ToString());\n            }\n            Assert.assertNotNull(await zk.existsAsync(\"/t1\", false));\n            Assert.assertNull(await zk.existsAsync(\"/t1/child\", false));\n            Assert.assertNull(await zk.existsAsync(\"/t2\", false));\n        }\n\n        private class HasTriggeredWatcher : Watcher\n        {\n            internal readonly TaskCompletionSource<bool> triggered = new TaskCompletionSource<bool>();\n\n            public override Task process(WatchedEvent @event)\n            {\n                triggered.TrySetResult(true);\n                return Task.CompletedTask;\n            }\n        }\n\n        private class HasBeenDeletedWatcher : Watcher\n        {\n            internal readonly TaskCompletionSource<bool> triggered = new TaskCompletionSource<bool>();\n\n            public override Task process(WatchedEvent @event)\n            {\n                if (@event.get_Type() == Watcher.Event.EventType.NodeDeleted)\n                {\n                    triggered.TrySetResult(true);\n                }\n                return Task.CompletedTask;\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/NullDataTest.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class NullDataTest : ClientBase {\n\n        [Fact]\n\t\tpublic async Task testNullData()\n\t\t{\n\t\t\tconst string path = \"/SIZE\";\n            ZooKeeper zk = await createClient();\n\t\t\t\tawait zk.createAsync(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\t\t// try sync zk exists \n\t\t\t\tawait zk.existsAsync(path, false);\n\t\t\t\tAssert.assertTrue(await zk.existsAsync(path, false).WithTimeout(10*1000));\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/StatTest.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class StatTest : ClientBase\n\t{\n        [Fact]\n\t\tpublic async Task testBasic()\n\t\t{\n            var zk = await createClient();\n            const string name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            \n            var stat=(await zk.getDataAsync(name, false)).Stat;\n\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(0, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(0, stat.getNumChildren());\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testChild()\n\t\t{\n            var zk = await createClient();\n            const string name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n\t\t\tconst string childname = name + \"/bar\";\n\t\t\tawait zk.createAsync(childname, childname.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n            var stat = (await zk.getDataAsync(name, false)).Stat;\n\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid() + 1, stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(1, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(1, stat.getNumChildren());\n\n\t\t\tstat = (await zk.getDataAsync(childname, false)).Stat;\n\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(0, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(zk.getSessionId(), stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(childname.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(0, stat.getNumChildren());\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testChildren()\n\t\t{\n            var zk = await createClient();\n            const string name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n\t\t\tfor (int i = 0; i < 10; i++)\n\t\t\t{\n\t\t\t\tstring childname = name + \"/bar\" + i;\n\t\t\t\tawait zk.createAsync(childname, childname.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n\t\t\t    var stat = (await zk.getDataAsync(name, false)).Stat;\n\n\t\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\t\tAssert.assertEquals(stat.getCzxid() + i + 1, stat.getPzxid());\n\t\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\t\tAssert.assertEquals(i + 1, stat.getCversion());\n\t\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\t\tAssert.assertEquals(i + 1, stat.getNumChildren());\n\t\t\t}\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testDataSizeChange()\n\t\t{\n            var zk = await createClient();\n            const string name = \"/foo\";\n\t\t\tawait zk.createAsync(name, name.UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n            var stat = (await zk.getDataAsync(name, false)).Stat;\n\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getPzxid());\n\t\t\tAssert.assertEquals(stat.getCtime(), stat.getMtime());\n\t\t\tAssert.assertEquals(0, stat.getCversion());\n\t\t\tAssert.assertEquals(0, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(name.Length, stat.getDataLength());\n\t\t\tAssert.assertEquals(0, stat.getNumChildren());\n\n\t\t\tawait zk.setDataAsync(name, (name + name).UTF8getBytes(), -1);\n\n\t\t\tstat = (await zk.getDataAsync(name, false)).Stat;\n\n\t\t\tAssert.assertNotEquals(stat.getCzxid(), stat.getMzxid());\n\t\t\tAssert.assertEquals(stat.getCzxid(), stat.getPzxid());\n\t\t\tAssert.assertEquals(0, stat.getCversion());\n\t\t\tAssert.assertEquals(1, stat.getVersion());\n\t\t\tAssert.assertEquals(0, stat.getAversion());\n\t\t\tAssert.assertEquals(0, stat.getEphemeralOwner());\n\t\t\tAssert.assertEquals(name.Length * 2, stat.getDataLength());\n\t\t\tAssert.assertEquals(0, stat.getNumChildren());\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/SyncCallTest.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing org.apache.utils;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class SyncCallTest : ClientBase\n\t{\n        private static readonly ILogProducer LOG = TypeLogger<SyncCallTest>.Instance;\n\n        [Fact]\n        public async Task testSync()\n        {\n            LOG.info(\"Starting ZK:\" + DateTime.Now);\n\n            ZooKeeper zk = await createClient();\n\n            LOG.info(\"Beginning test:\" + DateTime.Now);\n            for (var i = 0; i < 100; i++)\n            {\n                await zk.createAsync(\"/test\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            await zk.sync(\"/test\");\n            for (var i = 0; i < 100; i++)\n            {\n                await zk.deleteAsync(\"/test\" + i, 0);\n            }\n            for (var i = 0; i < 100; i++)\n            {\n                await zk.getChildrenAsync(\"/\", false);\n            }\n            for (var i = 0; i < 100; i++)\n            {\n                await zk.getChildrenAsync(\"/\", false);\n            }\n            LOG.info(\"Submitted all operations:\" + DateTime.Now);\n        }\n    }\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/WatchedEventTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing org.apache.utils;\nusing org.apache.zookeeper.proto;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class WatchedEventTest\n\t{\n        [Fact]\n\t\tpublic void testCreatingWatchedEvent()\n\t\t{\n\t\t\t// EventWatch is a simple, immutable type, so all we need to do\n\t\t   // is make sure we can create all possible combinations of values.\n\n\t\t\tIEnumerable<Watcher.Event.EventType> allTypes = EnumUtil<Watcher.Event.EventType>.GetValues();\n            IEnumerable<Watcher.Event.KeeperState> allStates = EnumUtil<Watcher.Event.KeeperState>.GetValues();\n\n            foreach (Watcher.Event.EventType et in allTypes)\n\t\t\t{\n\t\t\t   foreach (Watcher.Event.KeeperState ks in allStates)\n\t\t\t   {\n\t\t\t\t   var we = new WatchedEvent(et, ks, \"blah\");\n\t\t\t\t   Assert.assertEquals(et, we.get_Type());\n\t\t\t\t   Assert.assertEquals(ks, we.getState());\n\t\t\t\t   Assert.assertEquals(\"blah\", we.getPath());\n\t\t\t   }\n\n\t\t\t}\n\t\t}\n\n         [Fact]\n\t\tpublic void testCreatingWatchedEventFromWrapper()\n\t\t{\n\t\t\t// Make sure we can handle any type of correct wrapper\n\n            IEnumerable<Watcher.Event.EventType> allTypes = EnumUtil<Watcher.Event.EventType>.GetValues();\n            IEnumerable<Watcher.Event.KeeperState> allStates = EnumUtil<Watcher.Event.KeeperState>.GetValues();\n\n             foreach (Watcher.Event.EventType et in allTypes)\n\t\t\t{\n\t\t\t   foreach (Watcher.Event.KeeperState ks in allStates)\n\t\t\t   {\n\t\t\t\t   var wep = new WatcherEvent((int) et, (int) ks, \"blah\");\n\t\t\t\t   var we = new WatchedEvent(wep);\n\t\t\t\t   Assert.assertEquals(et, we.get_Type());\n\t\t\t\t   Assert.assertEquals(ks, we.getState());\n\t\t\t\t   Assert.assertEquals(\"blah\", we.getPath());\n\t\t\t   }\n\t\t\t}\n\t\t}\n\n        [Fact]\n\t\tpublic void testCreatingWatchedEventFromInvalidWrapper()\n\t\t{\n\t\t\t// Make sure we can't convert from an invalid wrapper\n\n\t\t   try\n\t\t   {\n\t\t\t   WatcherEvent wep = new WatcherEvent(-2342, -252352, \"foo\");\n\t\t\t   WatchedEvent we = new WatchedEvent(wep);\n\t\t\t   Assert.fail(\"Was able to create WatchedEvent from bad wrapper\");\n\t\t   }\n\t\t   catch (Exception)\n\t\t   {\n\t\t\t   // we're good\n\t\t   }\n\t\t}\n\n        [Fact]\n\t   public void testConvertingToEventWrapper()\n\t   {\n\t\t   WatchedEvent we = new WatchedEvent(Watcher.Event.EventType.NodeCreated, Watcher.Event.KeeperState.Expired, \"blah\");\n\t\t   WatcherEvent wew = we.getWrapper();\n\n\t\t   Assert.assertEquals((int)Watcher.Event.EventType.NodeCreated, wew.get_Type());\n           Assert.assertEquals((int)Watcher.Event.KeeperState.Expired, wew.getState());\n\t\t   Assert.assertEquals(\"blah\", wew.getPath());\n\t   }\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/WatcherFuncTest.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public sealed class WatcherFuncTest : ClientBase\n\t{\n\t\tprivate sealed class SimpleWatcher : Watcher\n\t\t{\n\t\t    private readonly BlockingCollection<WatchedEvent> events = new BlockingCollection<WatchedEvent>();\n\n\t\t    public override Task process(WatchedEvent @event) \n            {\n                if (@event.get_Type() != Event.EventType.None)\n\t\t        {\n\t\t            try\n\t\t            {\n\t\t                events.Add(@event);\n\t\t            }\n\t\t            catch\n\t\t            {\n\t\t                Assert.assertTrue(\"interruption unexpected\", false);\n\t\t            }\n\t\t        }\n\t\t        return Task.CompletedTask;\n            }\n\n\n\t\t    public void verify(IList<Event.EventType> expected)\n\t\t\t{\n\t\t\t\tWatchedEvent @event;\n\t\t\t\tint count = 0;\n\t\t\t\twhile (count < expected.Count && (@event = events.poll(30*1000)) != null)\n\t\t\t\t{\n\t\t\t\t\tAssert.assertEquals(expected[count], @event.get_Type());\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t    Assert.assertEquals(expected.Count, count);\n\t\t\t    while (events.TryTake(out @event)) ;\n\t\t\t}\n\t\t}\n\t\tprivate readonly SimpleWatcher client_dwatch;\n\t\tprivate ZooKeeper client;\n\t\tprivate readonly SimpleWatcher lsnr_dwatch;\n\t\tprivate ZooKeeper lsnr;\n\n\t\tprivate readonly IList<Watcher.Event.EventType> expected;\n\n\t    public override async Task InitializeAsync()\n\t    {\n\t        await base.InitializeAsync();\n\n\t        client = await createClient(client_dwatch);\n\n\t        lsnr = await createClient(lsnr_dwatch);\n\t    }\n\n\t\tpublic WatcherFuncTest()\n\t\t{\n\t\t\tclient_dwatch = new SimpleWatcher();\n\t\t\tlsnr_dwatch = new SimpleWatcher();\n\t\t\texpected = new List<Watcher.Event.EventType>();\n\t\t}\n\n\t\tprivate void verify()\n\t\t{\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\texpected.Clear();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testExistsSync()\n\t\t{\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/bar\", true));\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeCreated);\n\t\t\tawait client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeCreated);\n\n\t\t\tverify();\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", true));\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/car\", true));\n\t\t\t\tawait client.setDataAsync(\"/car\", \"missing\".UTF8getBytes(), -1);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/car\", e.getPath());\n\t\t\t}\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/car\", true));\n\t\t\t\tawait client.setDataAsync(\"/foo/car\", \"missing\".UTF8getBytes(), -1);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo/car\", e.getPath());\n\t\t\t}\n\n\t\t\tawait client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\n\t\t\tverify();\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", true));\n\n\t\t\tawait client.deleteAsync(\"/foo/bar\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tverify();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testGetDataSync()\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getDataAsync(\"/foo\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo\", e.getPath());\n\t\t\t}\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getDataAsync(\"/foo/bar\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo/bar\", e.getPath());\n\t\t\t}\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo\", true)).Data);\n            await client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", true)).Data);\n\n            await client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\n\t\t\tverify();\n\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo\", true)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", true)).Data);\n\n            await client.deleteAsync(\"/foo/bar\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tverify();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testGetChildrenSync()\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getChildrenAsync(\"/foo\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo\", e.getPath());\n\t\t\t}\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getChildrenAsync(\"/foo/bar\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo/bar\", e.getPath());\n\t\t\t}\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", true)).Children);\n\n\t\t\tawait client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeChildrenChanged); // /foo\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", true)).Children);\n\n\n            await client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", true)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", true)).Children);\n\n            await client.deleteAsync(\"/foo/bar\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted); // /foo/bar childwatch\n\t\t\texpected.Add(Watcher.Event.EventType.NodeChildrenChanged); // /foo\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tverify();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testExistsSyncWObj()\n\t\t{\n\t\t\tSimpleWatcher w1 = new SimpleWatcher();\n\t\t\tSimpleWatcher w2 = new SimpleWatcher();\n\t\t\tSimpleWatcher w3 = new SimpleWatcher();\n\t\t\tSimpleWatcher w4 = new SimpleWatcher();\n\n\t\t\tIList<Watcher.Event.EventType> e2 = new List<Watcher.Event.EventType>();\n\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo\", w1));\n\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/bar\", w2));\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/bar\", w3));\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/bar\", w3));\n\t\t\tAssert.assertNull(await lsnr.existsAsync(\"/foo/bar\", w4));\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeCreated);\n\t\t\tawait client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\te2.Add(Watcher.Event.EventType.NodeCreated);\n\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\n\t\t\t// default not registered\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", w1));\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w2));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w3));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w4));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w4));\n\n\t\t\tawait client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\t\t\te2.Add(Watcher.Event.EventType.NodeDataChanged);\n\n\t\t\tlsnr_dwatch.verify(new List<Watcher.Event.EventType>()); // not reg so should = 0\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", w1));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", w1));\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w2));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w2));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w3));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo/bar\", w4));\n\n\t\t\tawait client.deleteAsync(\"/foo/bar\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\te2.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testGetDataSyncWObj()\n\t\t{\n\t\t\tSimpleWatcher w1 = new SimpleWatcher();\n\t\t\tSimpleWatcher w2 = new SimpleWatcher();\n\t\t\tSimpleWatcher w3 = new SimpleWatcher();\n\t\t\tSimpleWatcher w4 = new SimpleWatcher();\n\n\t\t\tIList<Watcher.Event.EventType> e2 = new List<Watcher.Event.EventType>();\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getDataAsync(\"/foo\", w1);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo\", e.getPath());\n\t\t\t}\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getDataAsync(\"/foo/bar\", w2);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo/bar\", e.getPath());\n\t\t\t}\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo\", true)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo\", w1)).Data);\n            await client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w2)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w3)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w4)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w4)).Data);\n\n            await client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDataChanged);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\t\t\te2.Add(Watcher.Event.EventType.NodeDataChanged);\n\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo\", true)).Data);\n\t\t\tAssert.assertNotNull((await lsnr.getDataAsync(\"/foo\", w1)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w2)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w3)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w3)).Data);\n            Assert.assertNotNull((await lsnr.getDataAsync(\"/foo/bar\", w4)).Data);\n\n            await client.deleteAsync(\"/foo/bar\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\te2.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\t\t}\n\n        [Fact]\n\t\tpublic async Task testGetChildrenSyncWObj()\n\t\t{\n\t\t\tSimpleWatcher w1 = new SimpleWatcher();\n\t\t\tSimpleWatcher w2 = new SimpleWatcher();\n\t\t\tSimpleWatcher w3 = new SimpleWatcher();\n\t\t\tSimpleWatcher w4 = new SimpleWatcher();\n\n\t\t\tIList<Watcher.Event.EventType> e2 = new List<Watcher.Event.EventType>();\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getChildrenAsync(\"/foo\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo\", e.getPath());\n\t\t\t}\n\t\t\ttry\n\t\t\t{\n\t\t\t\tawait lsnr.getChildrenAsync(\"/foo/bar\", true);\n\t\t\t\tAssert.fail();\n\t\t\t}\n\t\t\tcatch (KeeperException e)\n\t\t\t{\n\t\t\t\tAssert.assertEquals(KeeperException.Code.NONODE, e.getCode());\n\t\t\t\tAssert.assertEquals(\"/foo/bar\", e.getPath());\n\t\t\t}\n\n\t\t\tawait client.createAsync(\"/foo\", \"parent\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", true)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", w1)).Children);\n\n            await client.createAsync(\"/foo/bar\", \"child\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeChildrenChanged); // /foo\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w2)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w2)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w3)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w4)).Children);\n\n\n            await client.setDataAsync(\"/foo\", \"parent\".UTF8getBytes(), -1);\n\t\t\tawait client.setDataAsync(\"/foo/bar\", \"child\".UTF8getBytes(), -1);\n\n\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", w1));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", true));\n\t\t\tAssert.assertNotNull(await lsnr.existsAsync(\"/foo\", w1));\n\n\t\t\tAssert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", true)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo\", w1)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w2)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w3)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w4)).Children);\n            Assert.assertNotNull((await lsnr.getChildrenAsync(\"/foo/bar\", w4)).Children);\n\n            await client.deleteAsync(\"/foo/bar\", -1);\n\t\t\te2.Add(Watcher.Event.EventType.NodeDeleted); // /foo/bar childwatch\n\t\t\texpected.Add(Watcher.Event.EventType.NodeChildrenChanged); // /foo\n\t\t\tawait client.deleteAsync(\"/foo\", -1);\n\t\t\texpected.Add(Watcher.Event.EventType.NodeDeleted);\n\n\t\t\tlsnr_dwatch.verify(expected);\n\t\t\tw1.verify(expected);\n\t\t\tw2.verify(e2);\n\t\t\tw3.verify(e2);\n\t\t\tw4.verify(e2);\n\t\t\texpected.Clear();\n\t\t\te2.Clear();\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/ZooKeeperNetEx.Tests/test/WatcherTest.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Threading.Tasks;\nusing org.apache.zookeeper.data;\nusing Xunit;\n\nnamespace org.apache.zookeeper.test\n{\n    public class WatcherTest : ClientBase\n\t{\n        private class MyWatcher : Watcher {\n            internal readonly BlockingCollection<WatchedEvent> events =\n            new BlockingCollection<WatchedEvent>();\n\n        public override Task process(WatchedEvent @event) {\n            if (@event.get_Type() != Event.EventType.None) {\n                events.Add(@event);\n            }\n            return Task.CompletedTask;\n        }\n    }\n\n\t\t// <summary>\n\t\t// Verify that we get all of the events we expect to get. This particular\n\t\t// case verifies that we see all of the data events on a particular node.\n\t\t// There was a bug (ZOOKEEPER-137) that resulted in events being dropped\n\t\t// in some cases (timing).\n\t\t// </summary>\n\t\t// <exception cref=\"IOException\"> </exception>\n\t\t// <exception cref=\"InterruptedException\"> </exception>\n\t\t// <exception cref=\"KeeperException\"> </exception>\n        [Fact]\n\t\tpublic async Task testWatcherCorrectness()\n\t\t{\n\t\t\tZooKeeper zk = null;\n\t\t\t\tMyWatcher watcher = new MyWatcher();\n\t\t\t\tzk = await createClient(watcher);\n\n\t\t\t\tstring[] names = new string[10];\n\t\t\t\tfor (int i = 0; i < names.Length; i++)\n\t\t\t\t{\n\t\t\t\t\tstring name = await zk.createAsync(\"/tc-\", \"initialvalue\".UTF8getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n\t\t\t\t\tnames[i] = name;\n\n\t\t\t\t\tStat stat = (await zk.getDataAsync(name, watcher)).Stat;\n\t\t\t\t\tawait zk.setDataAsync(name, \"new\".UTF8getBytes(), stat.getVersion());\n\t\t\t\t\tstat = await zk.existsAsync(name, watcher);\n\t\t\t\t\tawait zk.deleteAsync(name, stat.getVersion());\n\t\t\t\t}\n\n\t\t\t\tfor (int i = 0; i < names.Length; i++)\n\t\t\t\t{\n\t\t\t\t\tstring name = names[i];\n\t\t\t\t\tWatchedEvent @event = watcher.events.poll(10* 1000);\n\t\t\t\t\tAssert.assertEquals(name, @event.getPath());\n\t\t\t\t\tAssert.assertEquals(Watcher.Event.EventType.NodeDataChanged, @event.get_Type());\n\t\t\t\t\tAssert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n\t\t\t\t\t@event = watcher.events.poll(10* 1000);\n\t\t\t\t\tAssert.assertEquals(name, @event.getPath());\n\t\t\t\t\tAssert.assertEquals(Watcher.Event.EventType.NodeDeleted, @event.get_Type());\n\t\t\t\t\tAssert.assertEquals(Watcher.Event.KeeperState.SyncConnected, @event.getState());\n\t\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "src/csharp/test/xunit.runner.json",
    "content": "{\n  \"appDomain\": \"denied\",\n  \"diagnosticMessages\": true,\n  \"parallelizeTestCollections\": true,\n  \"methodDisplay\": \"classAndMethod\",\n  \"shadowCopy\": false\n}"
  },
  {
    "path": "src/docs/forrest.properties",
    "content": "# Copyright 2002-2004 The Apache Software Foundation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n##############\n# Properties used by forrest.build.xml for building the website\n# These are the defaults, un-comment them if you need to change them.\n##############\n\n# Prints out a summary of Forrest settings for this project\n#forrest.echo=true \n\n# Project name (used to name .war file)\n#project.name=my-project\n\n# Specifies name of Forrest skin to use\n#project.skin=tigris\n#project.skin=pelt\n\n# comma separated list, file:// is supported\n#forrest.skins.descriptors=http://forrest.apache.org/skins/skins.xml,file:///c:/myskins/skins.xml\n\n##############\n# behavioural properties\n#project.menu-scheme=tab_attributes\n#project.menu-scheme=directories\n\n##############\n# layout properties\n\n# Properties that can be set to override the default locations\n#\n# Parent properties must be set. This usually means uncommenting\n# project.content-dir if any other property using it is uncommented\n\n#project.status=status.xml\n#project.content-dir=src/documentation\nproject.configfile=${project.home}/src/documentation/conf/cli.xconf\n#project.raw-content-dir=${project.content-dir}/content\n#project.conf-dir=${project.content-dir}/conf\n#project.sitemap-dir=${project.content-dir}\n#project.xdocs-dir=${project.content-dir}/content/xdocs\n#project.resources-dir=${project.content-dir}/resources\n#project.stylesheets-dir=${project.resources-dir}/stylesheets\n#project.images-dir=${project.resources-dir}/images\n#project.schema-dir=${project.resources-dir}/schema\n#project.skins-dir=${project.content-dir}/skins\n#project.skinconf=${project.content-dir}/skinconf.xml\n#project.lib-dir=${project.content-dir}/lib\n#project.classes-dir=${project.content-dir}/classes\n#project.translations-dir=${project.content-dir}/translations\n\n##############\n# validation properties\n\n# This set of properties determine if validation is performed\n# Values are inherited unless overridden.\n# e.g. if forrest.validate=false then all others are false unless set to true.\nforrest.validate=true\nforrest.validate.xdocs=${forrest.validate}\nforrest.validate.skinconf=${forrest.validate}\nforrest.validate.stylesheets=${forrest.validate}\nforrest.validate.skins=${forrest.validate}\nforrest.validate.skins.stylesheets=${forrest.validate.skins}\n\n# Make Forrest work with JDK6\nforrest.validate.sitemap=false\n\n# *.failonerror=(true|false) - stop when an XML file is invalid\nforrest.validate.failonerror=true\n\n# *.excludes=(pattern) - comma-separated list of path patterns to not validate\n# e.g.\n#forrest.validate.xdocs.excludes=samples/subdir/**, samples/faq.xml\n#forrest.validate.xdocs.excludes=\n\n\n##############\n# General Forrest properties\n\n# The URL to start crawling from\n#project.start-uri=linkmap.html\n# Set logging level for messages printed to the console\n# (DEBUG, INFO, WARN, ERROR, FATAL_ERROR)\n#project.debuglevel=ERROR\n# Max memory to allocate to Java\n#forrest.maxmemory=64m\n# Any other arguments to pass to the JVM. For example, to run on an X-less\n# server, set to -Djava.awt.headless=true\n#forrest.jvmargs=\n# The bugtracking URL - the issue number will be appended\n#project.bugtracking-url=http://issues.apache.org/bugzilla/show_bug.cgi?id=\n#project.bugtracking-url=http://issues.apache.org/jira/browse/\n# The issues list as rss\n#project.issues-rss-url=\n#I18n Property only works for the \"forrest run\" target.\n#project.i18n=true\n\nproject.required.plugins=org.apache.forrest.plugin.output.pdf,org.apache.forrest.plugin.input.simplifiedDocbook\n"
  },
  {
    "path": "src/docs/src/documentation/README.txt",
    "content": "This is the base documentation directory.\n\nskinconf.xml     # This file customizes Forrest for your project. In it, you\n                 # tell forrest the project name, logo, copyright info, etc\n\nsitemap.xmap     # Optional. This sitemap is consulted before all core sitemaps.\n                 # See http://forrest.apache.org/docs/project-sitemap.html\n"
  },
  {
    "path": "src/docs/src/documentation/TODO.txt",
    "content": "This is a running list of todo documentation items. Feel free\nto add to the list or take on an item as you wish (in the form\nof a JIRA patch of course).\n-------------------------------------------------------------\n\nrecipes.xml:110:    \n[maybe an illustration would be nice for each recipe?]\n\nrecipes.xml:167:                     \n\"wait for each watch event\". [how do you wait?]\n\nrecipes.xml:457:          \n<remark>[tbd: myabe helpful to indicate which step this refers to?]</remark>\n\nzookeeperAdmin.xml:77:      \nbecause requires a majority <remark>[tbd: why?]</remark>, it is best to use...\n\nzookeeperAdmin.xml:112:   \n <screen>$yinst -i jdk-1.6.0.00_3 -br test  <remark>[y! prop - replace with open equiv]</remark></screen>\n \nzookeeperAdmin.xml:99:         \n- use a maximum heap size of 3GB for a 4GB machine.  <remark>[tbd:  where would they do this? Environment variable, etc?]</remark>\n\nzookeeperAdmin.xml:120\n<screen>$ yinst install -nostart zookeeper_server <remark>[Y! prop - replace with open eq]</remark></screen>\n\nzookeeperAdmin.xml:171:              \nIn Java, you can run the following command to execute simple operations:<remark> [tbd: also, maybe give some of those simple operations?]\n\nzookeeperAdmin.xml:194:          \nRunning either program gives you a shell in which to execute simple file-system-like operations. <remark>[tbd: again, sample\n          operations?]\n\nzookeeperAdmin.xml:252:       \nIf servers use different configuration files,\ncare must be taken to ensure that the list of servers in all of the\nstandard form, with legal values, etc]</remark>\n\nzookeeperAdmin.xml:408:\n(Note: The system property has no zookeeper\nprefix, and the configuration variable name is different from\nthe system property. Yes - it's not consistent, and it's\nannoying.<remark> [tbd: is there any explanation for\nthis?]</remark>)\n\t\t\nzookeeperAdmin.xml:445:               When the election algorithm is\n                \"0\" a UDP port with the same port number as the port listed in\n                the <emphasis role=\"bold\">server.num</emphasis> option will be\n                used. <remark>[tbd: should that be <emphasis\n                role=\"bold\">server.id</emphasis>? Also, why isn't server.id\n                documented anywhere?]</remark>\n\t\t\nzookeeperAdmin.xml:481:                The default to this option is yes, which\n                means that a leader will accept client connections.\n                <remark>[tbd: how do you specifiy which server is the\n                leader?]</remark>\n\t\t\nzookeeperAdmin.xml:495\t\tWhen the server\n                starts up, it determines which server it is by looking for the\n                file <filename>myid</filename> in the data directory.<remark>\n                [tdb: should we mention somewhere about creating this file,\n                myid, in the setup procedure?]</remark>\n\t\t\nzookeeperAdmin.xml:508:               [tbd: is the next sentence explanation an of what the\n                election port or is it a description of a special case?]\n                </remark>If you want to test multiple servers on a single\n                machine, the individual choices of electionPort for each\n                server can be defined in each server's config files using the\n                line electionPort=xxxx to avoid clashes.\n\t\t\nzookeeperAdmin.xml:524:               If followers fall too far behind a\n                leader, they will be dropped. <remark>[tbd: is this a correct\n                rewording: if followers fall beyond this limit, they are\n                dropped?]</remark>\n\t\t\nzookeeperAdmin.xml:551:               ZooKeeper will not require updates\n                to be synced to the media. <remark>[tbd: useful because...,\n                dangerous because...]</remark>\n\t\t\nzookeeperAdmin.xml:580:                Skips ACL checks. <remark>[tbd: when? where?]</remark>\n                \nzookeeperAdmin.xml:649:        <remark>[tbd: Patrick, Ben, et al: I believe the Message Broker\n        team does perform routine monitoring of Zookeeper. But I might be\n        wrong. To your knowledge, is there any monitoring of a Zookeeper\n        deployment that will a Zookeeper sys admin will want to do, outside of\n        Yahoo?]</remark>\n\t\nzookeeperAdmin.xml:755:            Also,\n            the server lists in each Zookeeper server configuration file\n            should be consistent with one another. <remark>[tbd: I'm assuming\n            this last part is true. Is it?]</remark>\n\t    \nzookeeperAdmin.xml:812:     For best results, take note of the following list of good\n      Zookeeper practices. <remark>[tbd: I just threw this section in. Do we\n      have list that is is different from the \"things to avoid\"? If not, I can\n      easily remove this section.]</remark>\n      \n\nzookeeperOver.xml:162:      Ephemeral nodes are useful when you\n      want to implement <remark>[tbd]</remark>.\n      \nzookeeperOver.xml:174:     And if the\n      connection between the client and one of the Zoo Keeper servers is\n      broken, the client will receive a local notification. These can be used\n      to <remark>[tbd]</remark>\n\nzookeeperOver.xml:215:            <para>For more information on these (guarantees), and how they can be used, see\n      <remark>[tbd]</remark></para>\n      \nzookeeperOver.xml:294:           <para><xref linkend=\"fg_zkComponents\" /> shows the high-level components\n      of the ZooKeeper service. With the exception of the request processor,\n      <remark>[tbd: where does the request processor live?]</remark> \n      \nzookeeperOver.xml:298:      <para><xref linkend=\"fg_zkComponents\" /> shows the high-level components\n      of the ZooKeeper service. With the exception of the request processor,\n     each of\n      the servers that make up the ZooKeeper service replicates its own copy\n      of each of components. <remark>[tbd: I changed the wording in this\n      sentence from the white paper. Can someone please make sure it is still\n      correct?]</remark>\n      \nzookeeperOver.xml:342:      The programming interface to ZooKeeper is deliberately simple.\n      With it, however, you can implement higher order operations, such as\n      synchronizations primitives, group membership, ownership, etc. Some\n      distributed applications have used it to: <remark>[tbd: add uses from\n      white paper and video presentation.]</remark> \n      \n\nzookeeperProgrammers.xml:94:              <listitem>\n        <para><xref linkend=\"ch_programStructureWithExample\" />\n        <remark>[tbd]</remark></para>\n      </listitem>\n      \nzookeeperProgrammers.xml:115:     Also,\n    the <ulink url=\"#ch_programStructureWithExample\">Simple Programmming\n    Example</ulink> <remark>[tbd]</remark> is helpful for understand the basic\n    structure of a ZooKeeper client application.\n    \nzookeeperProgrammers.xml:142:      The following characters are not\n\t\t\t\tallowed  because <remark>[tbd:\n\t\t\t\tdo we need reasons?]</remark> \n\nzookeeperProgrammers.xml:172:     If\n      the version it supplies doesn't match the actual version of the data,\n      the update will fail. (This behavior can be overridden. For more\n      information see... )<remark>[tbd... reference here to the section\n      describing the special version number -1]</remark>\n      \nzookeeperProgrammers.xml:197:        More information about watches can be\n        found in the section \n\t<ulink url=\"recipes.html#sc_recipes_Locks\">\n\tZookeeper Watches</ulink>.\n        <remark>[tbd: fix this link] [tbd: Ben there is note from to emphasize\n        that \"it is queued\". What is \"it\" and is what we have here\n        sufficient?]</remark></para>\n\t\nzookeeperProgrammers.xml:335:    it will send the session id as a part of the connection handshake.\n    As a security measure, the server creates a password for the session id\n    that any ZooKeeper server can validate. <remark>[tbd: note from Ben:\n    \"perhaps capability is a better word.\" need clarification on that.]\n    </remark>\n    \nzookeeperProgrammers.xml:601:              <ulink\n              url=\"recipes.html#sc_recipes_Locks\">Locks</ulink>\n              <remark>[tbd:...]</remark> in <ulink\n              url=\"recipes.html\">Zookeeper Recipes</ulink>.\n              <remark>[tbd:..]</remark>).</para>\n\t      \nzookeeperProgrammers.xml:766:             <para>See INSTALL for general information about running\n              <emphasis role=\"bold\">configure</emphasis>. <remark>[tbd: what\n              is INSTALL? a directory? a file?]</remark></para>\n\t     \n\t      \n\t      \nzookeeperProgrammers.xml:813:                <para>To verify that the node's been created:</para>\n\n        <para>You should see a list of node who are children of the root node\n        \"/\".</para><remark>[tbd: document all the cli commands (I think this is ben's comment)\n\nzookeeperProgrammers.xml:838:                <para>Refer to <xref linkend=\"ch_programStructureWithExample\"/>for examples of usage in Java and C.\n        <remark>[tbd]</remark></para>\n\nzookeeperProgrammers.xml 847: <remark>[tbd: This is a new section. The below\n    is just placeholder. Eventually, a subsection on each of those operations, with a little\n    bit of illustrative code for each op.] </remark>\n    \nzookeeperProgrammers.xml:915:    Program Structure, with Simple Example</title>\n\nzookeeperProgrammers.xml:999:        <term>ZooKeeper Whitepaper <remark>[tbd: find url]</remark></term>\n\nzookeeperProgrammers.xml:1008:        <term>API Reference <remark>[tbd: find url]</remark></term>\n\nzookeeperProgrammers.xml:1062:        [tbd]</remark></term><listitem>\n          <para>Any other good sources anyone can think of...</para>\n        </listitem>\n\nzookeeperStarted.xml:73:            <para>[tbd: should we start w/ a word here about were to get the source,\n      exactly what to download, how to unpack it, and where to put it? Also,\n      does the user need to be in sudo, or can they be under their regular\n      login?]</para>\n      \nzookeeperStarted.xml:84:      <para>This should generate a JAR file called zookeeper.jar. To start\n      Zookeeper, compile and run zookeeper.jar. <emphasis>[tbd, some more\n      instruction here. Perhaps a command line? Are these two steps or\n      one?]</emphasis></para>\n      \nzookeeperStarted.xml:139:      <para>ZooKeeper logs messages using log4j -- more detail available in\n      the <ulink url=\"zookeeperProgrammers.html#Logging\">Logging</ulink>\n      section of the Programmer's Guide.<remark revision=\"include_tbd\">[tbd:\n      real reference needed]</remark> \n      \nzookeeperStarted.xml:201:      The C bindings exist in two variants: single\n      threaded and multi-threaded. These differ only in how the messaging loop\n      is done. <remark>[tbd: what is the messaging loop? Do we talk about it\n      anywyhere? is this too much info for a getting started guide?]</remark>\n      \nzookeeperStarted.xml:217:      The entry <emphasis\n      role=\"bold\">syncLimit</emphasis> limits how far out of date a server can\n      be from a leader. [TBD: someone please verify that the previous is\n      true.] \n\nzookeeperStarted.xml:232:\tThese are the \"electionPort\" numbers of the servers (as opposed to\n      clientPorts), that is ports for <remark>[tbd: feedback need: what are\n      these ports, exactly?]\n      \nzookeeperStarted.xml:258:          <remark>[tbd: what is the other config param?\n          (I believe two are mentioned above.)]</remark>\n"
  },
  {
    "path": "src/docs/src/documentation/classes/CatalogManager.properties",
    "content": "# Copyright 2002-2004 The Apache Software Foundation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n#=======================================================================\n# CatalogManager.properties\n#\n# This is the default properties file for Apache Forrest.\n# This facilitates local configuration of application-specific catalogs.\n#\n# See the Apache Forrest documentation:\n# http://forrest.apache.org/docs/your-project.html\n# http://forrest.apache.org/docs/validation.html\n\n# verbosity ... level of messages for status/debug\n# See forrest/src/core/context/WEB-INF/cocoon.xconf\n\n# catalogs ... list of additional catalogs to load\n#  (Note that Apache Forrest will automatically load its own default catalog\n#  from src/core/context/resources/schema/catalog.xcat)\n# use full pathnames\n# pathname separator is always semi-colon (;) regardless of operating system\n# directory separator is always slash (/) regardless of operating system\n#\n#catalogs=/home/me/forrest/my-site/src/documentation/resources/schema/catalog.xcat\ncatalogs=\n\n"
  },
  {
    "path": "src/docs/src/documentation/conf/cli.xconf",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<!--+\n    |  This is the Apache Cocoon command line configuration file.\n    |  Here you give the command line interface details of where\n    |  to find various aspects of your Cocoon installation.\n    |\n    |  If you wish, you can also use this file to specify the URIs\n    |  that you wish to generate.\n    |\n    |  The current configuration information in this file is for\n    |  building the Cocoon documentation. Therefore, all links here\n    |  are relative to the build context dir, which, in the build.xml\n    |  file, is set to ${build.context}\n    |\n    |  Options:\n    |    verbose:            increase amount of information presented\n    |                        to standard output (default: false)\n    |    follow-links:       whether linked pages should also be\n    |                        generated (default: true)\n    |    precompile-only:    precompile sitemaps and XSP pages, but\n    |                        do not generate any pages (default: false)\n    |    confirm-extensions: check the mime type for the generated page\n    |                        and adjust filename and links extensions\n    |                        to match the mime type\n    |                        (e.g. text/html->.html)\n    |\n    |  Note: Whilst using an xconf file to configure the Cocoon\n    |        Command Line gives access to more features, the use of\n    |        command line parameters is more stable, as there are\n    |        currently plans to improve the xconf format to allow\n    |        greater flexibility. If you require a stable and\n    |        consistent method for accessing the CLI, it is recommended\n    |        that you use the command line parameters to configure\n    |        the CLI. See documentation at:\n    |        http://cocoon.apache.org/2.1/userdocs/offline/\n    |        http://wiki.apache.org/cocoon/CommandLine\n    |\n    +-->\n\n<cocoon verbose=\"true\"\n        follow-links=\"true\"\n        precompile-only=\"false\"\n        confirm-extensions=\"false\">\n\n   <!--+\n       |  The context directory is usually the webapp directory\n       |  containing the sitemap.xmap file.\n       |\n       |  The config file is the cocoon.xconf file.\n       |\n       |  The work directory is used by Cocoon to store temporary\n       |  files and cache files.\n       |\n       |  The destination directory is where generated pages will\n       |  be written (assuming the 'simple' mapper is used, see\n       |  below)\n       +-->\n   <context-dir>.</context-dir>\n   <config-file>WEB-INF/cocoon.xconf</config-file>\n   <work-dir>../tmp/cocoon-work</work-dir>\n   <dest-dir>../site</dest-dir>\n\n   <!--+\n       |  A checksum file can be used to store checksums for pages\n       |  as they are generated. When the site is next generated,\n       |  files will not be written if their checksum has not changed.\n       |  This means that it will be easier to detect which files\n       |  need to be uploaded to a server, using the timestamp.\n       |\n       |  The default path is relative to the core webapp directory.\n       |  An asolute path can be used.\n       +-->\n   <!--   <checksums-uri>build/work/checksums</checksums-uri>-->\n\n   <!--+\n       | Broken link reporting options:\n       |   Report into a text file, one link per line:\n       |     <broken-links type=\"text\" report=\"filename\"/>\n       |   Report into an XML file:\n       |     <broken-links type=\"xml\" report=\"filename\"/>\n       |   Ignore broken links (default):\n       |     <broken-links type=\"none\"/>\n       |\n       |   Two attributes to this node specify whether a page should\n       |   be generated when an error has occurred. 'generate' specifies\n       |   whether a page should be generated (default: true) and\n       |   extension specifies an extension that should be appended\n       |   to the generated page's filename (default: none)\n       |\n       |   Using this, a quick scan through the destination directory\n       |   will show broken links, by their filename extension.\n       +-->\n   <broken-links type=\"xml\"\n                 file=\"../brokenlinks.xml\"\n                 generate=\"false\"\n                 extension=\".error\"\n                 show-referrers=\"true\"/>\n\n   <!--+\n       |  Load classes at startup. This is necessary for generating\n       |  from sites that use SQL databases and JDBC.\n       |  The <load-class> element can be repeated if multiple classes\n       |  are needed.\n       +-->\n   <!--\n   <load-class>org.firebirdsql.jdbc.Driver</load-class>\n   -->\n\n   <!--+\n       |  Configures logging.\n       |  The 'log-kit' parameter specifies the location of the log kit\n       |  configuration file (usually called logkit.xconf.\n       |\n       |  Logger specifies the logging category (for all logging prior\n       |  to other Cocoon logging categories taking over)\n       |\n       |  Available log levels are:\n       |    DEBUG:        prints all level of log messages.\n       |    INFO:         prints all level of log messages except DEBUG\n       |                  ones.\n       |    WARN:         prints all level of log messages except DEBUG\n       |                  and INFO ones.\n       |    ERROR:        prints all level of log messages except DEBUG,\n       |                  INFO and WARN ones.\n       |    FATAL_ERROR:  prints only log messages of this level\n       +-->\n   <!-- <logging log-kit=\"WEB-INF/logkit.xconf\" logger=\"cli\" level=\"ERROR\" /> -->\n\n   <!--+\n       |  Specifies the filename to be appended to URIs that\n       |  refer to a directory (i.e. end with a forward slash).\n       +-->\n   <default-filename>index.html</default-filename>\n\n   <!--+\n       |  Specifies a user agent string to the sitemap when\n       |  generating the site.\n       |\n       |  A generic term for a web browser is \"user agent\". Any\n       |  user agent, when connecting to a web server, will provide\n       |  a string to identify itself (e.g. as Internet Explorer or\n       |  Mozilla). It is possible to have Cocoon serve different\n       |  content depending upon the user agent string provided by\n       |  the browser. If your site does this, then you may want to\n       |  use this <user-agent> entry to provide a 'fake' user agent\n       |  to Cocoon, so that it generates the correct version of your\n       |  site.\n       |\n       |  For most sites, this can be ignored.\n       +-->\n   <!--\n   <user-agent>Cocoon Command Line Environment 2.1</user-agent>\n   -->\n\n   <!--+\n       |  Specifies an accept string to the sitemap when generating\n       |  the site.\n       |  User agents can specify to an HTTP server what types of content\n       |  (by mime-type) they are able to receive. E.g. a browser may be\n       |  able to handle jpegs, but not pngs. The HTTP accept header\n       |  allows the server to take the browser's capabilities into account,\n       |  and only send back content that it can handle.\n       |\n       |  For most sites, this can be ignored.\n       +-->\n\n   <accept>*/*</accept>\n\n   <!--+\n       | Specifies which URIs should be included or excluded, according\n       | to wildcard patterns.\n       |\n       | These includes/excludes are only relevant when you are following\n       | links. A link URI must match an include pattern (if one is given)\n       | and not match an exclude pattern, if it is to be followed by\n       | Cocoon. It can be useful, for example, where there are links in\n       | your site to pages that are not generated by Cocoon, such as\n       | references to api-documentation.\n       |\n       | By default, all URIs are included. If both include and exclude\n       | patterns are specified, a URI is first checked against the\n       | include patterns, and then against the exclude patterns.\n       |\n       | Multiple patterns can be given, using muliple include or exclude\n       | nodes.\n       |\n       | The order of the elements is not significant, as only the first\n       | successful match of each category is used.\n       |\n       | Currently, only the complete source URI can be matched (including\n       | any URI prefix). Future plans include destination URI matching\n       | and regexp matching. If you have requirements for these, contact\n       | dev@cocoon.apache.org.\n       +-->\n\n   <exclude pattern=\"**/\"/>\n   <exclude pattern=\"**apidocs**\"/>\n   <exclude pattern=\"api/**\"/>\n\n   <!-- ZOOKEEPER-2364 - we build our own release notes separately -->\n   <exclude pattern=\"releasenotes.**\"/>\n\n<!--\n  This is a workaround for FOR-284 \"link rewriting broken when\n  linking to xml source views which contain site: links\".\n  See the explanation there and in declare-broken-site-links.xsl\n-->\n   <exclude pattern=\"site:**\"/>\n   <exclude pattern=\"ext:**\"/>\n   <exclude pattern=\"lm:**\"/>\n   <exclude pattern=\"**/site:**\"/>\n   <exclude pattern=\"**/ext:**\"/>\n   <exclude pattern=\"**/lm:**\"/>\n\n   <!-- Exclude tokens used in URLs to ASF mirrors (interpreted by a CGI) -->\n   <exclude pattern=\"[preferred]/**\"/>\n   <exclude pattern=\"[location]\"/>\n\n   <!--   <include-links extension=\".html\"/>-->\n\n   <!--+\n       |  <uri> nodes specify the URIs that should be generated, and\n       |  where required, what should be done with the generated pages.\n       |  They describe the way the URI of the generated file is created\n       |  from the source page's URI. There are three ways that a generated\n       |  file URI can be created: append, replace and insert.\n       |\n       |  The \"type\" attribute specifies one of (append|replace|insert):\n       |\n       |  append:\n       |  Append the generated page's URI to the end of the source URI:\n       |\n       |   <uri type=\"append\" src-prefix=\"documents/\" src=\"index.html\"\n       |   dest=\"build/dest/\"/>\n       |\n       |  This means that\n       |   (1) the \"documents/index.html\" page is generated\n       |   (2) the file will be written to \"build/dest/documents/index.html\"\n       |\n       |  replace:\n       |  Completely ignore the generated page's URI - just\n       |  use the destination URI:\n       |\n       |   <uri type=\"replace\" src-prefix=\"documents/\" src=\"index.html\"\n       |   dest=\"build/dest/docs.html\"/>\n       |\n       |  This means that\n       |   (1) the \"documents/index.html\" page is generated\n       |   (2) the result is written to \"build/dest/docs.html\"\n       |   (3) this works only for \"single\" pages - and not when links\n       |       are followed\n       |\n       |  insert:\n       |  Insert generated page's URI into the destination\n       |  URI at the point marked with a * (example uses fictional\n       |  zip protocol)\n       |\n       |   <uri type=\"insert\" src-prefix=\"documents/\" src=\"index.html\"\n       |   dest=\"zip://*.zip/page.html\"/>\n       |\n       |  This means that\n       |   (1)\n       |\n       |  In any of these scenarios, if the dest attribute is omitted,\n       |  the value provided globally using the <dest-dir> node will\n       |  be used instead.\n       +-->\n   <!--\n   <uri type=\"replace\"\n        src-prefix=\"samples/\"\n        src=\"hello-world/hello.html\"\n        dest=\"build/dest/hello-world.html\"/>\n   -->\n\n   <!--+\n       | <uri> nodes can be grouped together in a <uris> node. This\n       | enables a group of URIs to share properties. The following\n       | properties can be set for a group of URIs:\n       |   * follow-links:       should pages be crawled for links\n       |   * confirm-extensions: should file extensions be checked\n       |                         for the correct mime type\n       |   * src-prefix:         all source URIs should be\n       |                         pre-pended with this prefix before\n       |                         generation. The prefix is not\n       |                         included when calculating the\n       |                         destination URI\n       |   * dest:               the base destination URI to be\n       |                         shared by all pages in this group\n       |   * type:               the method to be used to calculate\n       |                         the destination URI. See above\n       |                         section on <uri> node for details.\n       |\n       | Each <uris> node can have a name attribute. When a name\n       | attribute has been specified, the -n switch on the command\n       | line can be used to tell Cocoon to only process the URIs\n       | within this URI group. When no -n switch is given, all\n       | <uris> nodes are processed. Thus, one xconf file can be\n       | used to manage multiple sites.\n       +-->\n   <!--\n   <uris name=\"mirrors\" follow-links=\"false\">\n     <uri type=\"append\" src=\"mirrors.html\"/>\n   </uris>\n   -->\n\n   <!--+\n       |  File containing URIs (plain text, one per line).\n       +-->\n   <!--\n   <uri-file>uris.txt</uri-file>\n   -->\n</cocoon>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/bookkeeperConfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_Admin\">\n  <title>BookKeeper Administrator's Guide</title>\n\n  <subtitle>Setup Guide</subtitle>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.\n      </para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.\n      </para>\n    </legalnotice>\n\n    <abstract>\n      <para>This document contains information about deploying, administering\n      and mantaining BookKeeper. It also discusses best practices and common\n      problems.\n      </para>\n\t  <para> As BookKeeper is still a prototype, this article is likely to change\n\t  significantly over time. \n\t  </para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"bk_deployment\">\n    <title>Deployment</title>\n\n    <para>This section contains information about deploying BookKeeper and\n    covers these topics:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"bk_sysReq\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"bk_runningBookies\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"bk_zkMetadata\" /></para>\n      </listitem>\n    </itemizedlist>\n    \n    <para> The first section tells you how many machines you need. The second explains how to bootstrap bookies\n     (BookKeeper storage servers). The third section explains how we use ZooKeeper and our requirements with\n     respect to ZooKeeper.\n    </para>\n    \n    <section id=\"bk_sysReq\">\n \t   <title>System requirements</title>\n \t   <para> A typical BookKeeper installation comprises a set of bookies and a set of ZooKeeper replicas. The exact number of bookies\n \t   depends on the quorum mode, desired throughput, and number of clients using this installation simultaneously. The minimum number of\n \t   bookies is three for self-verifying (stores a message authentication code along with each entry) and four for generic (does not\n \t   store a message authentication codewith each entry), and there is no upper limit on the number of bookies. Increasing the number of \n \t   bookies, in fact, enables higher throughput.\n \t   </para>\n \t   \n \t   <para> For performance, we require each server to have at least two disks. It is possible to run a bookie with a single disk, but \n \t   performance will be significantly lower in this case. Of course, it works with one disk, but performance is significantly lower. \n \t   </para>\n\n \t   <para> For ZooKeeper, there is no constraint with respect to the number of replicas. Having a single machine running ZooKeeper\n \t   in standalone mode is sufficient for BookKeeper. For resilience purposes, it might be a good idea to run ZooKeeper in quorum \n \t   mode with multiple servers. Please refer to the ZooKeeper documentation for detail on how to configure ZooKeeper with multiple\n \t   replicas\n \t   </para>    \n     </section>\n     \n     <section id=\"bk_runningBookies\">\n \t   <title>Running bookies</title>\n \t   <para>\n \t   To run a bookie, we execute the following command:\n \t   </para>\n \t   \n \t   <para><computeroutput>\n\t\tjava -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\\\n\t\t:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\\ \n\t\torg.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\\\n\t\t/path_to_ledger_device/\n\t   </computeroutput></para>\n \t   \n \t   <para>\n \t   The parameters are:\n \t   </para>\n \t   \n \t   <itemizedlist>\n \t   \t<listitem>\n \t   \t<para>\n \t   \t\tPort number that the bookie listens on;\n \t   \t</para>\n \t   \t</listitem>\n \t   \t\n \t   \t<listitem>\n \t   \t<para>\n \t   \t\tComma separated list of ZooKeeper servers with a hostname:port format;\n \t   \t</para>\n \t   \t</listitem>\n \t   \t\n \t   \t<listitem>\n \t   \t<para>\n \t   \t\tPath for Log Device (stores bookie write-ahead log);\n \t   \t</para>\n \t   \t</listitem>\n \t   \t\n \t   \t<listitem>\n \t   \t<para>\n \t   \t\tPath for Ledger Device (stores ledger entries);\n \t   \t</para>\n \t   \t</listitem>\n \t   </itemizedlist>\n \t   \n \t   <para>\n \t   Ideally, <computeroutput>/path_to_log_device/ </computeroutput> and <computeroutput>/path_to_ledger_device/ </computeroutput> are each\n \t   in a different device. \n \t   </para>\n \t </section>\n \t \n \t <section id=\"bk_zkMetadata\">\n \t   <title>ZooKeeper Metadata</title>\n \t   <para>\n \t   For BookKeeper, we require a ZooKeeper installation to store metadata, and to pass the list\n \t   of ZooKeeper servers as parameter to the constructor of the BookKeeper class (<computeroutput>\n \t   org.apache.bookkeeper.client,BookKeeper</computeroutput>).\n \t   To setup ZooKeeper, please check the <ulink url=\"index.html\">\n          ZooKeeper documentation</ulink>.\n \t   </para>\n \t </section>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/bookkeeperOverview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_GettStartedGuide\">\n  <title>BookKeeper overview</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about using BookKeeper\n      for logging. It discusses the basic operations BookKeeper supports, \n      and how to create logs and perform basic read and write operations on these\n      logs.</para>\n    </abstract>\n  </articleinfo>\n  <section id=\"bk_Overview\">\n  <title>BookKeeper overview</title>\n    \n  <section id=\"bk_Intro\">\n    <title>BookKeeper introduction</title>\n\t<para>\n\tBookKeeper is a replicated service to reliably log streams of records. In BookKeeper, \n\tservers are \"bookies\", log streams are \"ledgers\", and each unit of a log (aka record) is a \n\t\"ledger entry\". BookKeeper is designed to be reliable; bookies, the servers that store \n\tledgers, can crash, corrupt data, discard data, but as long as there are enough bookies \n\tbehaving correctly the service as a whole behaves correctly.\n\t</para>\n\n\t<para>\n    The initial motivation for BookKeeper comes from the namenode of HDFS. Namenodes have to \n    log operations in a reliable fashion so that recovery is possible in the case of crashes. \n    We have found the applications for BookKeeper extend far beyond HDFS, however. Essentially, \n    any application that requires an append storage can replace their implementations with\n    BookKeeper. BookKeeper has the advantage of scaling throughput with the number of servers. \n    </para>\n\t\n\t<para>\n    At a high level, a bookkeeper client receives entries from a client application and stores it to\n    sets of bookies, and there are a few advantages in having such a service:\n\t</para>\n\n\t<itemizedlist>\n    <listitem>\n    <para>\n    \tWe can use hardware that is optimized for such a service. We currently believe that such a\n      \tsystem has to be optimized only for disk I/O;\n    </para>\n    </listitem>\n    \n    <listitem>\n    <para>\n    \tWe can have a pool of servers implementing such a log system, and shared among a number of servers;\n    </para>\n    </listitem>\n    \n    <listitem>\n    <para>\n    \tWe can have a higher degree of replication with such a pool, which makes sense if the hardware necessary for it is cheaper compared to the one the application uses. \n\t</para>\n\t</listitem>\n\t</itemizedlist>\n\n\t</section>\n\t\n\t<section id=\"bk_moreDetail\">\n    <title>In slightly more detail...</title>\n    \n    <para> BookKeeper implements highly available logs, and it has been designed with write-ahead logging in mind. Besides high availability\n    due to the replicated nature of the service, it provides high throughput due to striping. As we write entries in a subset of bookies of an\n    ensemble and rotate writes across available quorums, we are able to increase throughput with the number of servers for both reads and writes. \n    Scalability is a property that is possible to achieve in this case due to the use of quorums. Other replication techniques, such as \n    state-machine replication, do not enable such a property. \n    </para> \n    \n\t<para> An application first creates a ledger before writing to bookies through a local BookKeeper client instance.   \n  \tUpon creating a ledger, a BookKeeper client writes metadata about the ledger to ZooKeeper. Each ledger currently \n  \thas a single writer. This writer has to execute a close ledger operation before any other client can read from it. \n  \tIf the writer of a ledger does not close a ledger properly because, for example, it has crashed before having the \n  \topportunity of closing the ledger, then the next client that tries to open a ledger executes a procedure to recover\n  \tit. As closing a ledger consists essentially of writing the last entry written to a ledger to ZooKeeper, the recovery\n  \tprocedure simply finds the last entry written correctly and writes it to ZooKeeper.\t\n\t</para>\n\t\t\n\t<para>\n\tNote that currently this recovery procedure is executed automatically upon trying to open a ledger and no explicit action is necessary. \n\tAlthough two clients may try to recover a ledger concurrently, only one will succeed, the first one that is able to create the close znode\n\tfor the ledger.\n\t</para> \n\t</section>  \n\t   \n    <section id=\"bk_basicComponents\">\n    <title>Bookkeeper elements and concepts</title>\n\t<para> \n\tBookKeeper uses four basic elements:\n\t</para>\n\t\n\t<itemizedlist>\n      <listitem>\n      <para> \n\t\t<emphasis role=\"bold\">Ledger</emphasis>: A ledger is a sequence of entries, and each entry is a sequence of bytes. Entries are\n\t\twritten sequentially to a ledger and at most once. Consequently, ledgers have an append-only semantics;\n\t  </para>\n\t  </listitem>\n\t\n\t  <listitem>\n\t  <para> \n\t\t<emphasis role=\"bold\">BookKeeper client</emphasis>: A client runs along with a BookKeeper application, and it enables applications\n\t\tto execute operations on ledgers, such as creating a ledger and writing to it; \n\t  </para>\n\t  </listitem> \n\t\n\t  <listitem>\n\t  <para>\n\t\t<emphasis role=\"bold\">Bookie</emphasis>: A bookie is a BookKeeper storage server. Bookies store the content of ledgers. For any given\n\t\tledger L, we call an <emphasis>ensemble</emphasis> the group of bookies storing the content of L. For performance, we store on\n\t\teach bookie of an ensemble only a fragment of a ledger. That is, we stripe when writing entries to a ledger such that\n\t\teach entry is written to sub-group of bookies of the ensemble.\n\t  </para>\n\t  </listitem>\n\n\t  <listitem>\n\t  <para> \t\n\t\t<emphasis role=\"bold\">Metadata storage service</emphasis>: BookKeeper requires a metadata storage service to store information related \n\t\tto ledgers and available bookies. We currently use ZooKeeper for such a task.     \n   \t  </para>\n   \t  </listitem>\n    </itemizedlist>\n    </section>\n    \n    <section id=\"bk_initialDesign\">\n    <title>Bookkeeper initial design</title>\n    <para>\n    A set of bookies implements BookKeeper, and we use a quorum-based protocol to replicate data across the bookies. \n    There are basically two operations to an existing ledger: read and append. Here is the complete API list \n    (mode detail <ulink url=\"bookkeeperProgrammer.html\">\n    \t      here</ulink>):\n\t</para>\n\t\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n    \tCreate ledger: creates a new empty ledger; \n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    \tOpen ledger: opens an existing ledger for reading;\n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    \tAdd entry: adds a record to a ledger either synchronously or asynchronously;\n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    Read entries: reads a sequence of entries from a ledger either synchronously or asynchronously \n\t</para>\n    </listitem>\n\t</itemizedlist>\n\n\t<para>\n\tThere is only a single client that can write to a ledger. Once that ledger is closed or the client fails, \n\tno more entries can be added. (We take advantage of this behavior to provide our strong guarantees.) \n\tThere will not be gaps in the ledger. Fingers get broken, people get roughed up or end up in prison when\n\tbooks are manipulated, so there is no deleting or changing of entries.\n\t</para>\n\n\t<figure>\n        <title>BookKeeper Overview</title>\n\t\n\t\t<mediaobject>\n        <imageobject>\n            <imagedata fileref=\"images/bk-overview.jpg\" width=\"3in\" depth=\"3in\" contentwidth=\"3in\" contentdepth=\"3in\" scalefit=\"0\"/>\n        </imageobject>\n        </mediaobject>\n    </figure>\n\n\t<para>\n    A simple use of BooKeeper is to implement a write-ahead transaction log. A server maintains an in-memory data structure\n    (with periodic snapshots for example) and logs changes to that structure before it applies the change. The application \n    server creates a ledger at startup and store the ledger id and password in a well known place (ZooKeeper maybe). When \n    it needs to make a change, the server adds an entry with the change information to a ledger and apply the change when \n    BookKeeper adds the entry successfully. The server can even use asyncAddEntry to queue up many changes for high change\n    throughput. BooKeeper meticulously logs the changes in order and call the completion functions in order.\n\t</para>\n\n\t<para>\n    When the application server dies, a backup server will come online, get the last snapshot and then it will open the \n    ledger of the old server and read all the entries from the time the snapshot was taken. (Since it doesn't know the \n    last entry number it will use MAX_INTEGER). Once all the entries have been processed, it will close the ledger and \n    start a new one for its use. \n\t</para>\n\t\n\t<para>\n\tA client library takes care of communicating with bookies and managing entry numbers. An entry has the following fields:\n\t</para>\n\n\t<table frame='all'><title>Entry fields</title>\n\t<tgroup cols='3' align='left' colsep='1' rowsep='1'>\n\t<colspec colname='Field'/>\n\t<colspec colname='Type'/>\n\t<colspec colname='Description'/>\n\t<colspec colnum='5' colname='c5'/>\n\t<thead>\n\t<row>\n  \t<entry>Field</entry>\n  \t<entry>Type</entry>\n  \t<entry>Description</entry>\n\t</row>\n\t</thead>\n\t<tfoot>\n\t<row>\n  \t<entry>Ledger number</entry>\n  \t<entry>long</entry>\n  \t<entry>The id of the ledger of this entry</entry>\n\t</row>\n\t<row>\n  \t<entry>Entry number</entry>\n  \t<entry>long</entry>\n  \t<entry>The id of this entry</entry>\n\t</row>\n\t</tfoot>\n\t<tbody>\n\t<row>\n  \t<entry>last confirmed (<emphasis>LC</emphasis>)</entry>\n  \t<entry>long</entry>\n  \t<entry>id of the last recorded entry</entry>\n\t</row>\n\t<row>\n  \t<entry>data</entry>\n  \t<entry>byte[]</entry>\n  \t<entry>the entry data (supplied by application)</entry>\n\t</row>\n\t<row>\n  \t<entry>authentication code</entry>\n  \t<entry>byte[]</entry>\n  \t<entry>Message authentication code that includes all other fields of the entry</entry>\n\t</row>\n\t\n\t</tbody>\n\t</tgroup>\n\t</table>\n\n\t<para>\n\tThe client library generates a ledger entry. None of the fields are modified by the bookies and only the first three \n\tfields are interpreted by the bookies.\n\t</para>\n\n\t<para>\n\tTo add to a ledger, the client generates the entry above using the ledger number. The entry number will be one more \n\tthan the last entry generated. The <emphasis>LC</emphasis> field contains the last entry that has been successfully recorded by BookKeeper. \n\tIf the client writes entries one at a time, <emphasis>LC</emphasis> is the last entry id. But, if the client is using asyncAddEntry, there \n\tmay be many entries in flight. An entry is considered recorded when both of the following conditions are met:\n\t</para>\n\n\t<itemizedlist>\n\t<listitem>\n    <para>\n    \tthe entry has been accepted by a quorum of bookies\n    </para>\n    </listitem>\n    \n    <listitem>\n    <para>\n    \tall entries with a lower entry id have been accepted by a quorum of bookies \n\t</para>\n\t</listitem>\n    </itemizedlist>\n    \n    <para>\n\t<emphasis>LC</emphasis> seems mysterious right now, but it is too early to explain how we use it; just smile and move on.\n\t</para>\n\t\n\t<para>\n\tOnce all the other fields have been field in, the client generates an authentication code with all of the previous fields. \n\tThe entry is then sent to a quorum of bookies to be recorded. Any failures will result in the entry being sent to a new\n\tquorum of bookies.\n\t</para>\n\n\t<para>\n\tTo read, the client library initially contacts a bookie and starts requesting entries. If an entry is missing or \n\tinvalid (a bad MAC for example), the client will make a request to a different bookie. By using quorum writes, \n\tas long as enough bookies are up we are guaranteed to eventually be able to read an entry.\n\t</para>\n\t\n\t</section>\n\n\t<section id=\"bk_metadata\">\n    <title>Bookkeeper metadata management</title>\n\n\t<para>\n\tThere are some meta data that needs to be made available to BookKeeper clients:\n\t</para>\n\t\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n\t\tThe available bookies;\n\t</para>\n\t</listitem>\n\t\n\t<listitem>\n\t<para>\n    \tThe list of ledgers;\n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    \tThe list of bookies that have been used for a given ledger;\n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    \tThe last entry of a ledger; \n\t</para>\n\t</listitem>\n\t</itemizedlist>\n\t\n\t<para>\n\tWe maintain this information in ZooKeeper. Bookies use ephemeral nodes to indicate their availability. Clients \n\tuse znodes to track ledger creation and deletion and also to know the end of the ledger and the bookies that \n\twere used to store the ledger. Bookies also watch the ledger list so that they can cleanup ledgers that get deleted.\n\t</para>\n\t\n\t</section>\n\n\t<section id=\"bk_closingOut\">\n    <title>Closing out ledgers</title>\n\n\t<para>\n\tThe process of closing out the ledger and finding the last ledger is difficult due to the durability guarantees of BookKeeper:\n\t</para>\n\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n    \tIf an entry has been successfully recorded, it must be readable.\n    </para>\n    </listitem>\n    \n    <listitem>\n\t<para>\n    \tIf an entry is read once, it must always be available to be read. \n\t</para>\n\t</listitem>\n\t</itemizedlist>\n\t\n\t<para>\n\tIf the ledger was closed gracefully, ZooKeeper will have the last entry and everything will work well. But, if the \n\tBookKeeper client that was writing the ledger dies, there is some recovery that needs to take place.\n\t</para>\n\n\t<para>\n\tThe problematic entries are the ones at the end of the ledger. There can be entries in flight when a BookKeeper client \n\tdies. If the entry only gets to one bookie, the entry should not be readable since the entry will disappear if that bookie\n\tfails. If the entry is only on one bookie, that doesn't mean that the entry has not been recorded successfully; the other\n\tbookies that recorded the entry might have failed.\n\t</para>\n\t\n\t<para>\n\tThe trick to making everything work is to have a correct idea of a last entry. We do it in roughly three steps:\n\t</para>\n\t<orderedlist>\n\t<listitem>\n\t<para>\n\t\tFind the entry with the highest last recorded entry, <emphasis>LC</emphasis>;\n\t</para>\n\t</listitem>\n\t\n\t<listitem>\n\t<para>\n\t\tFind the highest consecutively recorded entry, <emphasis>LR</emphasis>;\n\t</para>\n\t</listitem>\n\t\n\t<listitem>\n\t<para>\n\t\tMake sure that all entries between <emphasis>LC</emphasis> and <emphasis>LR</emphasis> are on a quorum of bookies; \n\t</para>\n\t</listitem>\n\t\n\t</orderedlist>\n    </section>\n  </section>  \n</article>"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/bookkeeperProgrammer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_GettStartedGuide\">\n  <title>BookKeeper Getting Started Guide</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about using BookKeeper\n      for logging. It discusses the basic operations BookKeeper supports, \n      and how to create logs and perform basic read and write operations on these\n      logs.</para>\n    </abstract>\n  </articleinfo>\n  <section id=\"bk_GettingStarted\">\n    <title>Programming with BookKeeper</title>\n    \n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"bk_instance\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"bk_createLedger\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"bk_writeLedger\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"bk_closeLedger\" /></para>\n      </listitem>\n      \n\t  <listitem>\n        <para><xref linkend=\"bk_openLedger\" /></para>\n      </listitem>\n      \n      <listitem>\n        <para><xref linkend=\"bk_readLedger\" /></para>\n      </listitem>\n      \n      <listitem>\n        <para><xref linkend=\"bk_deleteLedger\" /></para>\n      </listitem>\n      \n    </itemizedlist>\n    \n    <section id=\"bk_instance\">\n    <title> Instantiating BookKeeper.</title>\n    <para>\n    The first step to use BookKeeper is to instantiate a BookKeeper object:\n    </para>\n    <para>\n    <computeroutput>\n    org.apache.bookkeeper.BookKeeper\n    </computeroutput>\n    </para>\n    \n    <para>\n    There are three BookKeeper constructors:\n    </para>\n    \n    <para>\n    <computeroutput>\n\tpublic BookKeeper(String servers) \n    \tthrows KeeperException, IOException    \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>servers</computeroutput> is a comma-separated list of ZooKeeper servers.\n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n\n    <para>\n    <computeroutput>\n\tpublic BookKeeper(ZooKeeper zk) \n    \tthrows InterruptedException, KeeperException    \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>zk</computeroutput> is a ZooKeeper object. This constructor is useful when\n        the application also using ZooKeeper and wants to have a single instance of ZooKeeper.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n\n\n    <para>\n    <computeroutput>\n\tpublic BookKeeper(ZooKeeper zk, ClientSocketChannelFactory channelFactory) \n    \tthrows InterruptedException, KeeperException    \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>zk</computeroutput> is a ZooKeeper object. This constructor is useful when\n        the application also using ZooKeeper and wants to have a single instance of ZooKeeper.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para> \n        <computeroutput>channelFactory</computeroutput> is a netty channel object \n        (<computeroutput>org.jboss.netty.channel.socket</computeroutput>).  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n\n\n        \n    </section>\n    \n    <section id=\"bk_createLedger\">\n    <title> Creating a ledger. </title>\n    \n    <para> Before writing entries to BookKeeper, it is necessary to create a ledger. \n    With the current BookKeeper API, it is possible to create a ledger both synchronously\n    or asynchronously. The following methods belong\n    to <computeroutput>org.apache.bookkeeper.client.BookKeeper</computeroutput>.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Synchronous call:</emphasis>\n   \t</para>\n   \t\n   \t<para>\n    <computeroutput>\n    public LedgerHandle createLedger(int ensSize, int qSize, DigestType type,  byte passwd[])\n        throws KeeperException, InterruptedException, \n        IOException, BKException\n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n    \t<computeroutput>ensSize</computeroutput> is the number of bookies (ensemble size);\n    \t</para>\n    \t</listitem>\n    \n    \t<listitem> \n    \t<para>\n    \t<computeroutput>qSize</computeroutput> is the write quorum size;\n    \t</para>\n    \t</listitem>\n    \n    \t<listitem> \n    \t<para>\n    \t<computeroutput>type</computeroutput> is the type of digest used with entries: either MAC or CRC32.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para>\n    \t<computeroutput>passwd</computeroutput> is a password that authorizes the client to write to the\n    \tledger being created.\n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n    <para>\n    All further operations on a ledger are invoked through the <computeroutput>LedgerHandle</computeroutput>\n    object returned.\n    </para>\n    \n    <para>\n    As a convenience, we provide a <computeroutput>createLedger</computeroutput> with default parameters (3,2,VERIFIABLE), \n    and the only two input parameters it requires are a digest type and a password.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous call:</emphasis>\n   \t</para>\n    \n    <para>\n    <computeroutput>\n    public void asyncCreateLedger(int ensSize, \n            int qSize, \n            DigestType type,  \n            byte passwd[],\n            CreateCallback cb,\n            Object ctx\n            )\n    </computeroutput>\n\t</para>\n\t\n    <para>\n\tThe parameters are the same of the synchronous version, with the\n\texception of <computeroutput>cb</computeroutput> and <computeroutput>ctx</computeroutput>. <computeroutput>CreateCallback</computeroutput>\n\tis an interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>createComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tvoid createComplete(int rc, LedgerHandle lh, Object ctx);\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKException</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>lh</computeroutput> is a <computeroutput>LedgerHandle</computeroutput> object to manipulate a ledger;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is a control object for accountability purposes. It can be essentially any object the application is happy with.\n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t\n\t\n\t<para>\n\tThe <computeroutput>ctx</computeroutput> object passed as a parameter to the call to create a ledger\n\tis the one same returned in the callback.\n    </para>\n    </section>\n    \n    <section id=\"bk_writeLedger\">\n    <title> Adding entries to a ledger. </title>\n    <para>\n    Once we have a ledger handle <computeroutput>lh</computeroutput> obtained through a call to create a ledger, we\n    can start writing entries. As with creating ledgers, we can write both synchronously and \n    asynchronously. The following methods belong\n    to <computeroutput>org.apache.bookkeeper.client.LedgerHandle</computeroutput>.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Synchronous call:</emphasis>\n   \t</para>\n   \t\n   \t<para>\n    <computeroutput>\n\tpublic long addEntry(byte[] data)\n    \tthrows InterruptedException\n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    \n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n    \t<computeroutput>data</computeroutput> is a byte array;\n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n    <para>\n\tA call to <computeroutput>addEntry</computeroutput> returns the status of the operation (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous call:</emphasis>\n   \t</para>\n\n\t<para>\n    <computeroutput>\n\tpublic void asyncAddEntry(byte[] data, AddCallback cb, Object ctx)\n    </computeroutput>\n\t</para>\n\t\n    <para>\n    It also takes a byte array as the sequence of bytes to be stored as an entry. Additionaly, it takes\n    a callback object <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement\n    the <computeroutput>AddCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>addComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tvoid addComplete(int rc, LedgerHandle lh, long entryId, Object ctx);\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>lh</computeroutput> is a <computeroutput>LedgerHandle</computeroutput> object to manipulate a ledger;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>entryId</computeroutput> is the identifier of entry associated with this request;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is control object used for accountability purposes. It can be any object the application is happy with.\n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t \n    </section>\n    \n    <section id=\"bk_closeLedger\">\n    <title> Closing a ledger. </title>\n    <para>\n    Once a client is done writing, it closes the ledger. The following methods belong\n    to <computeroutput>org.apache.bookkeeper.client.LedgerHandle</computeroutput>.\n    </para>\n    <para>\n   \t<emphasis role=\"bold\">Synchronous close:</emphasis>\n   \t</para>\n    \n    <para>\n    <computeroutput>\n\tpublic void close() \n    throws InterruptedException\n    </computeroutput>\n\t</para>\n\n    <para>\n    It takes no input parameters.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous close:</emphasis>\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic void asyncClose(CloseCallback cb, Object ctx)\n    throws InterruptedException\n    </computeroutput>\n\t</para>\n\t\n    <para>\n    It takes a callback object <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement\n    the <computeroutput>CloseCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>closeComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tvoid closeComplete(int rc, LedgerHandle lh, Object ctx)\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>lh</computeroutput> is a <computeroutput>LedgerHandle</computeroutput> object to manipulate a ledger;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is control object used for accountability purposes. \n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t\n    \n    </section>\n    \n    <section id=\"bk_openLedger\">\n    <title> Opening a ledger. </title>\n    <para>\n    To read from a ledger, a client must open it first. The following methods belong\n    to <computeroutput>org.apache.bookkeeper.client.BookKeeper</computeroutput>.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Synchronous open:</emphasis>\n   \t</para>\n    \n    <para>\n    <computeroutput>\n\tpublic LedgerHandle openLedger(long lId, DigestType type, byte passwd[])\n    throws InterruptedException, BKException\n    </computeroutput>\n\t</para>\n\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n\t<computeroutput>ledgerId</computeroutput> is the ledger identifier;\n\t</para>\n\t</listitem>\n\t\n\t<listitem> \n    <para>\n    <computeroutput>type</computeroutput> is the type of digest used with entries: either MAC or CRC32.  \n    </para>\n    </listitem>\n\t\n\t<listitem>\n\t<para>\n\t<computeroutput>passwd</computeroutput> is a password to access the ledger (used only in the case of <computeroutput>VERIFIABLE</computeroutput> ledgers);\n\t</para>\n\t</listitem>\n\t</itemizedlist>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous open:</emphasis>\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic void asyncOpenLedger(long lId, DigestType type, byte passwd[], OpenCallback cb, Object ctx)\n    </computeroutput>\n\t</para>\n\t\n    <para>\n    It also takes a a ledger identifier and a password. Additionaly, it takes a callback object \n    <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement\n    the <computeroutput>OpenCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>openComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tpublic void openComplete(int rc, LedgerHandle lh, Object ctx)\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>lh</computeroutput> is a <computeroutput>LedgerHandle</computeroutput> object to manipulate a ledger;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is control object used for accountability purposes. \n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t\n    </section>\n    \n    <section id=\"bk_readLedger\">\n    <title> Reading from ledger </title>\n    <para>\n    Read calls may request one or more consecutive entries. The following methods belong\n    to <computeroutput>org.apache.bookkeeper.client.LedgerHandle</computeroutput>.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Synchronous read:</emphasis>\n   \t</para>\n    \n    <para>\n    <computeroutput>\n\tpublic Enumeration&lt;LedgerEntry&gt; readEntries(long firstEntry, long lastEntry) \n    throws InterruptedException, BKException\n    </computeroutput>\n\t</para>\n\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n\t<computeroutput>firstEntry</computeroutput> is the identifier of the first entry in the sequence of entries to read;\n\t</para>\n\t</listitem>\n\t\n\t<listitem>\n\t<para>\n\t<computeroutput>lastEntry</computeroutput> is the identifier of the last entry in the sequence of entries to read.\n\t</para>\n\t</listitem>\n\t</itemizedlist>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous read:</emphasis>\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic void asyncReadEntries(long firstEntry, \n            long lastEntry, ReadCallback cb, Object ctx)\n    throws BKException, InterruptedException\n    </computeroutput>\n\t</para>\n\t\n    <para>\n    It also takes a first and a last entry identifiers. Additionaly, it takes a callback object \n    <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement\n    the <computeroutput>ReadCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>readComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tvoid readComplete(int rc, LedgerHandle lh, Enumeration&lt;LedgerEntry&gt; seq, Object ctx)\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>lh</computeroutput> is a <computeroutput>LedgerHandle</computeroutput> object to manipulate a ledger;\n\t\t</para>\n\t\t</listitem>\n\t\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>seq</computeroutput> is a <computeroutput>Enumeration&lt;LedgerEntry&gt; </computeroutput> object to containing the list of entries requested;\n\t\t</para>\n\t\t</listitem>\n\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is control object used for accountability purposes. \n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t\n    </section>\n\n    <section id=\"bk_deleteLedger\">\n    <title> Deleting a ledger </title>\n    <para>\n    Once a client is done with a ledger and is sure that nobody will ever need to read from it again, they can delete the ledger.\n    The following methods belong to <computeroutput>org.apache.bookkeeper.client.BookKeeper</computeroutput>.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Synchronous delete:</emphasis>\n   \t</para>\n    \n    <para>\n    <computeroutput>\n        public void deleteLedger(long lId) throws InterruptedException, BKException\n    </computeroutput>\n    </para>\n\n\t<itemizedlist>\n\t<listitem>\n\t<para>\n\t<computeroutput>lId</computeroutput> is the ledger identifier;\n\t</para>\n\t</listitem>\n\t</itemizedlist>\n    \n    <para>\n   \t<emphasis role=\"bold\">Asynchronous delete:</emphasis>\n    </para>\n    <para>\n      <computeroutput>\n\t public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) \n      </computeroutput>\n    </para>\n\t\n    <para>\n    It takes a ledger identifier. Additionally, it takes a callback object \n    <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement\n    the <computeroutput>DeleteCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and\n\ta class implementing it has to implement a method called <computeroutput>deleteComplete</computeroutput>\n\tthat has the following signature: \n    </para>\n\n\t<para>\n\t<computeroutput>\n\tvoid deleteComplete(int rc, Object ctx)\n\t</computeroutput>    \n\t</para>\n\t\n\t<para>\n\twhere:\n\t</para>\n\t<itemizedlist>\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);\n\t\t</para>\n\t\t</listitem>\n\t\n\t\t<listitem>\n\t\t<para>\n\t\t<computeroutput>ctx</computeroutput> is control object used for accountability purposes. \n\t\t</para>\n\t\t</listitem>\n\t</itemizedlist>\t\n    </section>\n   </section>\n</article>"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/bookkeeperStarted.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_GettStartedGuide\">\n  <title>BookKeeper Getting Started Guide</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about using BookKeeper\n      for logging. It discusses the basic operations BookKeeper supports, \n      and how to create logs and perform basic read and write operations on these\n      logs.</para>\n    </abstract>\n  </articleinfo>\n  <section id=\"bk_GettingStarted\">\n    <title>Getting Started: Setting up BookKeeper to write logs.</title>\n\n    <para>This document contains information to get you started quickly with\n    BookKeeper. It is aimed primarily at developers willing to try it out, and\n    contains simple installation instructions for a simple BookKeeper installation\n    and a simple programming example. For further programming detail, please refer to \n    <ulink url=\"bookkeeperProgrammer.html\">BookKeeper Programmer's Guide</ulink>.\n    </para>\n  \n\t  <section id=\"bk_Prerequisites\">\n    \t  <title>Pre-requisites</title>\n\t      <para>See <ulink url=\"bookkeeperConfig.html#bk_sysReq\">\n    \t      System Requirements</ulink> in the Admin guide.</para>\n\t    </section>\n\n\t  <section id=\"bk_Download\">\n      \t<title>Download</title>\n\t\t<para> BookKeeper is distributed along with ZooKeeper. To get a ZooKeeper distribution, \n\t\t\t   download a recent\n    \t    <ulink url=\"http://zookeeper.apache.org/releases.html\">\n        \t  stable</ulink> release from one of the Apache Download\n       \t Mirrors.</para>\n\t  </section>\n\t  \n\t  <section id=\"bk_localBK\">\n      \t<title>LocalBookKeeper</title>\n\t\t<para> Under org.apache.bookkeeper.util, you'll find a java program\n\t\tcalled LocalBookKeeper.java that sets you up to run BookKeeper on a \n\t\tsingle machine. This is far from ideal from a performance perspective,\n\t\tbut the program is useful for both test and educational purposes.\n\t\t</para>\n\t  </section>\n\t  \n\t  <section id=\"bk_setupBookies\">\n      \t<title>Setting up bookies</title>\n\t\t<para> If you're bold and you want more than just running things locally, then\n\t\tyou'll need to run bookies in different servers. You'll need at least three bookies\n\t\tto start with.  \n\t\t</para>\n\t\t\n\t\t<para>\n\t\tFor each bookie, we need to execute a command like the following:\n\t\t</para>\n\t\t\n\t\t<para><computeroutput>\n\t\tjava -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\\\n\t\t:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\\ \n\t\torg.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\\\n\t\t/path_to_ledger_device/\n\t\t</computeroutput></para>\n\t\t\n\t\t<para> \"/path_to_log_device/\" and \"/path_to_ledger_device/\" are different paths. Also, port 3181\n\t\tis the port that a bookie listens on for connection requests from clients. 127.0.0.1:2181 is the hostname:port \n\t\tfor the ZooKeeper server. In this example, the standalone ZooKeeper server is running locally on port 2181.\n\t\tIf we had multiple ZooKeeper servers, this parameter would be a comma separated list of all the hostname:port\n\t\tvalues corresponding to them.\n\t\t</para>\n\t  </section>\n\t  \n\t  <section id=\"bk_setupZK\">\n\t  \t<title>Setting up ZooKeeper</title>\n\t  \t<para> ZooKeeper stores metadata on behalf of BookKeeper clients and bookies. To get a minimal \n\t  \tZooKeeper installation to work with BookKeeper, we can set up one server running in\n\t  \tstandalone mode. Once we have the server running, we need to create a few znodes:\n\t  \t</para>\n\t  \t\n\t  \t<orderedlist>\n\t  \t<listitem>\n\t  \t<para><computeroutput>\n\t  \t/ledgers\t\n\t  \t</computeroutput></para>\n\t  \t</listitem>\n\t  \t\n\t  \t<listitem>\n\t  \t<para><computeroutput>\n\t  \t/ledgers/available\n\t  \t</computeroutput></para>\n\t  \t</listitem>\n\t  \t\n\t  \t<listitem>\n\t  \t<para> For each bookie, we add one znode such that the name of the znode is the\n\t  \tconcatenation of the machine name and the port number that the bookie is \n\t  \tlistening on. For example, if a bookie is running on bookie.foo.com an is listening \n\t  \ton port 3181, we add a znode \n\t  \t<computeroutput>/ledgers/available/bookie.foo.com:3181</computeroutput>.  \n\t  \t</para>\n\t  \t</listitem>\n\t  \t</orderedlist>\n\t  </section>\n\t  \n\t  <section id=\"bk_example\">\n\t    <title>Example</title>\n\t    <para>\n\t    In the following excerpt of code, we:\n\t    </para>\n\t    \n\t    <orderedlist>\n\t    \t<listitem>\n\t    \t<para>\n\t    \tCreate a ledger;\n\t    \t</para>\n\t    \t</listitem>\n\t    \t\n\t    \t<listitem>\n\t    \t<para>\n\t    \tWrite to the ledger;\n\t    \t</para>\n\t    \t</listitem>\n\t    \t\n\t    \t<listitem>\n\t    \t<para>\n\t    \tClose the ledger;\n\t    \t</para>\n\t    \t</listitem>\n\t    \t\n\t    \t<listitem>\n\t    \t<para>\n\t    \tOpen the same ledger for reading;\n\t    \t</para>\n\t    \t</listitem>\n\t    \t\n\t    \t<listitem>\n\t    \t<para>\n\t    \tRead from the ledger;\n\t    \t</para>\n\t    \t</listitem>\n\t    \t\n\t    \t<listitem>\n\t    \t<para>\n\t    \tClose the ledger again;\n\t    \t</para>\n\t    \t</listitem>\n\t    </orderedlist>\n\t    \n\t    <programlisting>\nLedgerHandle lh = bkc.createLedger(ledgerPassword);\nledgerId = lh.getId();\nByteBuffer entry = ByteBuffer.allocate(4);\n\nfor(int i = 0; i &lt; 10; i++){\n\tentry.putInt(i);\n\tentry.position(0);\n\tentries.add(entry.array());\t\t\t\t\n\tlh.addEntry(entry.array());\n}\nlh.close();\nlh = bkc.openLedger(ledgerId, ledgerPassword);\t\t\n\t\t\t\nEnumeration&lt;LedgerEntry&gt; ls = lh.readEntries(0, 9);\nint i = 0;\nwhile(ls.hasMoreElements()){\n\tByteBuffer origbb = ByteBuffer.wrap(\n\t\t\t\tentries.get(i++));\n\tInteger origEntry = origbb.getInt();\n\tByteBuffer result = ByteBuffer.wrap(\n\t\t\t\tls.nextElement().getEntry());\n\n\tInteger retrEntry = result.getInt();\n}\nlh.close();\n\t    </programlisting>\n\t  </section>  \n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/bookkeeperStream.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_Stream\">\n  <title>Streaming with BookKeeper</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about using how to stream bytes\n      on top of BookKeeper. It essentially motivates and discusses the basic stream \n      operations currently supported.</para>\n    </abstract>\n  </articleinfo>\n\t<section id=\"bk_StreamSummary\">\n    <title>Summary</title>\n    \n    <para>\n    When using the BookKeeper API, an application has to split the data to write into entries, each\n    entry being a byte array. This is natural for many applications. For example, when using BookKeeper\n    for write-ahead logging, an application typically wants to write the modifications corresponding\n    to a command or a transaction. Some other applications, however, might not have a natural boundary\n    for entries, and may prefer to write and read streams of bytes. This is exactly the purpose of the\n    stream API we have implemented on top of BookKeeper.\n    </para>\n    \n    <para>\n    The stream API is implemented in the package <computeroutput>Streaming</computeroutput>, and it contains two main classes: <computeroutput>LedgerOutputStream</computeroutput> and \n    <computeroutput>LedgerInputStream</computeroutput>. The class names are indicative of what they do.\n    </para>\n    </section>\n    \n    <section id=\"bk_LedgerOutputStream\">\n    <title>Writing a stream of bytes</title>\n    <para>\n    Class <computeroutput>LedgerOutputStream</computeroutput> implements two constructors and five public methods:\n    </para>\n    \n    <para>\n    <computeroutput>\n\tpublic LedgerOutputStream(LedgerHandle lh) \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>lh</computeroutput> is a ledger handle for a previously created and open ledger.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n    <para>\n    <computeroutput>\n\tpublic LedgerOutputStream(LedgerHandle lh, int size) \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>lh</computeroutput> is a ledger handle for a previously created and open ledger.  \n    \t</para>\n    \t</listitem>\n\n    \t<listitem>\n    \t<para> \n        <computeroutput>size</computeroutput> is the size of the byte buffer to store written bytes before flushing.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n    \n    <para>\n   \t<emphasis role=\"bold\">Closing a stream.</emphasis> This call closes the stream by flushing the write buffer.\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic void close() \n    </computeroutput>\n\t</para>\n\n    <para>\n    which has no parameters.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Flushing a stream.</emphasis> This call essentially flushes the write buffer.\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic synchronized void flush() \n    </computeroutput>\n\t</para>\n    \n    <para>\n    which has no parameters.\n    </para>\n    \n    <para>\n   \t<emphasis role=\"bold\">Writing bytes.</emphasis> There are three calls for writing bytes to a stream.\n   \t</para>\n   \t\n    <para>\n    <computeroutput>\n\tpublic synchronized void write(byte[] b) \n    </computeroutput>\n\t</para>\n    \n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>b</computeroutput> is an array of bytes to write.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n    <para>\n    <computeroutput>\n\tpublic synchronized void write(byte[] b, int off, int len) \n    </computeroutput>\n\t</para>\n    \n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>b</computeroutput> is an array of bytes to write.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para> \n        <computeroutput>off</computeroutput> is a buffer offset.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para> \n        <computeroutput>len</computeroutput> is the length to write.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n        <para>\n    <computeroutput>\n\tpublic synchronized void write(int b) \n    </computeroutput>\n\t</para>\n    \n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>b</computeroutput> contains a byte to write. The method writes the least significant byte of the integer four bytes.    \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    </section>\n    \n    <section id=\"bk_LedgerInputStream\">\n    <title>Reading a stream of bytes</title>\n    \n    <para>\n    Class <computeroutput>LedgerOutputStream</computeroutput> implements two constructors and four public methods:\n    </para>\n    \n    <para>\n    <computeroutput>\n\tpublic LedgerInputStream(LedgerHandle lh)\n\tthrows BKException, InterruptedException \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>lh</computeroutput> is a ledger handle for a previously created and open ledger.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>    \n    \n    <para>\n    <computeroutput>\n\tpublic LedgerInputStream(LedgerHandle lh, int size) \n    throws BKException, InterruptedException\n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>lh</computeroutput> is a ledger handle for a previously created and open ledger.  \n    \t</para>\n    \t</listitem>\n\n    \t<listitem>\n    \t<para> \n        <computeroutput>size</computeroutput> is the size of the byte buffer to store bytes that the application\n        will eventually read.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n\n    <para>\n   \t<emphasis role=\"bold\">Closing.</emphasis> There is one call to close an input stream, but the call\n   \tis currently empty and the application is responsible for closing the ledger handle. \n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic void close()\n    </computeroutput>\n\t</para>\n\n    <para>\n    which has no parameters.\n    </para>\n   \n    <para>\n   \t<emphasis role=\"bold\">Reading.</emphasis> There are three calls to read from the stream.\n   \t</para>\n    <para>\n    <computeroutput>\n\tpublic synchronized int read()\n\tthrows IOException \n    </computeroutput>\n\t</para>\n\n    <para>\n    which has no parameters.\n    </para>\n\n    <para>\n    <computeroutput>\n\tpublic synchronized int read(byte[] b)\n\tthrows IOException \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n        <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>b</computeroutput> is a byte array to write to.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n    \n\n    <para>\n    <computeroutput>\n\tpublic synchronized int read(byte[] b, int off, int len)\n\tthrows IOException \n    </computeroutput>\n\t</para>\n\n    <para>\n    where:\n    </para>\n    <itemizedlist>\n    \t<listitem>\n    \t<para> \n        <computeroutput>b</computeroutput> is a byte array to write to.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para> \n        <computeroutput>off</computeroutput> is an offset for byte array <computeroutput>b</computeroutput>.  \n    \t</para>\n    \t</listitem>\n    \t\n    \t<listitem>\n    \t<para> \n        <computeroutput>len</computeroutput> is the length in bytes to write to <computeroutput>b</computeroutput>.  \n    \t</para>\n    \t</listitem>\n    </itemizedlist>\n\n    \n    </section>\n  </article>"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/index.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE document PUBLIC \"-//APACHE//DTD Documentation V2.0//EN\" \"http://forrest.apache.org/dtd/document-v20.dtd\">\n\n<document>\n  \n  <header>\n    <title>ZooKeeper: Because Coordinating Distributed Systems is a Zoo</title>\n  </header>\n  \n  <body>\n    <p>ZooKeeper is a high-performance coordination service for\n      distributed applications.  It exposes common services - such as\n      naming, configuration management, synchronization, and group\n      services - in a simple interface so you don't have to write them\n      from scratch.  You can use it off-the-shelf to implement\n      consensus, group management, leader election, and presence\n      protocols. And you can build on it for your own, specific needs.\n    </p>\n\n    <p>\n      The following documents describe concepts and procedures to get\n      you started using ZooKeeper. If you have more questions, please\n      ask the <a href=\"ext:lists\">mailing list</a> or browse the\n      archives.\n    </p>\n    <ul>\n\n      <li><strong>ZooKeeper Overview</strong><p>Technical Overview Documents for Client Developers, Adminstrators, and Contributors</p>\n      <ul><li><a href=\"zookeeperOver.html\">Overview</a> - a bird's eye view of ZooKeeper, including design concepts and architecture</li>\n      <li><a href=\"zookeeperStarted.html\">Getting Started</a> - a tutorial-style guide for developers to install, run, and program to ZooKeeper</li>\n      <li><a href=\"ext:relnotes\">Release Notes</a> - new developer and user facing features, improvements, and incompatibilities</li>\n      </ul>\n      </li>\n      \n      <li><strong>Developers</strong><p> Documents for Developers using the ZooKeeper Client API</p>\n      <ul>\n            <li><a href=\"ext:api/index\">API Docs</a> - the technical reference to ZooKeeper Client APIs</li>\n      <li><a href=\"zookeeperProgrammers.html\">Programmer's Guide</a> - a client application developer's guide to ZooKeeper</li>\n      <li><a href=\"javaExample.html\">ZooKeeper Java Example</a> - a simple Zookeeper client appplication, written in Java</li>\n      <li><a href=\"zookeeperTutorial.html\">Barrier and Queue Tutorial</a> - sample implementations of barriers and queues</li>  \n      <li><a href=\"recipes.html\">ZooKeeper Recipes</a> - higher level solutions to common problems in distributed applications</li>\n      </ul>\n      </li>\n      \n      <li><strong>Administrators &amp; Operators</strong> <p> Documents for Administrators and Operations Engineers of ZooKeeper Deployments</p>\n      <ul>\n      <li><a href=\"zookeeperAdmin.html\">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy ZooKeeper</li>\n      <li><a href=\"zookeeperQuotas.html\">Quota Guide</a> - a guide for system administrators on Quotas in ZooKeeper. </li>\n      <li><a href=\"zookeeperJMX.html\">JMX</a> - how to enable JMX in ZooKeeper</li>\n      <li><a href=\"zookeeperHierarchicalQuorums.html\">Hierarchical quorums</a></li>\n      <li><a href=\"zookeeperObservers.html\">Observers</a> - non-voting ensemble members that easily improve ZooKeeper's scalability</li>\n      </ul>\n      </li>\n      \n      <li><strong>Contributors</strong><p> Documents for Developers Contributing to the ZooKeeper Open Source Project</p>\n      <ul>\n      <li><a href=\"zookeeperInternals.html\">ZooKeeper Internals</a> - assorted topics on the inner workings of ZooKeeper</li>\n      </ul>\n      </li>\n      \n      <li><strong>Miscellaneous ZooKeeper Documentation</strong>\n      <ul>\n      <li><a href=\"ext:wiki\">Wiki</a></li>\n      <li><a href=\"ext:faq\">FAQ</a></li>    \n      </ul>\n      </li>\n\n\t  <li><strong>BookKeeper Documentation</strong>\n\t  <p> BookKeeper is a highly-available system that implements high-performance write-ahead logging. It uses ZooKeeper for metadata, \n\t  which is the main reason for being a ZooKeeper contrib.\n\t  </p>\n      <ul>\n      <li><a href=\"bookkeeperOverview.html\">henn, what's it again?</a></li>\n\t  <li><a href=\"bookkeeperStarted.html\">Ok, now how do I try it out</a></li>\n\t  <li><a href=\"bookkeeperProgrammer.html\">Awesome, but how do I integrate it with my app?</a></li>\n      <li><a href=\"bookkeeperStream.html\">Can I stream bytes instead of entries?</a></li>\n      </ul>\n      </li>\n    </ul>\n  </body>\n  \n</document>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/javaExample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"ar_JavaExample\">\n  <title>ZooKeeper Java Example</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This article contains sample Java code for a simple watch client.</para>\n\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_Introduction\">\n    <title>A Simple Watch Client</title>\n\n    <para>To introduce you to the ZooKeeper Java API, we develop here a very simple \n    watch client. This ZooKeeper client watches a ZooKeeper node for changes \n    and responds to by starting or stopping a program.</para>\n    \n    <section id=\"sc_requirements\"><title>Requirements</title>\n    \n    <para>The client has four requirements:</para>\n    \n    <itemizedlist><listitem><para>It takes as parameters:</para>\n    \t<itemizedlist>\n\t\t<listitem><para>the address of the ZooKeeper service</para></listitem>\n\t\t<listitem> <para>then name of a znode - the one to be watched</para></listitem>\n\t\t<listitem><para>an executable with arguments.</para></listitem></itemizedlist></listitem>\n\t<listitem><para>It fetches the data associated with the znode and starts the executable.</para></listitem>\n\t<listitem><para>If the znode changes, the client refetches the contents and restarts the executable.</para></listitem>\n\t<listitem><para>If the znode disappears, the client kills the executable.</para></listitem></itemizedlist>\n\n   </section>\n   \n   <section id=\"sc_design\">\n   \t<title>Program Design</title>\n\n   <para>Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection, \n   and the other which monitors data.  In this application, the class called the <emphasis role=\"bold\">Executor</emphasis> \n   maintains the ZooKeeper connection, and the class called the  <emphasis role=\"bold\">DataMonitor</emphasis> monitors the data\n   in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.\n   It is responsible for what little user interaction there is, as well as interaction with the exectuable program you\n   pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the \n   state of the znode.</para>\n   \n   </section>\n  \n   </section>\n\n   <section id=\"sc_executor\"><title>The Executor Class</title>\n    <para>The Executor object is the primary container of the sample application. It contains \n    both the <emphasis role=\"bold\">ZooKeeper</emphasis> object, <emphasis role=\"bold\">DataMonitor</emphasis>, as described above in \n    <xref linkend=\"sc_design\"/>.  </para>\n    \n    <programlisting>\n    // from the Executor class...\n    \n    public static void main(String[] args) {\n        if (args.length &lt; 4) {\n            System.err\n                    .println(\"USAGE: Executor hostPort znode filename program [args ...]\");\n            System.exit(2);\n        }\n        String hostPort = args[0];\n        String znode = args[1];\n        String filename = args[2];\n        String exec[] = new String[args.length - 3];\n        System.arraycopy(args, 3, exec, 0, exec.length);\n        try {\n            new Executor(hostPort, znode, filename, exec).run();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public Executor(String hostPort, String znode, String filename,\n            String exec[]) throws KeeperException, IOException {\n        this.filename = filename;\n        this.exec = exec;\n        zk = new ZooKeeper(hostPort, 3000, this);\n        dm = new DataMonitor(zk, znode, null, this);\n    }\n\n    public void run() {\n        try {\n            synchronized (this) {\n                while (!dm.dead) {\n                    wait();\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n</programlisting>\n\n\n    <para>\n    Recall that the Executor's job is to start and stop the executable whose name you pass in on the command line. \n    It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes\n    a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself\n    as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these\n    interfaces:\n    </para>\n    \n    <programlisting>\npublic class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener {\n...</programlisting>\n    \n    <para>The <emphasis role=\"bold\">Watcher</emphasis> interface is defined by the ZooKeeper Java API.\n    ZooKeeper uses it to communicate back to its container. It supports only one method, <command>process()</command>, and ZooKeeper uses \n    it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor \n    in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate\n    the point that, by convention, the Executor or some Executor-like object \"owns\" the ZooKeeper connection, but it is free to delegate the events to other\n    events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)</para>\n    \n<programlisting>\n    public void process(WatchedEvent event) {\n        dm.process(event);\n    }\n</programlisting>\n    \n    <para>The <emphasis role=\"bold\">DataMonitorListener</emphasis> \n    interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface, \n    designed for this sample application. The DataMonitor object uses it to communicate back to its container, which\n    is also the the Executor object.The DataMonitorListener interface looks like this:</para>\n    <programlisting>\npublic interface DataMonitorListener {\n    /**\n    * The existence status of the node has changed.\n    */\n    void exists(byte data[]);\n\n    /**\n    * The ZooKeeper session is no longer valid.\n    * \n    * @param rc\n    * the ZooKeeper reason code\n    */\n    void closing(int rc);\n}\n</programlisting>\n    <para>This interface is defined in the DataMonitor class and implemented in the Executor class. \n    When <command>Executor.exists()</command> is invoked,\n    the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the \n    znode ceases to <emphasis>exist</emphasis>. </para>\n    \n    <para>When <command>Executor.closing()</command>\n    is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.</para>\n    \n    <para>As you might have guessed, DataMonitor is the object that invokes \n    these methods, in response to changes in ZooKeeper's state.</para>\n    \n    <para>Here are Executor's implementation of \n    <command>DataMonitorListener.exists()</command> and <command>DataMonitorListener.closing</command>:\n    </para>\n    <programlisting>\npublic void exists( byte[] data ) {\n    if (data == null) {\n        if (child != null) {\n            System.out.println(\"Killing process\");\n            child.destroy();\n            try {\n                child.waitFor();\n            } catch (InterruptedException e) {\n            }\n        }\n        child = null;\n    } else {\n        if (child != null) {\n            System.out.println(\"Stopping child\");\n            child.destroy();\n            try {\n               child.waitFor();\n            } catch (InterruptedException e) {\n            e.printStackTrace();\n            }\n        }\n        try {\n            FileOutputStream fos = new FileOutputStream(filename);\n            fos.write(data);\n            fos.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            System.out.println(\"Starting child\");\n            child = Runtime.getRuntime().exec(exec);\n            new StreamWriter(child.getInputStream(), System.out);\n            new StreamWriter(child.getErrorStream(), System.err);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n\npublic void closing(int rc) {\n    synchronized (this) {\n        notifyAll();\n    }\n}\n</programlisting>\n    \n</section>\n<section id=\"sc_DataMonitor\"><title>The DataMonitor Class</title>\n<para>\nThe DataMonitor class has the meat of the ZooKeeper logic. It is mostly \nasynchronous and event driven. DataMonitor kicks things off in the constructor with:</para>\n<programlisting>\npublic DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,\n        DataMonitorListener listener) {\n    this.zk = zk;\n    this.znode = znode;\n    this.chainedWatcher = chainedWatcher;\n    this.listener = listener;\n    \n    // Get things started by checking if the node exists. We are going\n    // to be completely event driven\n    <emphasis role=\"bold\">zk.exists(znode, true, this, null);</emphasis>\n}\n</programlisting>\n\n<para>The call to <command>ZooKeeper.exists()</command> checks for the existence of the znode, \nsets a watch, and passes a reference to itself (<command>this</command>)\nas the completion callback object. In this sense, it kicks things off, since the\nreal processing happens when the watch is triggered.</para>\n\n<note>\n<para>Don't confuse the completion callback with the watch callback. The <command>ZooKeeper.exists()</command> \ncompletion callback, which happens to be the method <command>StatCallback.processResult()</command> implemented \nin the DataMonitor object, is invoked when the asynchronous <emphasis>setting of the watch</emphasis> operation \n(by <command>ZooKeeper.exists()</command>) completes on the server. </para>\n<para>\nThe triggering of the watch, on the other hand, sends an event to the <emphasis>Executor</emphasis> object, since\nthe Executor registered as the Watcher of the ZooKeeper object.</para>\n\n<para>As an aside, you might note that the DataMonitor could also register itself as the Watcher\nfor this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this\nexample, however, DataMonitor does not register as the Watcher.</para>\n</note>\n\n<para>When the <command>ZooKeeper.exists()</command> operation completes on the server, the ZooKeeper API invokes this completion callback on \nthe client:</para>\n\n<programlisting>\npublic void processResult(int rc, String path, Object ctx, Stat stat) {\n    boolean exists;\n    switch (rc) {\n    case Code.Ok:\n        exists = true;\n        break;\n    case Code.NoNode:\n        exists = false;\n        break;\n    case Code.SessionExpired:\n    case Code.NoAuth:\n        dead = true;\n        listener.closing(rc);\n        return;\n    default:\n        // Retry errors\n        zk.exists(znode, true, this, null);\n        return;\n    }\n \n    byte b[] = null;\n    if (exists) {\n        try {\n            <emphasis role=\"bold\">b = zk.getData(znode, false, null);</emphasis>\n        } catch (KeeperException e) {\n            // We don't need to worry about recovering now. The watch\n            // callbacks will kick off any exception handling\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            return;\n        }\n    }     \n    if ((b == null &amp;&amp; b != prevData)\n            || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {\n        <emphasis role=\"bold\">listener.exists(b);</emphasis>\n        prevData = b;\n    }\n}\n</programlisting>\n\n<para>\nThe code first checks the error codes for znode existence, fatal errors, and \nrecoverable errors. If the file (or znode) exists, it gets the data from the znode, and \nthen invoke the exists() callback of Executor if the state has changed. Note, \nit doesn't have to do any Exception processing for the getData call because it \nhas watches pending for anything that could cause an error: if the node is deleted \nbefore it calls <command>ZooKeeper.getData()</command>, the watch event set by \nthe <command>ZooKeeper.exists()</command> triggers a callback; \nif there is a communication error, a connection watch event fires when \nthe connection comes back up.\n</para>\n\n<para>Finally, notice how DataMonitor processes watch events: </para>\n<programlisting>\n    public void process(WatchedEvent event) {\n        String path = event.getPath();\n        if (event.getType() == Event.EventType.None) {\n            // We are are being told that the state of the\n            // connection has changed\n            switch (event.getState()) {\n            case SyncConnected:\n                // In this particular example we don't need to do anything\n                // here - watches are automatically re-registered with \n                // server and any watches triggered while the client was \n                // disconnected will be delivered (in order of course)\n                break;\n            case Expired:\n                // It's all over\n                dead = true;\n                listener.closing(KeeperException.Code.SessionExpired);\n                break;\n            }\n        } else {\n            if (path != null &amp;&amp; path.equals(znode)) {\n                // Something has changed on the node, let's find out\n                zk.exists(znode, true, this, null);\n            }\n        }\n        if (chainedWatcher != null) {\n            chainedWatcher.process(event);\n        }\n    }\n</programlisting>\n<para>\nIf the client-side ZooKeeper libraries can re-establish the\ncommunication channel (SyncConnected event) to ZooKeeper before\nsession expiration (Expired event) all of the session's watches will\nautomatically be re-established with the server (auto-reset of watches\nis new in ZooKeeper 3.0.0). See <ulink\nurl=\"zookeeperProgrammers.html#ch_zkWatches\">ZooKeeper Watches</ulink>\nin the programmer guide for more on this. A bit lower down in this\nfunction, when DataMonitor gets an event for a znode, it calls\n<command>ZooKeeper.exists()</command> to find out what has changed.\n</para>\n</section>\n\n<section id=\"sc_completeSourceCode\">\n\t<title>Complete Source Listings</title>\n\t<example id=\"eg_Executor_java\"><title>Executor.java</title><programlisting>\n/**\n * A simple example program to use DataMonitor to start and\n * stop executables based on a znode. The program watches the\n * specified znode and saves the data that corresponds to the\n * znode in the filesystem. It also starts the specified program\n * with the specified arguments when the znode exists and kills\n * the program if the znode goes away.\n */\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\n\npublic class Executor\n    implements Watcher, Runnable, DataMonitor.DataMonitorListener\n{\n    String znode;\n\n    DataMonitor dm;\n\n    ZooKeeper zk;\n\n    String filename;\n\n    String exec[];\n\n    Process child;\n\n    public Executor(String hostPort, String znode, String filename,\n            String exec[]) throws KeeperException, IOException {\n        this.filename = filename;\n        this.exec = exec;\n        zk = new ZooKeeper(hostPort, 3000, this);\n        dm = new DataMonitor(zk, znode, null, this);\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        if (args.length &lt; 4) {\n            System.err\n                    .println(\"USAGE: Executor hostPort znode filename program [args ...]\");\n            System.exit(2);\n        }\n        String hostPort = args[0];\n        String znode = args[1];\n        String filename = args[2];\n        String exec[] = new String[args.length - 3];\n        System.arraycopy(args, 3, exec, 0, exec.length);\n        try {\n            new Executor(hostPort, znode, filename, exec).run();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /***************************************************************************\n     * We do process any events ourselves, we just need to forward them on.\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.proto.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        dm.process(event);\n    }\n\n    public void run() {\n        try {\n            synchronized (this) {\n                while (!dm.dead) {\n                    wait();\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n\n    public void closing(int rc) {\n        synchronized (this) {\n            notifyAll();\n        }\n    }\n\n    static class StreamWriter extends Thread {\n        OutputStream os;\n\n        InputStream is;\n\n        StreamWriter(InputStream is, OutputStream os) {\n            this.is = is;\n            this.os = os;\n            start();\n        }\n\n        public void run() {\n            byte b[] = new byte[80];\n            int rc;\n            try {\n                while ((rc = is.read(b)) > 0) {\n                    os.write(b, 0, rc);\n                }\n            } catch (IOException e) {\n            }\n\n        }\n    }\n\n    public void exists(byte[] data) {\n        if (data == null) {\n            if (child != null) {\n                System.out.println(\"Killing process\");\n                child.destroy();\n                try {\n                    child.waitFor();\n                } catch (InterruptedException e) {\n                }\n            }\n            child = null;\n        } else {\n            if (child != null) {\n                System.out.println(\"Stopping child\");\n                child.destroy();\n                try {\n                    child.waitFor();\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n            try {\n                FileOutputStream fos = new FileOutputStream(filename);\n                fos.write(data);\n                fos.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            try {\n                System.out.println(\"Starting child\");\n                child = Runtime.getRuntime().exec(exec);\n                new StreamWriter(child.getInputStream(), System.out);\n                new StreamWriter(child.getErrorStream(), System.err);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}\n</programlisting>\n\t\n</example>\n\n<example id=\"eg_DataMonitor_java\">\n\t<title>DataMonitor.java</title>\n\t<programlisting>\n/**\n * A simple class that monitors the data and existence of a ZooKeeper\n * node. It uses asynchronous ZooKeeper APIs.\n */\nimport java.util.Arrays;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.data.Stat;\n\npublic class DataMonitor implements Watcher, StatCallback {\n\n    ZooKeeper zk;\n\n    String znode;\n\n    Watcher chainedWatcher;\n\n    boolean dead;\n\n    DataMonitorListener listener;\n\n    byte prevData[];\n\n    public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,\n            DataMonitorListener listener) {\n        this.zk = zk;\n        this.znode = znode;\n        this.chainedWatcher = chainedWatcher;\n        this.listener = listener;\n        // Get things started by checking if the node exists. We are going\n        // to be completely event driven\n        zk.exists(znode, true, this, null);\n    }\n\n    /**\n     * Other classes use the DataMonitor by implementing this method\n     */\n    public interface DataMonitorListener {\n        /**\n         * The existence status of the node has changed.\n         */\n        void exists(byte data[]);\n\n        /**\n         * The ZooKeeper session is no longer valid.\n         *\n         * @param rc\n         *                the ZooKeeper reason code\n         */\n        void closing(int rc);\n    }\n\n    public void process(WatchedEvent event) {\n        String path = event.getPath();\n        if (event.getType() == Event.EventType.None) {\n            // We are are being told that the state of the\n            // connection has changed\n            switch (event.getState()) {\n            case SyncConnected:\n                // In this particular example we don't need to do anything\n                // here - watches are automatically re-registered with \n                // server and any watches triggered while the client was \n                // disconnected will be delivered (in order of course)\n                break;\n            case Expired:\n                // It's all over\n                dead = true;\n                listener.closing(KeeperException.Code.SessionExpired);\n                break;\n            }\n        } else {\n            if (path != null &amp;&amp; path.equals(znode)) {\n                // Something has changed on the node, let's find out\n                zk.exists(znode, true, this, null);\n            }\n        }\n        if (chainedWatcher != null) {\n            chainedWatcher.process(event);\n        }\n    }\n\n    public void processResult(int rc, String path, Object ctx, Stat stat) {\n        boolean exists;\n        switch (rc) {\n        case Code.Ok:\n            exists = true;\n            break;\n        case Code.NoNode:\n            exists = false;\n            break;\n        case Code.SessionExpired:\n        case Code.NoAuth:\n            dead = true;\n            listener.closing(rc);\n            return;\n        default:\n            // Retry errors\n            zk.exists(znode, true, this, null);\n            return;\n        }\n\n        byte b[] = null;\n        if (exists) {\n            try {\n                b = zk.getData(znode, false, null);\n            } catch (KeeperException e) {\n                // We don't need to worry about recovering now. The watch\n                // callbacks will kick off any exception handling\n                e.printStackTrace();\n            } catch (InterruptedException e) {\n                return;\n            }\n        }\n        if ((b == null &amp;&amp; b != prevData)\n                || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {\n            listener.exists(b);\n            prevData = b;\n        }\n    }\n}\n</programlisting>\n</example>\n</section>\n\n\n\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/recipes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"ar_Recipes\">\n  <title>ZooKeeper Recipes and Solutions</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains pseudocode and guidelines for using Zookeeper to\n      solve common problems in Distributed Application Coordination. It\n      discusses such problems as event handlers, queues, and locks..</para>\n\n      <para>$Revision: 1.6 $ $Date: 2008/09/19 03:46:18 $</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_recipes\">\n    <title>A Guide to Creating Higher-level Constructs with ZooKeeper</title>\n\n    <para>In this article, you'll find guidelines for using\n    ZooKeeper to implement higher order functions. All of them are conventions\n    implemented at the client and do not require special support from\n    ZooKeeper. Hopfully the community will capture these conventions in client-side libraries \n    to ease their use and to encourage standardization.</para>\n\n    <para>One of the most interesting things about ZooKeeper is that even\n    though ZooKeeper uses <emphasis>asynchronous</emphasis> notifications, you\n    can use it to build <emphasis>synchronous</emphasis> consistency\n    primitives, such as queues and locks. As you will see, this is possible\n    because ZooKeeper imposes an overall order on updates, and has mechanisms\n    to expose this ordering.</para>\n\n    <para>Note that the recipes below attempt to employ best practices. In\n    particular, they avoid polling, timers or anything else that would result\n    in a \"herd effect\", causing bursts of traffic and limiting\n    scalability.</para>\n\n    <para>There are many useful functions that can be imagined that aren't\n    included here - revocable read-write priority locks, as just one example.\n    And some of the constructs mentioned here - locks, in particular -\n    illustrate certain points, even though you may find other constructs, such\n    as event handles or queues, a more practical means of performing the same\n    function. In general, the examples in this section are designed to\n    stimulate thought.</para>\n\n\n  <section id=\"sc_outOfTheBox\">\n    <title>Out of the Box Applications: Name Service, Configuration, Group\n    Membership</title>\n\n    <para>Name service and configuration are two of the primary applications\n    of ZooKeeper. These two functions are provided directly by the ZooKeeper\n    API.</para>\n\n    <para>Another function directly provided by ZooKeeper is <emphasis>group\n    membership</emphasis>. The group is represented by a node. Members of the\n    group create ephemeral nodes under the group node. Nodes of the members\n    that fail abnormally will be removed automatically when ZooKeeper detects\n    the failure.</para>\n  </section>\n\n  <section id=\"sc_recipes_eventHandles\">\n    <title>Barriers</title>\n\n    <para>Distributed systems use <emphasis>barriers</emphasis>\n      to block processing of a set of nodes until a condition is met\n      at which time all the nodes are allowed to proceed. Barriers are\n      implemented in ZooKeeper by designating a barrier node. The\n      barrier is in place if the barrier node exists. Here's the\n      pseudo code:</para>\n\n    <orderedlist>\n      <listitem>\n        <para>Client calls the ZooKeeper API's <emphasis\n        role=\"bold\">exists()</emphasis> function on the barrier node, with\n        <emphasis>watch</emphasis> set to true.</para>\n      </listitem>\n\n      <listitem>\n        <para>If <emphasis role=\"bold\">exists()</emphasis> returns false, the\n        barrier is gone and the client proceeds</para>\n      </listitem>\n\n      <listitem>\n        <para>Else, if <emphasis role=\"bold\">exists()</emphasis> returns true,\n        the clients wait for a watch event from ZooKeeper for the barrier\n        node.</para>\n      </listitem>\n\n      <listitem>\n        <para>When the watch event is triggered, the client reissues the\n        <emphasis role=\"bold\">exists( )</emphasis> call, again waiting until\n        the barrier node is removed.</para>\n      </listitem>\n    </orderedlist>\n\n    <section id=\"sc_doubleBarriers\">\n      <title>Double Barriers</title>\n\n      <para>Double barriers enable clients to synchronize the beginning and\n      the end of a computation. When enough processes have joined the barrier,\n      processes start their computation and leave the barrier once they have\n      finished. This recipe shows how to use a ZooKeeper node as a\n      barrier.</para>\n\n      <para>The pseudo code in this recipe represents the barrier node as\n      <emphasis>b</emphasis>. Every client process <emphasis>p</emphasis>\n      registers with the barrier node on entry and unregisters when it is\n      ready to leave. A node registers with the barrier node via the <emphasis\n      role=\"bold\">Enter</emphasis> procedure below, it waits until\n      <emphasis>x</emphasis> client process register before proceeding with\n      the computation. (The <emphasis>x</emphasis> here is up to you to\n      determine for your system.)</para>\n\n      <informaltable colsep=\"0\" frame=\"none\" rowsep=\"0\">\n        <tgroup cols=\"2\">\n          <tbody>\n            <row>\n              <entry align=\"center\"><emphasis\n                                       role=\"bold\">Enter</emphasis></entry>\n\n              <entry align=\"center\"><emphasis\n                                       role=\"bold\">Leave</emphasis></entry>\n            </row>\n\n            <row>\n              <entry align=\"left\"><orderedlist>\n                  <listitem>\n                    <para>Create a name <emphasis><emphasis>n</emphasis> =\n                        <emphasis>b</emphasis>+“/”+<emphasis>p</emphasis></emphasis></para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Set watch: <emphasis\n                                        role=\"bold\">exists(<emphasis>b</emphasis> + ‘‘/ready’’,\n                        true)</emphasis></para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Create child: <emphasis role=\"bold\">create(\n                        <emphasis>n</emphasis>, EPHEMERAL)</emphasis></para>\n                  </listitem>\n\n                  <listitem>\n                    <para><emphasis role=\"bold\">L = getChildren(b,\n                        false)</emphasis></para>\n                  </listitem>\n\n                  <listitem>\n                    <para>if fewer children in L than<emphasis>\n                        x</emphasis>, wait for watch event</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>else <emphasis role=\"bold\">create(b + ‘‘/ready’’,\n                        REGULAR)</emphasis></para>\n                  </listitem>\n                </orderedlist></entry>\n\n              <entry><orderedlist>\n                  <listitem>\n                    <para><emphasis role=\"bold\">L = getChildren(b,\n                        false)</emphasis></para>\n                  </listitem>\n\n                  <listitem>\n                    <para>if no children, exit</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>if <emphasis>p</emphasis> is only process node in\n                      L, delete(n) and exit</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>if <emphasis>p</emphasis> is the lowest process\n                      node in L, wait on highest process node in L</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>else <emphasis\n                                  role=\"bold\">delete(<emphasis>n</emphasis>) </emphasis>if\n                      still exists and wait on lowest process node in L</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>goto 1</para>\n                  </listitem>\n                </orderedlist></entry>\n            </row>\n          </tbody>\n        </tgroup>\n      </informaltable>\n      <para>On entering, all processes watch on a ready node and\n        create an ephemeral node as a child of the barrier node. Each process\n        but the last enters the barrier and waits for the ready node to appear\n        at line 5. The process that creates the xth node, the last process, will\n        see x nodes in the list of children and create the ready node, waking up\n        the other processes. Note that waiting processes wake up only when it is\n        time to exit, so waiting is efficient.\n      </para>\n\n      <para>On exit, you can't use a flag such as <emphasis>ready</emphasis>\n      because you are watching for process nodes to go away. By using\n      ephemeral nodes, processes that fail after the barrier has been entered\n      do not prevent correct processes from finishing. When processes are\n      ready to leave, they need to delete their process nodes and wait for all\n      other processes to do the same.</para>\n\n      <para>Processes exit when there are no process nodes left as children of\n      <emphasis>b</emphasis>. However, as an efficiency, you can use the\n      lowest process node as the ready flag. All other processes that are\n      ready to exit watch for the lowest existing process node to go away, and\n      the owner of the lowest process watches for any other process node\n      (picking the highest for simplicity) to go away. This means that only a\n      single process wakes up on each node deletion except for the last node,\n      which wakes up everyone when it is removed.</para>\n    </section>\n  </section>\n\n  <section id=\"sc_recipes_Queues\">\n    <title>Queues</title>\n\n    <para>Distributed queues are a common data structure. To implement a\n    distributed queue in ZooKeeper, first designate a znode to hold the queue,\n    the queue node. The distributed clients put something into the queue by\n    calling create() with a pathname ending in \"queue-\", with the\n    <emphasis>sequence</emphasis> and <emphasis>ephemeral</emphasis> flags in\n    the create() call set to true. Because the <emphasis>sequence</emphasis>\n    flag is set, the new pathnames will have the form\n    _path-to-queue-node_/queue-X, where X is a monotonic increasing number. A\n    client that wants to be removed from the queue calls ZooKeeper's <emphasis\n    role=\"bold\">getChildren( )</emphasis> function, with\n    <emphasis>watch</emphasis> set to true on the queue node, and begins\n    processing nodes with the lowest number. The client does not need to issue\n    another <emphasis role=\"bold\">getChildren( )</emphasis> until it exhausts\n    the list obtained from the first <emphasis role=\"bold\">getChildren(\n    )</emphasis> call. If there are are no children in the queue node, the\n    reader waits for a watch notification to check the queue again.</para>\n\n    <note>\n      <para>There now exists a Queue implementation in ZooKeeper\n      recipes directory. This is distributed with the release --\n      src/recipes/queue directory of the release artifact.\n      </para>\n    </note>\n\n    <section id=\"sc_recipes_priorityQueues\">\n      <title>Priority Queues</title>\n\n      <para>To implement a priority queue, you need only make two simple\n      changes to the generic <ulink url=\"#sc_recipes_Queues\">queue\n      recipe</ulink> . First, to add to a queue, the pathname ends with\n      \"queue-YY\" where YY is the priority of the element with lower numbers\n      representing higher priority (just like UNIX). Second, when removing\n      from the queue, a client uses an up-to-date children list meaning that\n      the client will invalidate previously obtained children lists if a watch\n      notification triggers for the queue node.</para>\n    </section>\n  </section>\n\n  <section id=\"sc_recipes_Locks\">\n    <title>Locks</title>\n\n    <para>Fully distributed locks that are globally synchronous, meaning at\n    any snapshot in time no two clients think they hold the same lock. These\n    can be implemented using ZooKeeeper. As with priority queues, first define\n    a lock node.</para>\n\n    <note>\n      <para>There now exists a Lock implementation in ZooKeeper\n      recipes directory. This is distributed with the release --\n      src/recipes/lock directory of the release artifact.\n      </para>\n    </note>\n\n    <para>Clients wishing to obtain a lock do the following:</para>\n\n    <orderedlist>\n      <listitem>\n        <para>Call <emphasis role=\"bold\">create( )</emphasis> with a pathname\n        of \"_locknode_/lock-\" and the <emphasis>sequence</emphasis> and\n        <emphasis>ephemeral</emphasis> flags set.</para>\n      </listitem>\n\n      <listitem>\n        <para>Call <emphasis role=\"bold\">getChildren( )</emphasis> on the lock\n        node <emphasis>without</emphasis> setting the watch flag (this is\n        important to avoid the herd effect).</para>\n      </listitem>\n\n      <listitem>\n        <para>If the pathname created in step <emphasis\n        role=\"bold\">1</emphasis> has the lowest sequence number suffix, the\n        client has the lock and the client exits the protocol.</para>\n      </listitem>\n\n      <listitem>\n        <para>The client calls <emphasis role=\"bold\">exists( )</emphasis> with\n        the watch flag set on the path in the lock directory with the next\n        lowest sequence number.</para>\n      </listitem>\n\n      <listitem>\n        <para>if <emphasis role=\"bold\">exists( )</emphasis> returns false, go\n        to step <emphasis role=\"bold\">2</emphasis>. Otherwise, wait for a\n        notification for the pathname from the previous step before going to\n        step <emphasis role=\"bold\">2</emphasis>.</para>\n      </listitem>\n    </orderedlist>\n\n    <para>The unlock protocol is very simple: clients wishing to release a\n    lock simply delete the node they created in step 1.</para>\n\n    <para>Here are a few things to notice:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para>The removal of a node will only cause one client to wake up\n        since each node is watched by exactly one client. In this way, you\n        avoid the herd effect.</para>\n      </listitem>\n    </itemizedlist>\n\n    <itemizedlist>\n      <listitem>\n        <para>There is no polling or timeouts.</para>\n      </listitem>\n    </itemizedlist>\n\n    <itemizedlist>\n      <listitem>\n        <para>Because of the way you implement locking, it is easy to see the\n        amount of lock contention, break locks, debug locking problems,\n        etc.</para>\n      </listitem>\n    </itemizedlist>\n\n    <section>\n      <title>Shared Locks</title>\n\n      <para>You can implement shared locks by with a few changes to the lock\n      protocol:</para>\n\n      <informaltable colsep=\"0\" frame=\"none\" rowsep=\"0\">\n        <tgroup cols=\"2\">\n          <tbody>\n            <row>\n              <entry align=\"center\"><emphasis role=\"bold\">Obtaining a read\n              lock:</emphasis></entry>\n\n              <entry align=\"center\"><emphasis role=\"bold\">Obtaining a write\n              lock:</emphasis></entry>\n            </row>\n\n            <row>\n              <entry align=\"left\"><orderedlist>\n                  <listitem>\n                    <para>Call <emphasis role=\"bold\">create( )</emphasis> to\n                    create a node with pathname\n                    \"<filename>_locknode_/read-</filename>\". This is the\n                    lock node use later in the protocol. Make sure to set both\n                    the <emphasis>sequence</emphasis> and\n                    <emphasis>ephemeral</emphasis> flags.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Call <emphasis role=\"bold\">getChildren( )</emphasis>\n                    on the lock node <emphasis>without</emphasis> setting the\n                    <emphasis>watch</emphasis> flag - this is important, as it\n                    avoids the herd effect.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>If there are no children with a pathname starting\n                    with \"<filename>write-</filename>\" and having a lower\n                    sequence number than the node created in step <emphasis\n                    role=\"bold\">1</emphasis>, the client has the lock and can\n                    exit the protocol. </para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Otherwise, call <emphasis role=\"bold\">exists(\n                    )</emphasis>, with <emphasis>watch</emphasis> flag, set on\n                    the node in lock directory with pathname staring with\n                    \"<filename>write-</filename>\" having the next lowest\n                    sequence number.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>If <emphasis role=\"bold\">exists( )</emphasis>\n                    returns <emphasis>false</emphasis>, goto step <emphasis\n                    role=\"bold\">2</emphasis>.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Otherwise, wait for a notification for the pathname\n                    from the previous step before going to step <emphasis\n                    role=\"bold\">2</emphasis></para>\n                  </listitem>\n                </orderedlist></entry>\n\n              <entry><orderedlist>\n                  <listitem>\n                    <para>Call <emphasis role=\"bold\">create( )</emphasis> to\n                    create a node with pathname\n                    \"<filename>_locknode_/write-</filename>\". This is the\n                    lock node spoken of later in the protocol. Make sure to\n                    set both <emphasis>sequence</emphasis> and\n                    <emphasis>ephemeral</emphasis> flags.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Call <emphasis role=\"bold\">getChildren( )\n                    </emphasis> on the lock node <emphasis>without</emphasis>\n                    setting the <emphasis>watch</emphasis> flag - this is\n                    important, as it avoids the herd effect.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>If there are no children with a lower sequence\n                    number than the node created in step <emphasis\n                    role=\"bold\">1</emphasis>, the client has the lock and the\n                    client exits the protocol.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>Call <emphasis role=\"bold\">exists( ),</emphasis>\n                    with <emphasis>watch</emphasis> flag set, on the node with\n                    the pathname that has the next lowest sequence\n                    number.</para>\n                  </listitem>\n\n                  <listitem>\n                    <para>If <emphasis role=\"bold\">exists( )</emphasis>\n                    returns <emphasis>false</emphasis>, goto step <emphasis\n                    role=\"bold\">2</emphasis>. Otherwise, wait for a\n                    notification for the pathname from the previous step\n                    before going to step <emphasis\n                    role=\"bold\">2</emphasis>.</para>\n                  </listitem>\n                </orderedlist></entry>\n            </row>\n          </tbody>\n        </tgroup>\n      </informaltable>\n\n      <note>\n        <para>It might appear that this recipe creates a herd effect:\n          when there is a large group of clients waiting for a read\n          lock, and all getting notified more or less simultaneously\n          when the \"<filename>write-</filename>\" node with the lowest\n          sequence number is deleted. In fact. that's valid behavior:\n          as all those waiting reader clients should be released since\n          they have the lock. The herd effect refers to releasing a\n          \"herd\" when in fact only a single or a small number of\n          machines can proceed.\n        </para>\n      </note>\n    </section>\n\n    <section id=\"sc_recoverableSharedLocks\">\n      <title>Recoverable Shared Locks</title>\n\n      <para>With minor modifications to the Shared Lock protocol, you make\n      shared locks revocable by modifying the shared lock protocol:</para>\n\n      <para>In step <emphasis role=\"bold\">1</emphasis>, of both obtain reader\n      and writer lock protocols, call <emphasis role=\"bold\">getData(\n      )</emphasis> with <emphasis>watch</emphasis> set, immediately after the\n      call to <emphasis role=\"bold\">create( )</emphasis>. If the client\n      subsequently receives notification for the node it created in step\n      <emphasis role=\"bold\">1</emphasis>, it does another <emphasis\n      role=\"bold\">getData( )</emphasis> on that node, with\n      <emphasis>watch</emphasis> set and looks for the string \"unlock\", which\n      signals to the client that it must release the lock. This is because,\n      according to this shared lock protocol, you can request the client with\n      the lock give up the lock by calling <emphasis role=\"bold\">setData()\n      </emphasis> on the lock node, writing \"unlock\" to that node.</para>\n\n      <para>Note that this protocol requires the lock holder to consent to\n      releasing the lock. Such consent is important, especially if the lock\n      holder needs to do some processing before releasing the lock. Of course\n      you can always implement <emphasis>Revocable Shared Locks with Freaking\n      Laser Beams</emphasis> by stipulating in your protocol that the revoker\n      is allowed to delete the lock node if after some length of time the lock\n      isn't deleted by the lock holder.</para>\n    </section>\n  </section>\n\n  <section id=\"sc_recipes_twoPhasedCommit\">\n    <title>Two-phased Commit</title>\n\n    <para>A two-phase commit protocol is an algorithm that lets all clients in\n    a distributed system agree either to commit a transaction or abort.</para>\n\n    <para>In ZooKeeper, you can implement a two-phased commit by having a\n    coordinator create a transaction node, say \"/app/Tx\", and one child node\n    per participating site, say \"/app/Tx/s_i\". When coordinator creates the\n    child node, it leaves the content undefined. Once each site involved in\n    the transaction receives the transaction from the coordinator, the site\n    reads each child node and sets a watch. Each site then processes the query\n    and votes \"commit\" or \"abort\" by writing to its respective node. Once the\n    write completes, the other sites are notified, and as soon as all sites\n    have all votes, they can decide either \"abort\" or \"commit\". Note that a\n    node can decide \"abort\" earlier if some site votes for \"abort\".</para>\n\n    <para>An interesting aspect of this implementation is that the only role\n    of the coordinator is to decide upon the group of sites, to create the\n    ZooKeeper nodes, and to propagate the transaction to the corresponding\n    sites. In fact, even propagating the transaction can be done through\n    ZooKeeper by writing it in the transaction node.</para>\n\n    <para>There are two important drawbacks of the approach described above.\n    One is the message complexity, which is O(n²). The second is the\n    impossibility of detecting failures of sites through ephemeral nodes. To\n    detect the failure of a site using ephemeral nodes, it is necessary that\n    the site create the node.</para>\n\n    <para>To solve the first problem, you can have only the coordinator\n    notified of changes to the transaction nodes, and then notify the sites\n    once coordinator reaches a decision. Note that this approach is scalable,\n    but it's is slower too, as it requires all communication to go through the\n    coordinator.</para>\n\n    <para>To address the second problem, you can have the coordinator\n    propagate the transaction to the sites, and have each site creating its\n    own ephemeral node.</para>\n  </section>\n\n  <section id=\"sc_leaderElection\">\n    <title>Leader Election</title>\n\n    <para>A simple way of doing leader election with ZooKeeper is to use the\n    <emphasis role=\"bold\">SEQUENCE|EPHEMERAL</emphasis> flags when creating\n    znodes that represent \"proposals\" of clients. The idea is to have a znode,\n    say \"/election\", such that each znode creates a child znode \"/election/n_\"\n    with both flags SEQUENCE|EPHEMERAL. With the sequence flag, ZooKeeper\n    automatically appends a sequence number that is greater that any one\n    previously appended to a child of \"/election\". The process that created\n    the znode with the smallest appended sequence number is the leader.\n    </para>\n\n    <para>That's not all, though. It is important to watch for failures of the\n    leader, so that a new client arises as the new leader in the case the\n    current leader fails. A trivial solution is to have all application\n    processes watching upon the current smallest znode, and checking if they\n    are the new leader when the smallest znode goes away (note that the\n    smallest znode will go away if the leader fails because the node is\n    ephemeral). But this causes a herd effect: upon of failure of the current\n    leader, all other processes receive a notification, and execute\n    getChildren on \"/election\" to obtain the current list of children of\n    \"/election\". If the number of clients is large, it causes a spike on the\n    number of operations that ZooKeeper servers have to process. To avoid the\n    herd effect, it is sufficient to watch for the next znode down on the\n    sequence of znodes. If a client receives a notification that the znode it\n    is watching is gone, then it becomes the new leader in the case that there\n    is no smaller znode. Note that this avoids the herd effect by not having\n    all clients watching the same znode. </para>\n\n    <para>Here's the pseudo code:</para>\n\n    <para>Let ELECTION be a path of choice of the application. To volunteer to\n    be a leader: </para>\n\n    <orderedlist>\n      <listitem>\n        <para>Create znode z with path \"ELECTION/n_\" with both SEQUENCE and\n        EPHEMERAL flags;</para>\n      </listitem>\n\n      <listitem>\n        <para>Let C be the children of \"ELECTION\", and i be the sequence\n        number of z;</para>\n      </listitem>\n\n      <listitem>\n        <para>Watch for changes on \"ELECTION/n_j\", where j is the largest\n        sequence number such that j &lt; i and n_j is a znode in C;</para>\n      </listitem>\n    </orderedlist>\n\n    <para>Upon receiving a notification of znode deletion: </para>\n\n    <orderedlist>\n      <listitem>\n        <para>Let C be the new set of children of ELECTION; </para>\n      </listitem>\n\n      <listitem>\n        <para>If z is the smallest node in C, then execute leader\n        procedure;</para>\n      </listitem>\n\n      <listitem>\n        <para>Otherwise, watch for changes on \"ELECTION/n_j\", where j is the\n        largest sequence number such that j &lt; i and n_j is a znode in C;\n        </para>\n      </listitem>\n    </orderedlist>\n\n    <para>Note that the znode having no preceding znode on the list of\n    children does not imply that the creator of this znode is aware that it is\n    the current leader. Applications may consider creating a separate znode\n    to acknowledge that the leader has executed the leader procedure. </para>\n  </section>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/site.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!--\nForrest site.xml\n\nThis file contains an outline of the site's information content.  It is used to:\n- Generate the website menus (though these can be overridden - see docs)\n- Provide semantic, location-independent aliases for internal 'site:' URIs, eg\n<link href=\"site:changes\"> links to changes.html (or ../changes.html if in\n  subdir).\n- Provide aliases for external URLs in the external-refs section.  Eg, <link\n  href=\"ext:cocoon\"> links to http://xml.apache.org/cocoon/\n\nSee http://forrest.apache.org/docs/linking.html for more info.\n-->\n\n<site label=\"ZooKeeper\" href=\"\" xmlns=\"http://apache.org/forrest/linkmap/1.0\">\n\n  <docs label=\"Overview\"> \n    <welcome   label=\"Welcome\"                href=\"index.html\" />\n    <overview  label=\"Overview\"               href=\"zookeeperOver.html\" />\n    <started   label=\"Getting Started\"        href=\"zookeeperStarted.html\" />\n    <relnotes  label=\"Release Notes\"          href=\"ext:relnotes\" />\n  </docs>\n  \n  <docs label=\"Developer\">\n    <api       label=\"API Docs\"               href=\"ext:api/index\" />\n    <program   label=\"Programmer's Guide\"     href=\"zookeeperProgrammers.html\" />\n    <javaEx    label=\"Java Example\"     href=\"javaExample.html\" />\n    <barTutor  label=\"Barrier and Queue Tutorial\" href=\"zookeeperTutorial.html\" />\n    <recipes   label=\"Recipes\"\t\t      href=\"recipes.html\" />\n  </docs>\n  \n  <docs label=\"BookKeeper\">\n      <bkStarted label=\"Getting started\"  href=\"bookkeeperStarted.html\" />\n      <bkOverview label=\"Overview\"            href=\"bookkeeperOverview.html\" />\n      <bkProgrammer   label=\"Setup guide\"                    href=\"bookkeeperConfig.html\" />\n      <bkProgrammer   label=\"Programmer's guide\"                    href=\"bookkeeperProgrammer.html\" />\n  </docs>\n  \n  <docs label=\"Admin &amp; Ops\">\n      <admin label=\"Administrator's Guide\"  href=\"zookeeperAdmin.html\" />\n      <quota label=\"Quota Guide\"            href=\"zookeeperQuotas.html\" />\n      <jmx   label=\"JMX\"                    href=\"zookeeperJMX.html\" />\n      <observers label=\"Observers Guide\" href=\"zookeeperObservers.html\" />\n  </docs>\n  \n  <docs label=\"Contributor\">\n      <internals label=\"ZooKeeper Internals\"\thref=\"zookeeperInternals.html\" />\n  </docs>\n  \n  <docs label=\"Miscellaneous\">\n    <wiki      label=\"Wiki\"                   href=\"ext:wiki\" />\n    <faq       label=\"FAQ\"                    href=\"ext:faq\" />\n    <lists     label=\"Mailing Lists\"          href=\"ext:lists\" />\n    <!--<other     label=\"Other Info\"\t      href=\"zookeeperOtherInfo.html\" />-->\n  </docs>\n  \n  \n\n  <external-refs>\n    <site      href=\"http://zookeeper.apache.org/\"/>\n    <lists     href=\"http://zookeeper.apache.org/mailing_lists.html\"/>\n    <releases  href=\"http://zookeeper.apache.org/releases.html\">\n      <download href=\"#Download\" />\n    </releases>\n    <jira      href=\"http://zookeeper.apache.org/issue_tracking.html\"/>\n    <wiki      href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER\" />\n    <faq       href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/FAQ\" />\n    <zlib      href=\"http://www.zlib.net/\" />\n    <lzo       href=\"http://www.oberhumer.com/opensource/lzo/\" />\n    <gzip      href=\"http://www.gzip.org/\" />\n    <cygwin    href=\"http://www.cygwin.com/\" />\n    <osx       href=\"http://www.apple.com/macosx\" />\n    <relnotes  href=\"releasenotes.html\" />\n    <api href=\"api/\">\n      <started href=\"overview-summary.html#overview_description\" />\n      <index href=\"index.html\" />\n      <org href=\"org/\">\n        <apache href=\"apache/\">\n          <zookeeper href=\"zookeeper/\">\n          </zookeeper>\n        </apache>\n      </org>\n    </api>\n  </external-refs>\n \n</site>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/tabs.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE tabs PUBLIC \"-//APACHE//DTD Cocoon Documentation Tab V1.0//EN\" \n          \"http://forrest.apache.org/dtd/tab-cocoon-v10.dtd\">\n\n<tabs software=\"ZooKeeper\"\n      title=\"ZooKeeper\"\n      copyright=\"The Apache Software Foundation\"\n      xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n  <!-- The rules are:\n    @dir will always have /index.html added.\n    @href is not modified unless it is root-relative and obviously specifies a\n    directory (ends in '/'), in which case /index.html will be added\n  -->\n\n  <tab label=\"Project\" href=\"http://zookeeper.apache.org/\" />\n  <tab label=\"Wiki\" href=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/\" />\n  <tab label=\"ZooKeeper 3.4 Documentation\" dir=\"\" />\n  \n</tabs>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_Admin\">\n  <title>ZooKeeper Administrator's Guide</title>\n\n  <subtitle>A Guide to Deployment and Administration</subtitle>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This document contains information about deploying, administering\n      and mantaining ZooKeeper. It also discusses best practices and common\n      problems.</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_deployment\">\n    <title>Deployment</title>\n\n    <para>This section contains information about deploying Zookeeper and\n    covers these topics:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"sc_systemReq\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"sc_zkMulitServerSetup\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"sc_singleAndDevSetup\" /></para>\n      </listitem>\n    </itemizedlist>\n\n    <para>The first two sections assume you are interested in installing\n    ZooKeeper in a production environment such as a datacenter. The final\n    section covers situations in which you are setting up ZooKeeper on a\n    limited basis - for evaluation, testing, or development - but not in a\n    production environment.</para>\n\n    <section id=\"sc_systemReq\">\n      <title>System Requirements</title>\n\n      <section id=\"sc_supportedPlatforms\">\n        <title>Supported Platforms</title>\n\n        <para>ZooKeeper consists of multiple components. Some components are\n        supported broadly, and other components are supported only on a smaller\n        set of platforms.</para>\n\n        <itemizedlist>\n          <listitem>\n            <para><emphasis role=\"bold\">Client</emphasis> is the Java client\n            library, used by applications to connect to a ZooKeeper ensemble.\n            </para>\n          </listitem>\n          <listitem>\n            <para><emphasis role=\"bold\">Server</emphasis> is the Java server\n            that runs on the ZooKeeper ensemble nodes.</para>\n          </listitem>\n          <listitem>\n            <para><emphasis role=\"bold\">Native Client</emphasis> is a client\n            implemented in C, similar to the Java client, used by applications\n            to connect to a ZooKeeper ensemble.</para>\n          </listitem>\n          <listitem>\n            <para><emphasis role=\"bold\">Contrib</emphasis> refers to multiple\n            optional add-on components.</para>\n          </listitem>\n        </itemizedlist>\n\n        <para>The following matrix describes the level of support committed for\n        running each component on different operating system platforms.</para>\n\n        <table>\n          <title>Support Matrix</title>\n          <tgroup cols=\"5\" align=\"left\" colsep=\"1\" rowsep=\"1\">\n            <thead>\n              <row>\n                <entry>Operating System</entry>\n                <entry>Client</entry>\n                <entry>Server</entry>\n                <entry>Native Client</entry>\n                <entry>Contrib</entry>\n              </row>\n            </thead>\n            <tbody>\n              <row>\n                <entry>GNU/Linux</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n              </row>\n              <row>\n                <entry>Solaris</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n                <entry>Not Supported</entry>\n                <entry>Not Supported</entry>\n              </row>\n              <row>\n                <entry>FreeBSD</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n                <entry>Not Supported</entry>\n                <entry>Not Supported</entry>\n              </row>\n              <row>\n                <entry>Windows</entry>\n                <entry>Development and Production</entry>\n                <entry>Development and Production</entry>\n                <entry>Not Supported</entry>\n                <entry>Not Supported</entry>\n              </row>\n              <row>\n                <entry>Mac OS X</entry>\n                <entry>Development Only</entry>\n                <entry>Development Only</entry>\n                <entry>Not Supported</entry>\n                <entry>Not Supported</entry>\n              </row>\n            </tbody>\n          </tgroup>\n        </table>\n\n        <para>For any operating system not explicitly mentioned as supported in\n        the matrix, components may or may not work.  The ZooKeeper community\n        will fix obvious bugs that are reported for other platforms, but there\n        is no full support.</para>\n      </section>\n\n      <section id=\"sc_requiredSoftware\">\n        <title>Required Software </title>\n\n        <para>ZooKeeper runs in Java, release 1.6 or greater (JDK 6 or\n          greater).  It runs as an <emphasis>ensemble</emphasis> of\n          ZooKeeper servers. Three ZooKeeper servers is the minimum\n          recommended size for an ensemble, and we also recommend that\n          they run on separate machines. At Yahoo!, ZooKeeper is\n          usually deployed on dedicated RHEL boxes, with dual-core\n          processors, 2GB of RAM, and 80GB IDE hard drives.</para>\n      </section>\n\n    </section>\n\n    <section id=\"sc_zkMulitServerSetup\">\n      <title>Clustered (Multi-Server) Setup</title>\n\n      <para>For reliable ZooKeeper service, you should deploy ZooKeeper in a\n      cluster known as an <emphasis>ensemble</emphasis>. As long as a majority\n      of the ensemble are up, the service will be available. Because Zookeeper\n      requires a majority, it is best to use an\n      odd number of machines. For example, with four machines ZooKeeper can\n      only handle the failure of a single machine; if two machines fail, the\n      remaining two machines do not constitute a majority. However, with five\n      machines ZooKeeper can handle the failure of two machines. </para>\n      <note>\n         <para>\n            As mentioned in the\n            <ulink url=\"zookeeperStarted.html\">ZooKeeper Getting Started Guide</ulink>\n            , a minimum of three servers are required for a fault tolerant\n            clustered setup, and it is strongly recommended that you have an\n            odd number of servers.\n         </para>\n         <para>Usually three servers is more than enough for a production\n            install, but for maximum reliability during maintenance, you may\n            wish to install five servers. With three servers, if you perform\n            maintenance on one of them, you are vulnerable to a failure on one\n            of the other two servers during that maintenance. If you have five\n            of them running, you can take one down for maintenance, and know\n            that you're still OK if one of the other four suddenly fails.\n         </para>\n         <para>Your redundancy considerations should include all aspects of\n            your environment. If you have three ZooKeeper servers, but their\n            network cables are all plugged into the same network switch, then\n            the failure of that switch will take down your entire ensemble.\n         </para>\n      </note>\n      <para>Here are the steps to setting a server that will be part of an\n      ensemble. These steps should be performed on every host in the\n      ensemble:</para>\n\n      <orderedlist>\n        <listitem>\n          <para>Install the Java JDK. You can use the native packaging system\n          for your system, or download the JDK from:</para>\n\n          <para><ulink\n          url=\"http://java.sun.com/javase/downloads/index.jsp\">http://java.sun.com/javase/downloads/index.jsp</ulink></para>\n        </listitem>\n\n        <listitem>\n          <para>Set the Java heap size. This is very important to avoid\n          swapping, which will seriously degrade ZooKeeper performance. To\n          determine the correct value, use load tests, and make sure you are\n          well below the usage limit that would cause you to swap. Be\n          conservative - use a maximum heap size of 3GB for a 4GB\n          machine.</para>\n        </listitem>\n\n        <listitem>\n          <para>Install the ZooKeeper Server Package. It can be downloaded\n            from:\n          </para>\n          <para>\n            <ulink url=\"http://zookeeper.apache.org/releases.html\">\n              http://zookeeper.apache.org/releases.html\n            </ulink>\n          </para>\n        </listitem>\n\n        <listitem>\n          <para>Create a configuration file. This file can be called anything.\n          Use the following settings as a starting point:</para>\n\n          <programlisting>\ntickTime=2000\ndataDir=/var/lib/zookeeper/\nclientPort=2181\ninitLimit=5\nsyncLimit=2\nserver.1=zoo1:2888:3888\nserver.2=zoo2:2888:3888\nserver.3=zoo3:2888:3888</programlisting>\n\n          <para>You can find the meanings of these and other configuration\n          settings in the section <xref linkend=\"sc_configuration\" />. A word\n          though about a few here:</para>\n\n          <para>Every machine that is part of the ZooKeeper ensemble should know\n          about every other machine in the ensemble. You accomplish this with\n          the series of lines of the form <emphasis\n          role=\"bold\">server.id=host:port:port</emphasis>. The parameters <emphasis\n          role=\"bold\">host</emphasis> and <emphasis\n          role=\"bold\">port</emphasis> are straightforward. You attribute the\n          server id to each machine by creating a file named\n          <filename>myid</filename>, one for each server, which resides in\n          that server's data directory, as specified by the configuration file\n          parameter <emphasis role=\"bold\">dataDir</emphasis>.</para></listitem>\n\n          <listitem><para>The myid file\n          consists of a single line containing only the text of that machine's\n          id. So <filename>myid</filename> of server 1 would contain the text\n          \"1\" and nothing else. The id must be unique within the\n          ensemble and should have a value between 1 and 255.</para>\n        </listitem>\n\n        <listitem>\n          <para>If your configuration file is set up, you can start a\n          ZooKeeper server:</para>\n\n          <para><computeroutput>$ java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf \\\n              org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg\n          </computeroutput></para>\n          \n          <para>QuorumPeerMain starts a ZooKeeper server,\n            <ulink url=\"http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/\">JMX</ulink>\n            management beans are also registered which allows\n            management through a JMX management console. \n            The <ulink url=\"zookeeperJMX.html\">ZooKeeper JMX\n            document</ulink> contains details on managing ZooKeeper with JMX.\n          </para>\n\n          <para>See the script <emphasis>bin/zkServer.sh</emphasis>,\n            which is included in the release, for an example\n            of starting server instances.</para>\n\n        </listitem>\n\n        <listitem>\n          <para>Test your deployment by connecting to the hosts:</para>\n\n          <para>In Java, you can run the following command to execute\n          simple operations:</para>\n\n          <para><computeroutput>$ bin/zkCli.sh -server 127.0.0.1:2181</computeroutput></para>\n        </listitem>\n      </orderedlist>\n    </section>\n\n    <section id=\"sc_singleAndDevSetup\">\n      <title>Single Server and Developer Setup</title>\n\n      <para>If you want to setup ZooKeeper for development purposes, you will\n      probably want to setup a single server instance of ZooKeeper, and then\n      install either the Java or C client-side libraries and bindings on your\n      development machine.</para>\n\n      <para>The steps to setting up a single server instance are the similar\n      to the above, except the configuration file is simpler. You can find the\n      complete instructions in the <ulink\n      url=\"zookeeperStarted.html#sc_InstallingSingleMode\">Installing and\n      Running ZooKeeper in Single Server Mode</ulink> section of the <ulink\n      url=\"zookeeperStarted.html\">ZooKeeper Getting Started\n      Guide</ulink>.</para>\n\n      <para>For information on installing the client side libraries, refer to\n      the <ulink url=\"zookeeperProgrammers.html#Bindings\">Bindings</ulink>\n      section of the <ulink url=\"zookeeperProgrammers.html\">ZooKeeper\n      Programmer's Guide</ulink>.</para>\n    </section>\n  </section>\n\n  <section id=\"ch_administration\">\n    <title>Administration</title>\n\n    <para>This section contains information about running and maintaining\n    ZooKeeper and covers these topics: </para>\n    <itemizedlist>\n        <listitem>\n          <para><xref linkend=\"sc_designing\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_provisioning\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_strengthsAndLimitations\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_administering\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_maintenance\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_supervision\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_monitoring\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_logging\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_troubleshooting\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_configuration\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_zkCommands\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_dataFileManagement\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_commonProblems\" /></para>\n        </listitem>\n\n        <listitem>\n          <para><xref linkend=\"sc_bestPractices\" /></para>\n        </listitem>\n      </itemizedlist>\n\n    <section id=\"sc_designing\">\n      <title>Designing a ZooKeeper Deployment</title>\n\n      <para>The reliablity of ZooKeeper rests on two basic assumptions.</para>\n      <orderedlist>\n        <listitem><para> Only a minority of servers in a deployment\n            will fail. <emphasis>Failure</emphasis> in this context\n            means a machine crash, or some error in the network that\n            partitions a server off from the majority.</para>\n        </listitem>\n        <listitem><para> Deployed machines operate correctly. To\n            operate correctly means to execute code correctly, to have\n            clocks that work properly, and to have storage and network\n            components that perform consistently.</para>\n        </listitem>\n      </orderedlist>\n    \n    <para>The sections below contain considerations for ZooKeeper\n      administrators to maximize the probability for these assumptions\n      to hold true. Some of these are cross-machines considerations,\n      and others are things you should consider for each and every\n      machine in your deployment.</para>\n\n    <section id=\"sc_CrossMachineRequirements\">\n      <title>Cross Machine Requirements</title>\n    \n      <para>For the ZooKeeper service to be active, there must be a\n        majority of non-failing machines that can communicate with\n        each other. To create a deployment that can tolerate the\n        failure of F machines, you should count on deploying 2xF+1\n        machines.  Thus, a deployment that consists of three machines\n        can handle one failure, and a deployment of five machines can\n        handle two failures. Note that a deployment of six machines\n        can only handle two failures since three machines is not a\n        majority.  For this reason, ZooKeeper deployments are usually\n        made up of an odd number of machines.</para>\n\n      <para>To achieve the highest probability of tolerating a failure\n        you should try to make machine failures independent. For\n        example, if most of the machines share the same switch,\n        failure of that switch could cause a correlated failure and\n        bring down the service. The same holds true of shared power\n        circuits, cooling systems, etc.</para>\n    </section>\n\n    <section>\n      <title>Single Machine Requirements</title>\n\n      <para>If ZooKeeper has to contend with other applications for\n        access to resourses like storage media, CPU, network, or\n        memory, its performance will suffer markedly.  ZooKeeper has\n        strong durability guarantees, which means it uses storage\n        media to log changes before the operation responsible for the\n        change is allowed to complete. You should be aware of this\n        dependency then, and take great care if you want to ensure\n        that ZooKeeper operations aren’t held up by your media. Here\n        are some things you can do to minimize that sort of\n        degradation:\n      </para>\n\n      <itemizedlist>\n        <listitem>\n          <para>ZooKeeper's transaction log must be on a dedicated\n            device. (A dedicated partition is not enough.) ZooKeeper\n            writes the log sequentially, without seeking Sharing your\n            log device with other processes can cause seeks and\n            contention, which in turn can cause multi-second\n            delays.</para>\n        </listitem>\n\n        <listitem>\n          <para>Do not put ZooKeeper in a situation that can cause a\n            swap. In order for ZooKeeper to function with any sort of\n            timeliness, it simply cannot be allowed to swap.\n            Therefore, make certain that the maximum heap size given\n            to ZooKeeper is not bigger than the amount of real memory\n            available to ZooKeeper.  For more on this, see\n            <xref linkend=\"sc_commonProblems\"/>\n            below. </para>\n        </listitem>\n      </itemizedlist>\n    </section>\n    </section>\n\n    <section id=\"sc_provisioning\">\n      <title>Provisioning</title>\n\n      <para></para>\n    </section>\n\n    <section id=\"sc_strengthsAndLimitations\">\n      <title>Things to Consider: ZooKeeper Strengths and Limitations</title>\n\n      <para></para>\n    </section>\n\n    <section id=\"sc_administering\">\n      <title>Administering</title>\n\n      <para></para>\n    </section>\n\n    <section id=\"sc_maintenance\">\n      <title>Maintenance</title>\n\n      <para>Little long term maintenance is required for a ZooKeeper\n        cluster however you must be aware of the following:</para>\n\n      <section>\n        <title>Ongoing Data Directory Cleanup</title>\n\n        <para>The ZooKeeper <ulink url=\"#var_datadir\">Data\n          Directory</ulink> contains files which are a persistent copy\n          of the znodes stored by a particular serving ensemble. These\n          are the snapshot and transactional log files. As changes are\n          made to the znodes these changes are appended to a\n          transaction log. Occasionally, when a log grows large, a\n          snapshot of the current state of all znodes will be written\n          to the filesystem and a new transaction log file is created\n          for future transactions. During snapshotting, ZooKeeper may\n          continue appending incoming transactions to the old log file.\n          Therefore, some transactions which are newer than a snapshot\n          may be found in the last transaction log preceding the\n          snapshot.\n        </para>\n\n        <para>A ZooKeeper server <emphasis role=\"bold\">will not remove\n        old snapshots and log files</emphasis> when using the default\n        configuration (see autopurge below), this is the\n        responsibility of the operator. Every serving environment is\n        different and therefore the requirements of managing these\n        files may differ from install to install (backup for example).\n        </para>\n\n        <para>The PurgeTxnLog utility implements a simple retention\n        policy that administrators can use. The <ulink\n        url=\"ext:api/index\">API docs</ulink> contains details on\n        calling conventions (arguments, etc...).\n        </para>\n\n        <para>In the following example the last count snapshots and\n        their corresponding logs are retained and the others are\n        deleted.  The value of &lt;count&gt; should typically be\n        greater than 3 (although not required, this provides 3 backups\n        in the unlikely event a recent log has become corrupted). This\n        can be run as a cron job on the ZooKeeper server machines to\n        clean up the logs daily.</para>\n\n        <programlisting> java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.PurgeTxnLog &lt;dataDir&gt; &lt;snapDir&gt; -n &lt;count&gt;</programlisting>\n\n        <para>Automatic purging of the snapshots and corresponding\n        transaction logs was introduced in version 3.4.0 and can be\n        enabled via the following configuration parameters <emphasis\n        role=\"bold\">autopurge.snapRetainCount</emphasis> and <emphasis\n        role=\"bold\">autopurge.purgeInterval</emphasis>. For more on\n        this, see <xref linkend=\"sc_advancedConfiguration\"/>\n        below.</para>\n      </section>\n\n      <section>\n        <title>Debug Log Cleanup (log4j)</title>\n\n        <para>See the section on <ulink\n        url=\"#sc_logging\">logging</ulink> in this document. It is\n        expected that you will setup a rolling file appender using the\n        in-built log4j feature. The sample configuration file in the\n        release tar's conf/log4j.properties provides an example of\n        this.\n        </para>\n      </section>\n\n    </section>\n\n    <section id=\"sc_supervision\">\n      <title>Supervision</title>\n\n      <para>You will want to have a supervisory process that manages\n      each of your ZooKeeper server processes (JVM). The ZK server is\n      designed to be \"fail fast\" meaning that it will shutdown\n      (process exit) if an error occurs that it cannot recover\n      from. As a ZooKeeper serving cluster is highly reliable, this\n      means that while the server may go down the cluster as a whole\n      is still active and serving requests. Additionally, as the\n      cluster is \"self healing\" the failed server once restarted will\n      automatically rejoin the ensemble w/o any manual\n      interaction.</para>\n\n      <para>Having a supervisory process such as <ulink\n      url=\"http://cr.yp.to/daemontools.html\">daemontools</ulink> or\n      <ulink\n      url=\"http://en.wikipedia.org/wiki/Service_Management_Facility\">SMF</ulink>\n      (other options for supervisory process are also available, it's\n      up to you which one you would like to use, these are just two\n      examples) managing your ZooKeeper server ensures that if the\n      process does exit abnormally it will automatically be restarted\n      and will quickly rejoin the cluster.</para>\n    </section>\n\n    <section id=\"sc_monitoring\">\n      <title>Monitoring</title>\n\n      <para>The ZooKeeper service can be monitored in one of two\n      primary ways; 1) the command port through the use of <ulink\n      url=\"#sc_zkCommands\">4 letter words</ulink> and 2) <ulink\n      url=\"zookeeperJMX.html\">JMX</ulink>. See the appropriate section for\n      your environment/requirements.</para>\n    </section>\n\n    <section id=\"sc_logging\">\n      <title>Logging</title>\n\n      <para>ZooKeeper uses <emphasis role=\"bold\">log4j</emphasis> version 1.2 as \n      its logging infrastructure. The  ZooKeeper default <filename>log4j.properties</filename> \n      file resides in the <filename>conf</filename> directory. Log4j requires that \n      <filename>log4j.properties</filename> either be in the working directory \n      (the directory from which ZooKeeper is run) or be accessible from the classpath.</para>\n\n      <para>For more information, see \n      <ulink url=\"http://logging.apache.org/log4j/1.2/manual.html#defaultInit\">Log4j Default Initialization Procedure</ulink> \n      of the log4j manual.</para>\n      \n    </section>\n\n    <section id=\"sc_troubleshooting\">\n      <title>Troubleshooting</title>\n\t<variablelist>\n\t\t<varlistentry>\n\t\t<term> Server not coming up because of file corruption</term>\n\t\t<listitem>\n\t\t<para>A server might not be able to read its database and fail to come up because of \n\t\tsome file corruption in the transaction logs of the ZooKeeper server. You will\n\t\tsee some IOException on loading ZooKeeper database. In such a case,\n\t\tmake sure all the other servers in your ensemble are up and  working. Use \"stat\" \n\t\tcommand on the command port to see if they are in good health. After you have verified that\n\t\tall the other servers of the ensemble are up, you can go ahead and clean the database\n\t\tof the corrupt server. Delete all the files in datadir/version-2 and datalogdir/version-2/.\n\t\tRestart the server.\n\t\t</para>\n\t\t</listitem>\n\t\t</varlistentry>\n\t\t</variablelist>\n    </section>\n\n    <section id=\"sc_configuration\">\n      <title>Configuration Parameters</title>\n\n      <para>ZooKeeper's behavior is governed by the ZooKeeper configuration\n      file. This file is designed so that the exact same file can be used by\n      all the servers that make up a ZooKeeper server assuming the disk\n      layouts are the same. If servers use different configuration files, care\n      must be taken to ensure that the list of servers in all of the different\n      configuration files match.</para>\n\n      <section id=\"sc_minimumConfiguration\">\n        <title>Minimum Configuration</title>\n\n        <para>Here are the minimum configuration keywords that must be defined\n        in the configuration file:</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>clientPort</term>\n\n            <listitem>\n              <para>the port to listen for client connections; that is, the\n              port that clients attempt to connect to.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry id=\"var_datadir\">\n            <term>dataDir</term>\n\n            <listitem>\n              <para>the location where ZooKeeper will store the in-memory\n              database snapshots and, unless specified otherwise, the\n              transaction log of updates to the database.</para>\n\n              <note>\n                <para>Be careful where you put the transaction log. A\n                dedicated transaction log device is key to consistent good\n                performance. Putting the log on a busy device will adversely\n                effect performance.</para>\n              </note>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry id=\"id_tickTime\">\n            <term>tickTime</term>\n\n            <listitem>\n              <para>the length of a single tick, which is the basic time unit\n              used by ZooKeeper, as measured in milliseconds. It is used to\n              regulate heartbeats, and timeouts. For example, the minimum\n              session timeout will be two ticks.</para>\n            </listitem>\n          </varlistentry>\n        </variablelist>\n      </section>\n\n      <section id=\"sc_advancedConfiguration\">\n        <title>Advanced Configuration</title>\n\n        <para>The configuration settings in the section are optional. You can\n        use them to further fine tune the behaviour of your ZooKeeper servers.\n        Some can also be set using Java system properties, generally of the\n        form <emphasis>zookeeper.keyword</emphasis>. The exact system\n        property, when available, is noted below.</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>dataLogDir</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>This option will direct the machine to write the\n              transaction log to the <emphasis\n              role=\"bold\">dataLogDir</emphasis> rather than the <emphasis\n              role=\"bold\">dataDir</emphasis>. This allows a dedicated log\n              device to be used, and helps avoid competition between logging\n              and snaphots.</para>\n\n              <note>\n                <para>Having a dedicated log device has a large impact on\n                throughput and stable latencies. It is highly recommened to\n                dedicate a log device and set <emphasis\n                role=\"bold\">dataLogDir</emphasis> to point to a directory on\n                that device, and then make sure to point <emphasis\n                role=\"bold\">dataDir</emphasis> to a directory\n                <emphasis>not</emphasis> residing on that device.</para>\n              </note>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>globalOutstandingLimit</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.globalOutstandingLimit.</emphasis>)</para>\n\n              <para>Clients can submit requests faster than ZooKeeper can\n              process them, especially if there are a lot of clients. To\n              prevent ZooKeeper from running out of memory due to queued\n              requests, ZooKeeper will throttle clients so that there is no\n              more than globalOutstandingLimit outstanding requests in the\n              system. The default limit is 1,000.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>preAllocSize</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.preAllocSize</emphasis>)</para>\n\n              <para>To avoid seeks ZooKeeper allocates space in the\n              transaction log file in blocks of preAllocSize kilobytes. The\n              default block size is 64M. One reason for changing the size of\n              the blocks is to reduce the block size if snapshots are taken\n              more often. (Also, see <emphasis\n              role=\"bold\">snapCount</emphasis>).</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>snapCount</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.snapCount</emphasis>)</para>\n\n              <para>ZooKeeper records its transactions using snapshots and\n              a transaction log (think write-ahead log).The number of\n              transactions recorded in the transaction log before a snapshot\n              can be taken (and the transaction log rolled) is determined\n              by snapCount. In order to prevent all of the machines in the quorum\n              from taking a snapshot at the same time, each ZooKeeper server\n              will take a snapshot when the number of transactions in the transaction log\n              reaches a runtime generated random value in the [snapCount/2+1, snapCount] \n              range.The default snapCount is 100,000.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>maxClientCnxns</term>\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Limits the number of concurrent connections (at the socket \n              level) that a single client, identified by IP address, may make\n              to a single member of the ZooKeeper ensemble. This is used to \n              prevent certain classes of DoS attacks, including file \n              descriptor exhaustion. The default is 60. Setting this to 0\n              entirely removes the limit on concurrent connections.</para>\n            </listitem>\n           </varlistentry>\n\n           <varlistentry>\n             <term>clientPortAddress</term>\n\n             <listitem>\n               <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> the\n               address (ipv4, ipv6 or hostname) to listen for client\n               connections; that is, the address that clients attempt\n               to connect to. This is optional, by default we bind in\n               such a way that any connection to the <emphasis\n               role=\"bold\">clientPort</emphasis> for any\n               address/interface/nic on the server will be\n               accepted.</para>\n             </listitem>\n           </varlistentry>\n\n          <varlistentry>\n            <term>minSessionTimeout</term>\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> the\n              minimum session timeout in milliseconds that the server\n              will allow the client to negotiate. Defaults to 2 times\n              the <emphasis role=\"bold\">tickTime</emphasis>.</para>\n            </listitem>\n           </varlistentry>\n\n          <varlistentry>\n            <term>maxSessionTimeout</term>\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> the\n              maximum session timeout in milliseconds that the server\n              will allow the client to negotiate. Defaults to 20 times\n              the <emphasis role=\"bold\">tickTime</emphasis>.</para>\n            </listitem>\n           </varlistentry>\n           \n           <varlistentry>\n             <term>fsync.warningthresholdms</term>\n             <listitem>\n               <para>(Java system property: <emphasis\n               role=\"bold\">zookeeper.fsync.warningthresholdms</emphasis>)</para>\n\n               <para><emphasis role=\"bold\">New in 3.3.4:</emphasis> A\n               warning message will be output to the log whenever an\n               fsync in the Transactional Log (WAL) takes longer than\n               this value. The values is specified in milliseconds and\n               defaults to 1000. This value can only be set as a\n               system property.</para>\n             </listitem>\n           </varlistentry>\n\n          <varlistentry>\n            <term>autopurge.snapRetainCount</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.0:</emphasis> \n              When enabled, ZooKeeper auto purge feature retains\n              the <emphasis role=\"bold\">autopurge.snapRetainCount</emphasis> most\n              recent snapshots and the corresponding transaction logs in the \n              <emphasis role=\"bold\">dataDir</emphasis> and <emphasis \n              role=\"bold\">dataLogDir</emphasis> respectively and deletes the rest.\n              Defaults to 3. Minimum value is 3.</para>\n            </listitem>\n          </varlistentry>\n          \n          <varlistentry>\n            <term>autopurge.purgeInterval</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.0:</emphasis> The\n              time interval in hours for which the purge task has to\n              be triggered. Set to a positive integer (1 and above)\n              to enable the auto purging. Defaults to 0.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>syncEnabled</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.observer.syncEnabled</emphasis>)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.6, 3.5.0:</emphasis>\n              The observers now log transaction and write snapshot to disk\n              by default like the participants. This reduces the recovery time\n              of the observers on restart. Set to \"false\" to disable this\n              feature. Default is \"true\"</para>\n            </listitem>\n          </varlistentry>\n        </variablelist>\n      </section>\n\n      <section id=\"sc_clusterOptions\">\n        <title>Cluster Options</title>\n\n        <para>The options in this section are designed for use with an ensemble\n        of servers -- that is, when deploying clusters of servers.</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>electionAlg</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Election implementation to use. A value of \"0\" corresponds\n              to the original UDP-based version, \"1\" corresponds to the\n              non-authenticated UDP-based version of fast leader election, \"2\"\n              corresponds to the authenticated UDP-based version of fast\n              leader election, and \"3\" corresponds to TCP-based version of\n              fast leader election. Currently, algorithm 3 is the default</para>\n              \n              <note>\n              <para> The implementations of leader election 0, 1, and 2 are now \n              <emphasis role=\"bold\"> deprecated </emphasis>. We have the intention\n              of removing them in the next release, at which point only the \n              FastLeaderElection will be available. \n              </para>\n              </note>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>initLimit</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Amount of time, in ticks (see <ulink\n              url=\"#id_tickTime\">tickTime</ulink>), to allow followers to\n              connect and sync to a leader. Increased this value as needed, if\n              the amount of data managed by ZooKeeper is large.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>leaderServes</term>\n\n            <listitem>\n              <para>(Java system property: zookeeper.<emphasis\n              role=\"bold\">leaderServes</emphasis>)</para>\n\n              <para>Leader accepts client connections. Default value is \"yes\".\n              The leader machine coordinates updates. For higher update\n              throughput at thes slight expense of read throughput the leader\n              can be configured to not accept clients and focus on\n              coordination. The default to this option is yes, which means\n              that a leader will accept client connections.</para>\n\n              <note>\n                <para>Turning on leader selection is highly recommended when\n                you have more than three ZooKeeper servers in an ensemble.</para>\n              </note>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>server.x=[hostname]:nnnnn[:nnnnn], etc</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>servers making up the ZooKeeper ensemble. When the server\n              starts up, it determines which server it is by looking for the\n              file <filename>myid</filename> in the data directory. That file\n              contains the server number, in ASCII, and it should match\n              <emphasis role=\"bold\">x</emphasis> in <emphasis\n              role=\"bold\">server.x</emphasis> in the left hand side of this\n              setting.</para>\n\n              <para>The list of servers that make up ZooKeeper servers that is\n              used by the clients must match the list of ZooKeeper servers\n              that each ZooKeeper server has.</para>\n\n              <para>There are two port numbers <emphasis role=\"bold\">nnnnn</emphasis>. \n              The first followers use to connect to the leader, and the second is for \n              leader election. The leader election port is only necessary if electionAlg \n              is 1, 2, or 3 (default). If electionAlg is 0, then the second port is not \n              necessary. If you want to test multiple servers on a single machine, then \n              different ports can be used for each server.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>syncLimit</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Amount of time, in ticks (see <ulink\n              url=\"#id_tickTime\">tickTime</ulink>), to allow followers to sync\n              with ZooKeeper. If followers fall too far behind a leader, they\n              will be dropped.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>group.x=nnnnn[:nnnnn]</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Enables a hierarchical quorum construction.\"x\" is a group identifier\n              and the numbers following the \"=\" sign correspond to server identifiers. \n              The left-hand side of the assignment is a colon-separated list of server\n              identifiers. Note that groups must be disjoint and the union of all groups\n              must be the ZooKeeper ensemble. </para>\n              \n              <para> You will find an example <ulink url=\"zookeeperHierarchicalQuorums.html\">here</ulink>\n              </para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>weight.x=nnnnn</term>\n\n            <listitem>\n              <para>(No Java system property)</para>\n\n              <para>Used along with \"group\", it assigns a weight to a server when\n              forming quorums. Such a value corresponds to the weight of a server\n              when voting. There are a few parts of ZooKeeper that require voting\n              such as leader election and the atomic broadcast protocol. By default\n              the weight of server is 1. If the configuration defines groups, but not\n              weights, then a value of 1 will be assigned to all servers.  \n              </para>\n              \n              <para> You will find an example <ulink url=\"zookeeperHierarchicalQuorums.html\">here</ulink>\n              </para>\n            </listitem>\n          </varlistentry>\n          \n          <varlistentry>\n            <term>cnxTimeout</term>\n\n            <listitem>\n              <para>(Java system property: zookeeper.<emphasis\n              role=\"bold\">cnxTimeout</emphasis>)</para>\n\n              <para>Sets the timeout value for opening connections for leader election notifications. \n              Only applicable if you are using electionAlg 3. \n              </para>\n\n              <note>\n                <para>Default value is 5 seconds.</para>\n              </note>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>4lw.commands.whitelist</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n                      role=\"bold\">zookeeper.4lw.commands.whitelist</emphasis>)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.10:</emphasis>\n                This property contains a list of comma separated\n                <ulink url=\"#sc_zkCommands\">Four Letter Words</ulink> commands. It is introduced\n                to provide fine grained control over the set of commands ZooKeeper can execute,\n                so users can turn off certain commands if necessary.\n                By default it contains all supported four letter word commands except \"wchp\" and \"wchc\",\n                if the property is not specified. If the property is specified, then only commands listed\n                in the whitelist are enabled.\n              </para>\n\n              <para>Here's an example of the configuration that enables stat, ruok, conf, and isro\n                command while disabling the rest of Four Letter Words command:</para>\n              <programlisting>\n                4lw.commands.whitelist=stat, ruok, conf, isro\n              </programlisting>\n\n              <para>Users can also use asterisk option so they don't have to include every command one by one in the list.\n                As an example, this will enable all four letter word commands:\n              </para>\n              <programlisting>\n                4lw.commands.whitelist=*\n              </programlisting>\n\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>ipReachableTimeout</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n                      role=\"bold\">zookeeper.ipReachableTimeout</emphasis>)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.11:</emphasis>\n                Set this timeout value for IP addresses reachable checking when hostname is resolved, as mesured in\n                milliseconds.\n                By default, ZooKeeper will use the first IP address of the hostname(without any reachable checking).\n                When zookeeper.ipReachableTimeout is set(larger than 0), ZooKeeper will will try to pick up the first \n                IP address which is reachable. This is done by calling Java API InetAddress.isReachable(long timeout)\n                function, in which this timeout value is used. If none of such reachable IP address can be found, the\n                first IP address of the hostname will be used anyway.\n              </para>\n\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>tcpKeepAlive</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n                      role=\"bold\">zookeeper.tcpKeepAlive</emphasis>)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.11:</emphasis>\n                Setting this to true sets the TCP keepAlive flag on the\n                sockets used by quorum members to perform elections.\n                This will allow for connections between quorum members to\n                remain up when there is network infrastructure that may\n                otherwise break them. Some NATs and firewalls may terminate\n                or lose state for long running or idle connections.</para>\n\n              <para> Enabling this option relies on OS level settings to work\n                properly, check your operating system's options regarding TCP\n                keepalive for more information.  Defaults to\n                <emphasis role=\"bold\">false</emphasis>.\n              </para>\n            </listitem>\n          </varlistentry>\n\n        </variablelist>\n        <para></para>\n      </section>\n\n      <section id=\"sc_authOptions\">\n        <title>Authentication &amp; Authorization Options</title>\n\n        <para>The options in this section allow control over\n        authentication/authorization performed by the service.</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>zookeeper.DigestAuthenticationProvider.superDigest</term>\n\n            <listitem>\n              <para>(Java system property only: <emphasis\n              role=\"bold\">zookeeper.DigestAuthenticationProvider.superDigest</emphasis>)</para>\n\n              <para>By default this feature is <emphasis\n              role=\"bold\">disabled</emphasis></para>\n\n              <para><emphasis role=\"bold\">New in 3.2:</emphasis>\n              Enables a ZooKeeper ensemble administrator to access the\n              znode hierarchy as a \"super\" user. In particular no ACL\n              checking occurs for a user authenticated as\n              super.</para>\n\n              <para>org.apache.zookeeper.server.auth.DigestAuthenticationProvider\n              can be used to generate the superDigest, call it with\n              one parameter of \"super:&lt;password>\". Provide the\n              generated \"super:&lt;data>\" as the system property value\n              when starting each server of the ensemble.</para>\n\n              <para>When authenticating to a ZooKeeper server (from a\n              ZooKeeper client) pass a scheme of \"digest\" and authdata\n              of \"super:&lt;password>\". Note that digest auth passes\n              the authdata in plaintext to the server, it would be\n              prudent to use this authentication method only on\n              localhost (not over the network) or over an encrypted\n              connection.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>isro</term>\n\n            <listitem>\n              <para><emphasis role=\"bold\">New in 3.4.0:</emphasis> Tests if\n              server is running in read-only mode.  The server will respond with\n              \"ro\" if in read-only mode or \"rw\" if not in read-only mode.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>gtmk</term>\n\n            <listitem>\n              <para>Gets the current trace mask as a 64-bit signed long value in\n              decimal format.  See <command>stmk</command> for an explanation of\n              the possible values.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>stmk</term>\n\n            <listitem>\n              <para>Sets the current trace mask.  The trace mask is 64 bits,\n              where each bit enables or disables a specific category of trace\n              logging on the server.  Log4J must be configured to enable\n              <command>TRACE</command> level first in order to see trace logging\n              messages.  The bits of the trace mask correspond to the following\n              trace logging categories.</para>\n\n              <table>\n                <title>Trace Mask Bit Values</title>\n                <tgroup cols=\"2\" align=\"left\" colsep=\"1\" rowsep=\"1\">\n                  <tbody>\n                    <row>\n                      <entry>0b0000000000</entry>\n                      <entry>Unused, reserved for future use.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0000000010</entry>\n                      <entry>Logs client requests, excluding ping\n                      requests.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0000000100</entry>\n                      <entry>Unused, reserved for future use.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0000001000</entry>\n                      <entry>Logs client ping requests.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0000010000</entry>\n                      <entry>Logs packets received from the quorum peer that is\n                      the current leader, excluding ping requests.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0000100000</entry>\n                      <entry>Logs addition, removal and validation of client\n                      sessions.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0001000000</entry>\n                      <entry>Logs delivery of watch events to client\n                      sessions.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0010000000</entry>\n                      <entry>Logs ping packets received from the quorum peer\n                      that is the current leader.</entry>\n                    </row>\n                    <row>\n                      <entry>0b0100000000</entry>\n                      <entry>Unused, reserved for future use.</entry>\n                    </row>\n                    <row>\n                      <entry>0b1000000000</entry>\n                      <entry>Unused, reserved for future use.</entry>\n                    </row>\n                  </tbody>\n                </tgroup>\n              </table>\n\n              <para>All remaining bits in the 64-bit value are unused and\n              reserved for future use.  Multiple trace logging categories are\n              specified by calculating the bitwise OR of the documented values.\n              The default trace mask is 0b0100110010.  Thus, by default, trace\n              logging includes client requests, packets received from the\n              leader and sessions.</para>\n\n              <para>To set a different trace mask, send a request containing the\n              <command>stmk</command> four-letter word followed by the trace\n              mask represented as a 64-bit signed long value.  This example uses\n              the Perl <command>pack</command> function to construct a trace\n              mask that enables all trace logging categories described above and\n              convert it to a 64-bit signed long value with big-endian byte\n              order.  The result is appended to <command>stmk</command> and sent\n              to the server using netcat.  The server responds with the new\n              trace mask in decimal format.</para>\n\n              <programlisting>$ perl -e \"print 'stmk', pack('q>', 0b0011111010)\" | nc localhost 2181\n250\n              </programlisting>\n            </listitem>\n          </varlistentry>\n        </variablelist>\n      </section>\n\n      <section>\n        <title>Experimental Options/Features</title>\n\n        <para>New features that are currently considered experimental.</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>Read Only Mode Server</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">readonlymode.enabled</emphasis>)</para>\n\n              <para><emphasis role=\"bold\">New in 3.4.0:</emphasis>\n              Setting this value to true enables Read Only Mode server\n              support (disabled by default). ROM allows clients\n              sessions which requested ROM support to connect to the\n              server even when the server might be partitioned from\n              the quorum. In this mode ROM clients can still read\n              values from the ZK service, but will be unable to write\n              values and see changes from other clients. See\n              ZOOKEEPER-784 for more details.\n              </para>\n            </listitem>\n          </varlistentry>\n\n        </variablelist>\n      </section>\n\n      <section>\n        <title>Unsafe Options</title>\n\n        <para>The following options can be useful, but be careful when you use\n        them. The risk of each is explained along with the explanation of what\n        the variable does.</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>forceSync</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.forceSync</emphasis>)</para>\n\n              <para>Requires updates to be synced to media of the transaction\n              log before finishing processing the update. If this option is\n              set to no, ZooKeeper will not require updates to be synced to\n              the media.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>jute.maxbuffer:</term>\n\n            <listitem>\n              <para>(Java system property:<emphasis role=\"bold\">\n              jute.maxbuffer</emphasis>)</para>\n\n              <para>This option can only be set as a Java system property.\n              There is no zookeeper prefix on it. It specifies the maximum\n              size of the data that can be stored in a znode. The default is\n              0xfffff, or just under 1M. If this option is changed, the system\n              property must be set on all servers and clients otherwise\n              problems will arise. This is really a sanity check. ZooKeeper is\n              designed to store data on the order of kilobytes in size.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>skipACL</term>\n\n            <listitem>\n              <para>(Java system property: <emphasis\n              role=\"bold\">zookeeper.skipACL</emphasis>)</para>\n\n              <para>Skips ACL checks. This results in a boost in throughput,\n              but opens up full access to the data tree to everyone.</para>\n            </listitem>\n          </varlistentry>\n\n          <varlistentry>\n            <term>quorumListenOnAllIPs</term>\n\n            <listitem>\n              <para>When set to true the ZooKeeper server will listen  \n              for connections from its peers on all available IP addresses,\n              and not only the address configured in the server list of the\n              configuration file. It affects the connections handling the \n              ZAB protocol and the Fast Leader Election protocol. Default\n              value is <emphasis role=\"bold\">false</emphasis>.</para>\n            </listitem>\n          </varlistentry>\n\n        </variablelist>\n      </section>\n\n      <section>\n        <title>Communication using the Netty framework</title>\n\n        <para><emphasis role=\"bold\">New in\n            3.4:</emphasis> <ulink url=\"http://jboss.org/netty\">Netty</ulink>\n            is an NIO based client/server communication framework, it\n            simplifies (over NIO being used directly) many of the\n            complexities of network level communication for java\n            applications. Additionally the Netty framework has built\n            in support for encryption (SSL) and authentication\n            (certificates). These are optional features and can be\n            turned on or off individually.\n        </para>\n        <para>Prior to version 3.4 ZooKeeper has always used NIO\n            directly, however in versions 3.4 and later Netty is\n            supported as an option to NIO (replaces). NIO continues to\n            be the default, however Netty based communication can be\n            used in place of NIO by setting the environment variable\n            \"zookeeper.serverCnxnFactory\" to\n            \"org.apache.zookeeper.server.NettyServerCnxnFactory\". You\n            have the option of setting this on either the client(s) or\n            server(s), typically you would want to set this on both,\n            however that is at your discretion.\n        </para>\n        <para>\n          TBD - tuning options for netty - currently there are none that are netty specific but we should add some. Esp around max bound on the number of reader worker threads netty creates.\n        </para>\n        <para>\n          TBD - how to manage encryption\n        </para>\n        <para>\n          TBD - how to manage certificates\n        </para>\n\n      </section>\n\n    </section>\n\n    <section id=\"sc_zkCommands\">\n      <title>ZooKeeper Commands: The Four Letter Words</title>\n\n      <para>ZooKeeper responds to a small set of commands. Each command is\n      composed of four letters. You issue the commands to ZooKeeper via telnet\n      or nc, at the client port.</para>\n\n      <para>Three of the more interesting commands: \"stat\" gives some\n      general information about the server and connected clients,\n      while \"srvr\" and \"cons\" give extended details on server and\n      connections respectively.</para>\n\n      <variablelist>\n        <varlistentry>\n          <term>conf</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Print\n            details about serving configuration.</para>\n          </listitem>\n\n        </varlistentry>\n\n        <varlistentry>\n          <term>cons</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> List\n            full connection/session details for all clients connected\n            to this server. Includes information on numbers of packets\n            received/sent, session id, operation latencies, last\n            operation performed, etc...</para>\n          </listitem>\n\n        </varlistentry>\n\n        <varlistentry>\n          <term>crst</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Reset\n            connection/session statistics for all connections.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>dump</term>\n\n          <listitem>\n            <para>Lists the outstanding sessions and ephemeral nodes. This\n            only works on the leader.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>envi</term>\n\n          <listitem>\n            <para>Print details about serving environment</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>ruok</term>\n\n          <listitem>\n            <para>Tests if server is running in a non-error state. The server\n            will respond with imok if it is running. Otherwise it will not\n            respond at all.</para>\n\n            <para>A response of \"imok\" does not necessarily indicate that the\n            server has joined the quorum, just that the server process is active\n            and bound to the specified client port. Use \"stat\" for details on\n            state wrt quorum and client connection information.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>srst</term>\n\n          <listitem>\n            <para>Reset server statistics.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>srvr</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Lists\n            full details for the server.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>stat</term>\n\n          <listitem>\n            <para>Lists brief details for the server and connected\n            clients.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>wchs</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Lists\n            brief information on watches for the server.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>wchc</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Lists\n            detailed information on watches for the server, by\n            session.  This outputs a list of sessions(connections)\n            with associated watches (paths). Note, depending on the\n            number of watches this operation may be expensive (ie\n            impact server performance), use it carefully.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>wchp</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.3.0:</emphasis> Lists\n            detailed information on watches for the server, by path.\n            This outputs a list of paths (znodes) with associated\n            sessions. Note, depending on the number of watches this\n            operation may be expensive (ie impact server performance),\n            use it carefully.</para>\n          </listitem>\n        </varlistentry>\n\n\n        <varlistentry>\n          <term>mntr</term>\n\n          <listitem>\n            <para><emphasis role=\"bold\">New in 3.4.0:</emphasis> Outputs a list \n            of variables that could be used for monitoring the health of the cluster.</para>\n\n            <programlisting>$ echo mntr | nc localhost 2185\n\nzk_version  3.4.0\nzk_avg_latency  0\nzk_max_latency  0\nzk_min_latency  0\nzk_packets_received 70\nzk_packets_sent 69\nzk_outstanding_requests 0\nzk_server_state leader\nzk_znode_count   4\nzk_watch_count  0\nzk_ephemerals_count 0\nzk_approximate_data_size    27\nzk_followers    4                   - only exposed by the Leader\nzk_synced_followers 4               - only exposed by the Leader\nzk_pending_syncs    0               - only exposed by the Leader\nzk_open_file_descriptor_count 23    - only available on Unix platforms\nzk_max_file_descriptor_count 1024   - only available on Unix platforms\n</programlisting>\n\n          <para>The output is compatible with java properties format and the content \n        may change over time (new keys added). Your scripts should expect changes.</para>\n\n          <para>ATTENTION: Some of the keys are platform specific and some of the keys are only exported by the Leader. </para>\n\n          <para>The output contains multiple lines with the following format:</para>\n          <programlisting>key \\t value</programlisting>\n          </listitem>\n        </varlistentry>\n      </variablelist>\n\n      <para>Here's an example of the <emphasis role=\"bold\">ruok</emphasis>\n      command:</para>\n\n      <programlisting>$ echo ruok | nc 127.0.0.1 5111\nimok\n</programlisting>\n\n    \n    </section>\n\n    <section id=\"sc_dataFileManagement\">\n      <title>Data File Management</title>\n\n      <para>ZooKeeper stores its data in a data directory and its transaction\n      log in a transaction log directory. By default these two directories are\n      the same. The server can (and should) be configured to store the\n      transaction log files in a separate directory than the data files.\n      Throughput increases and latency decreases when transaction logs reside\n      on a dedicated log devices.</para>\n\n      <section>\n        <title>The Data Directory</title>\n\n        <para>This directory has two files in it:</para>\n\n        <itemizedlist>\n          <listitem>\n            <para><filename>myid</filename> - contains a single integer in\n            human readable ASCII text that represents the server id.</para>\n          </listitem>\n\n          <listitem>\n            <para><filename>snapshot.&lt;zxid&gt;</filename> - holds the fuzzy\n            snapshot of a data tree.</para>\n          </listitem>\n        </itemizedlist>\n\n        <para>Each ZooKeeper server has a unique id. This id is used in two\n        places: the <filename>myid</filename> file and the configuration file.\n        The <filename>myid</filename> file identifies the server that\n        corresponds to the given data directory. The configuration file lists\n        the contact information for each server identified by its server id.\n        When a ZooKeeper server instance starts, it reads its id from the\n        <filename>myid</filename> file and then, using that id, reads from the\n        configuration file, looking up the port on which it should\n        listen.</para>\n\n        <para>The <filename>snapshot</filename> files stored in the data\n        directory are fuzzy snapshots in the sense that during the time the\n        ZooKeeper server is taking the snapshot, updates are occurring to the\n        data tree. The suffix of the <filename>snapshot</filename> file names\n        is the <emphasis>zxid</emphasis>, the ZooKeeper transaction id, of the\n        last committed transaction at the start of the snapshot. Thus, the\n        snapshot includes a subset of the updates to the data tree that\n        occurred while the snapshot was in process. The snapshot, then, may\n        not correspond to any data tree that actually existed, and for this\n        reason we refer to it as a fuzzy snapshot. Still, ZooKeeper can\n        recover using this snapshot because it takes advantage of the\n        idempotent nature of its updates. By replaying the transaction log\n        against fuzzy snapshots ZooKeeper gets the state of the system at the\n        end of the log.</para>\n      </section>\n\n      <section>\n        <title>The Log Directory</title>\n\n        <para>The Log Directory contains the ZooKeeper transaction logs.\n        Before any update takes place, ZooKeeper ensures that the transaction\n        that represents the update is written to non-volatile storage. A new\n        log file is started when the number of transactions written to the\n        current log file reaches a (variable) threshold. The threshold is\n        computed using the same parameter which influences the frequency of\n        snapshotting (see snapCount above). The log file's suffix is the first\n        zxid written to that log.</para>\n      </section>\n\n      <section id=\"sc_filemanagement\">\n        <title>File Management</title>\n\n        <para>The format of snapshot and log files does not change between\n        standalone ZooKeeper servers and different configurations of\n        replicated ZooKeeper servers. Therefore, you can pull these files from\n        a running replicated ZooKeeper server to a development machine with a\n        stand-alone ZooKeeper server for trouble shooting.</para>\n\n        <para>Using older log and snapshot files, you can look at the previous\n        state of ZooKeeper servers and even restore that state. The\n        LogFormatter class allows an administrator to look at the transactions\n        in a log.</para>\n\n        <para>The ZooKeeper server creates snapshot and log files, but\n        never deletes them. The retention policy of the data and log\n        files is implemented outside of the ZooKeeper server. The\n        server itself only needs the latest complete fuzzy snapshot, all log\n        files following it, and the last log file preceding it.  The latter\n        requirement is necessary to include updates which happened after this\n        snapshot was started but went into the existing log file at that time.\n        This is possible because snapshotting and rolling over of logs\n        proceed somewhat independently in ZooKeeper. See the\n        <ulink url=\"#sc_maintenance\">maintenance</ulink> section in\n        this document for more details on setting a retention policy\n        and maintenance of ZooKeeper storage.\n        </para>\n        <note>\n        <para>The data stored in these files is not encrypted. In the case of\n        storing sensitive data in ZooKeeper, necessary measures need to be\n        taken to prevent unauthorized access. Such measures are external to\n        ZooKeeper (e.g., control access to the files) and depend on the\n        individual settings in which it is being deployed. </para>\n        </note>\n      </section>\n    </section>\n\n    <section id=\"sc_commonProblems\">\n      <title>Things to Avoid</title>\n\n      <para>Here are some common problems you can avoid by configuring\n      ZooKeeper correctly:</para>\n\n      <variablelist>\n        <varlistentry>\n          <term>inconsistent lists of servers</term>\n\n          <listitem>\n            <para>The list of ZooKeeper servers used by the clients must match\n            the list of ZooKeeper servers that each ZooKeeper server has.\n            Things work okay if the client list is a subset of the real list,\n            but things will really act strange if clients have a list of\n            ZooKeeper servers that are in different ZooKeeper clusters. Also,\n            the server lists in each Zookeeper server configuration file\n            should be consistent with one another.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>incorrect placement of transaction log</term>\n\n          <listitem>\n            <para>The most performance critical part of ZooKeeper is the\n            transaction log. ZooKeeper syncs transactions to media before it\n            returns a response. A dedicated transaction log device is key to\n            consistent good performance. Putting the log on a busy device will\n            adversely effect performance. If you only have one storage device,\n            put trace files on NFS and increase the snapshotCount; it doesn't\n            eliminate the problem, but it should mitigate it.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>incorrect Java heap size</term>\n\n          <listitem>\n            <para>You should take special care to set your Java max heap size\n            correctly. In particular, you should not create a situation in\n            which ZooKeeper swaps to disk. The disk is death to ZooKeeper.\n            Everything is ordered, so if processing one request swaps the\n            disk, all other queued requests will probably do the same. the\n            disk. DON'T SWAP.</para>\n\n            <para>Be conservative in your estimates: if you have 4G of RAM, do\n            not set the Java max heap size to 6G or even 4G. For example, it\n            is more likely you would use a 3G heap for a 4G machine, as the\n            operating system and the cache also need memory. The best and only\n            recommend practice for estimating the heap size your system needs\n            is to run load tests, and then make sure you are well below the\n            usage limit that would cause the system to swap.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>Publicly accessible deployment</term>\n          <listitem>\n            <para>\n              A ZooKeeper ensemble is expected to operate in a trusted computing environment.\n              It is thus recommended to deploy ZooKeeper behind a firewall.\n            </para>\n          </listitem>\n        </varlistentry>\n      </variablelist>\n    </section>\n\n    <section id=\"sc_bestPractices\">\n      <title>Best Practices</title>\n\n      <para>For best results, take note of the following list of good\n      Zookeeper practices:</para>\n\n\n      <para>For multi-tennant installations see the <ulink\n      url=\"zookeeperProgrammers.html#ch_zkSessions\">section</ulink>\n      detailing ZooKeeper \"chroot\" support, this can be very useful\n      when deploying many applications/services interfacing to a\n      single ZooKeeper cluster.</para>\n\n    </section>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"zk_HierarchicalQuorums\">\n  <title>Introduction to hierarchical quorums</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This document contains information about hierarchical quorums.</para>\n    </abstract>\n  </articleinfo>\n\n    <para>\n    This document gives an example of how to use hierarchical quorums. The basic idea is\n    very simple. First, we split servers into groups, and add a line for each group listing\n    the servers that form this group. Next we have to assign a weight to each server.  \n    </para>\n    \n    <para>\n    The following example shows how to configure a system with three groups of three servers\n    each, and we assign a weight of 1 to each server:\n    </para>\n    \n    <programlisting>\n    group.1=1:2:3\n    group.2=4:5:6\n    group.3=7:8:9\n   \n    weight.1=1\n    weight.2=1\n    weight.3=1\n    weight.4=1\n    weight.5=1\n    weight.6=1\n    weight.7=1\n    weight.8=1\n    weight.9=1\n \t</programlisting>\n\n\t<para>    \n    When running the system, we are able to form a quorum once we have a majority of votes from\n    a majority of non-zero-weight groups. Groups that have zero weight are discarded and not\n    considered when forming quorums. Looking at the example, we are able to form a quorum once\n    we have votes from at least two servers from each of two different groups.\n    </para> \n </article>"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperInternals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"ar_ZooKeeperInternals\">\n  <title>ZooKeeper Internals</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This article contains topics which discuss the inner workings of\n       ZooKeeper. So far, that's logging and atomic broadcast. </para>\n\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_Introduction\">\n    <title>Introduction</title>\n\n    <para>This document contains information on the inner workings of ZooKeeper. \n    So far, it discusses these topics:\n    </para>\n\n<itemizedlist>    \n<listitem><para><xref linkend=\"sc_atomicBroadcast\"/></para></listitem>\n<listitem><para><xref linkend=\"sc_logging\"/></para></listitem>\n</itemizedlist>\n\n</section>\n\n<section id=\"sc_atomicBroadcast\">\n<title>Atomic Broadcast</title>\n\n<para>\nAt the heart of ZooKeeper is an atomic messaging system that keeps all of the servers in sync.</para>\n\n<section id=\"sc_guaranteesPropertiesDefinitions\"><title>Guarantees, Properties, and Definitions</title>\n<para>\nThe specific guarantees provided by the messaging system used by ZooKeeper are the following:</para>\n\n<variablelist>\n\n<varlistentry><term><emphasis >Reliable delivery</emphasis></term>\n<listitem><para>If a message, m, is delivered \nby one server, it will be eventually delivered by all servers.</para></listitem></varlistentry>\n\n<varlistentry><term><emphasis >Total order</emphasis></term>\n<listitem><para> If a message is \ndelivered before message b by one server, a will be delivered before b by all \nservers. If a and b are delivered messages, either a will be delivered before b \nor b will be delivered before a.</para></listitem></varlistentry>\n\n<varlistentry><term><emphasis >Causal order</emphasis> </term>\n\n<listitem><para>\nIf a message b is sent after a message a has been delivered by the sender of b, \na must be ordered before b. If a sender sends c after sending b, c must be ordered after b.\n</para></listitem></varlistentry>\n\n</variablelist>\n\n\n<para>\nThe ZooKeeper messaging system also needs to be efficient, reliable, and easy to \nimplement and maintain. We make heavy use of messaging, so we need the system to \nbe able to handle thousands of requests per second. Although we can require at \nleast k+1 correct servers to send new messages, we must be able to recover from \ncorrelated failures such as power outages. When we implemented the system we had \nlittle time and few engineering resources, so we needed a protocol that is \naccessible to engineers and is easy to implement. We found that our protocol \nsatisfied all of these goals.\n\n</para>\n\n<para>\nOur protocol assumes that we can construct point-to-point FIFO channels between \nthe servers. While similar services usually assume message delivery that can \nlose or reorder messages, our assumption of FIFO channels is very practical \ngiven that we use TCP for communication. Specifically we rely on the following property of TCP:</para>\n\n<variablelist>\n\n<varlistentry>\n<term><emphasis >Ordered delivery</emphasis></term>\n<listitem><para>Data is delivered in the same order it is sent and a message m is \ndelivered only after all messages sent before m have been delivered. \n(The corollary to this is that if message m is lost all messages after m will be lost.)</para></listitem></varlistentry>\n\n<varlistentry><term><emphasis >No message after close</emphasis></term>\n<listitem><para>Once a FIFO channel is closed, no messages will be received from it.</para></listitem></varlistentry>\n\n</variablelist>\n\n<para>\nFLP proved that consensus cannot be achieved in asynchronous distributed systems \nif failures are possible. To ensure we achieve consensus in the presence of failures \nwe use timeouts. However, we rely on times for liveness not for correctness. So, \nif timeouts stop working (clocks malfunction for example) the messaging system may \nhang, but it will not violate its guarantees.</para>\n\n<para>When describing the ZooKeeper messaging protocol we will talk of packets, \nproposals, and messages:</para>\n<variablelist>\n<varlistentry><term><emphasis >Packet</emphasis></term>\n<listitem><para>a sequence of bytes sent through a FIFO channel</para></listitem></varlistentry><varlistentry>\n\n<term><emphasis >Proposal</emphasis></term>\n<listitem><para>a unit of agreement. Proposals are agreed upon by exchanging packets \nwith a quorum of ZooKeeper servers. Most proposals contain messages, however the \nNEW_LEADER proposal is an example of a proposal that does not correspond to a message.</para></listitem>\n</varlistentry><varlistentry>\n\n<term><emphasis >Message</emphasis></term>\n<listitem><para>a sequence of bytes to be atomically broadcast to all ZooKeeper \nservers. A message put into a proposal and agreed upon before it is delivered.</para></listitem>\n</varlistentry>\n\n</variablelist>\n\n<para>\nAs stated above, ZooKeeper guarantees a total order of messages, and it also \nguarantees a total order of proposals. ZooKeeper exposes the total ordering using\na ZooKeeper transaction id (<emphasis>zxid</emphasis>). All proposals will be stamped with a zxid when \nit is proposed and exactly reflects the total ordering. Proposals are sent to all \nZooKeeper servers and committed when a quorum of them acknowledge the proposal. \nIf a proposal contains a message, the message will be delivered when the proposal \nis committed. Acknowledgement means the server has recorded the proposal to persistent storage. \nOur quorums have the requirement that any pair of quorum must have at least one server \nin common. We ensure this by requiring that all quorums have size (<emphasis>n/2+1</emphasis>) where \nn is the number of servers that make up a ZooKeeper service.\n</para>\n\n<para>\nThe zxid has two parts: the epoch and a counter. In our implementation the zxid \nis a 64-bit number. We use the high order 32-bits for the epoch and the low order \n32-bits for the counter. Because it has two parts represent the zxid both as a \nnumber and as a pair of integers, (<emphasis>epoch, count</emphasis>). The epoch number represents a \nchange in leadership. Each time a new leader comes into power it will have its \nown epoch number. We have a simple algorithm to assign a unique zxid to a proposal: \nthe leader simply increments the zxid to obtain a unique zxid for each proposal. \n<emphasis>Leadership activation will ensure that only one leader uses a given epoch, so our \nsimple algorithm guarantees that every proposal will have a unique id.</emphasis>\n</para>\n\n<para>\nZooKeeper messaging consists of two phases:</para>\n\n<variablelist>\n<varlistentry><term><emphasis >Leader activation</emphasis></term>\n<listitem><para>In this phase a leader establishes the correct state of the system \nand gets ready to start making proposals.</para></listitem>\n</varlistentry>\n\n<varlistentry><term><emphasis >Active messaging</emphasis></term>\n<listitem><para>In this phase a leader accepts messages to propose and coordinates message delivery.</para></listitem>\n</varlistentry>\n</variablelist>\n\n<para>\nZooKeeper is a holistic protocol. We do not focus on individual proposals, rather \nlook at the stream of proposals as a whole. Our strict ordering allows us to do this \nefficiently and greatly simplifies our protocol. Leadership activation embodies \nthis holistic concept. A leader becomes active only when a quorum of followers \n(The leader counts as a follower as well. You can always vote for yourself ) has synced \nup with the leader, they have the same state. This state consists of all of the \nproposals that the leader believes have been committed and the proposal to follow \nthe leader, the NEW_LEADER proposal. (Hopefully you are thinking to \nyourself, <emphasis>Does the set of proposals that the leader believes has been committed \nincluded all the proposals that really have been committed?</emphasis> The answer is <emphasis>yes</emphasis>. \nBelow, we make clear why.)\n</para>\n\n</section>\n\n<section id=\"sc_leaderElection\">\n\n<title>Leader Activation</title>\n<para>\nLeader activation includes leader election. We currently have two leader election \nalgorithms in ZooKeeper: LeaderElection and FastLeaderElection (AuthFastLeaderElection \nis a variant of FastLeaderElection that uses UDP and allows servers to perform a simple\nform of authentication to avoid IP spoofing). ZooKeeper messaging doesn't care about the \nexact method of electing a leader has long as the following holds:\n</para>\n\n<itemizedlist>\n\n<listitem><para>The leader has seen the highest zxid of all the followers.</para></listitem>\n<listitem><para>A quorum of servers have committed to following the leader.</para></listitem>\n\n</itemizedlist>\n\n<para>\nOf these two requirements only the first, the highest zxid amoung the followers \nneeds to hold for correct operation. The second requirement, a quorum of followers, \njust needs to hold with high probability. We are going to recheck the second requirement, \nso if a failure happens during or after the leader election and quorum is lost, \nwe will recover by abandoning leader activation and running another election.\n</para>\n\n<para>\nAfter leader election a single server will be designated as a leader and start \nwaiting for followers to connect. The rest of the servers will try to connect to \nthe leader. The leader will sync up with followers by sending any proposals they \nare missing, or if a follower is missing too many proposals, it will send a full \nsnapshot of the state to the follower.\n</para>\n\n<para>\nThere is a corner case in which a follower that has proposals, U, not seen \nby a leader arrives. Proposals are seen in order, so the proposals of U will have a zxids \nhigher than zxids seen by the leader. The follower must have arrived after the \nleader election, otherwise the follower would have been elected leader given that \nit has seen a higher zxid. Since committed proposals must be seen by a quorum of \nservers, and a quorum of servers that elected the leader did not see U, the proposals \nof you have not been committed, so they can be discarded. When the follower connects \nto the leader, the leader will tell the follower to discard U.\n</para>\n\n<para>\nA new leader establishes a zxid to start using for new proposals by getting the \nepoch, e, of the highest zxid it has seen and setting the next zxid to use to be \n(e+1, 0), fter the leader syncs with a follower, it will propose a NEW_LEADER \nproposal. Once the NEW_LEADER proposal has been committed, the leader will activate \nand start receiving and issuing proposals.\n</para>\n\n<para>\nIt all sounds complicated but here are the basic rules of operation during leader \nactivation:\n</para>\n\n<itemizedlist>\n<listitem><para>A follower will ACK the NEW_LEADER proposal after it has synced with the leader.</para></listitem>\n<listitem><para>A follower will only ACK a NEW_LEADER proposal with a given zxid from a single server.</para></listitem>\n<listitem><para>A new leader will COMMIT the NEW_LEADER proposal when a quorum of followers have ACKed it.</para></listitem>\n<listitem><para>A follower will commit any state it received from the leader when the NEW_LEADER proposal is COMMIT.</para></listitem>\n<listitem><para>A new leader will not accept new proposals until the NEW_LEADER proposal has been COMMITED.</para></listitem>\n</itemizedlist>\n\n<para>\nIf leader election terminates erroneously, we don't have a problem since the \nNEW_LEADER proposal will not be committed since the leader will not have quorum. \nWhen this happens, the leader and any remaining followers will timeout and go back \nto leader election.\n</para>\n\n</section>\n\n<section id=\"sc_activeMessaging\">\n<title>Active Messaging</title>\n<para>\nLeader Activation does all the heavy lifting. Once the leader is coronated he can \nstart blasting out proposals. As long as he remains the leader no other leader can \nemerge since no other leader will be able to get a quorum of followers. If a new \nleader does emerge, \nit means that the leader has lost quorum, and the new leader will clean up any \nmess left over during her leadership activation.\n</para>\n\n<para>ZooKeeper messaging operates similar to a classic two-phase commit.</para>\n\n<mediaobject id=\"fg_2phaseCommit\" >\n  <imageobject>\n    <imagedata fileref=\"images/2pc.jpg\"/>\n  </imageobject>\n</mediaobject>\n\n<para>\nAll communication channels are FIFO, so everything is done in order. Specifically \nthe following operating constraints are observed:</para>\n\n<itemizedlist>\n\n<listitem><para>The leader sends proposals to all followers using \nthe same order. Moreover, this order follows the order in which requests have been \nreceived. Because we use FIFO channels this means that followers also receive proposals in order.\n</para></listitem>\n\n<listitem><para>Followers process messages in the order they are received. This \nmeans that messages will be ACKed in order and the leader will receive ACKs from \nfollowers in order, due to the FIFO channels. It also means that if message $m$ \nhas been written to non-volatile storage, all messages that were proposed before \n$m$ have been written to non-volatile storage.</para></listitem>\n\n<listitem><para>The leader will issue a COMMIT to all followers as soon as a \nquorum of followers have ACKed a message. Since messages are ACKed in order, \nCOMMITs will be sent by the leader as received by the followers in order.</para></listitem>\n\n<listitem><para>COMMITs are processed in order. Followers deliver a proposals \nmessage when that proposal is committed.</para></listitem>\n\n</itemizedlist>\n\n</section>\n\n<section id=\"sc_summary\">\n<title>Summary</title>\n<para>So there you go. Why does it work? Specifically, why does is set of proposals \nbelieved by a new leader always contain any proposal that has actually been committed? \nFirst, all proposals have a unique zxid, so unlike other protocols, we never have \nto worry about two different values being proposed for the same zxid; followers \n(a leader is also a follower) see and record proposals in order; proposals are \ncommitted in order; there is only one active leader at a time since followers only \nfollow a single leader at a time; a new leader has seen all committed proposals \nfrom the previous epoch since it has seen the highest zxid from a quorum of servers; \nany uncommited proposals from a previous epoch seen by a new leader will be committed \nby that leader before it becomes active.</para></section>\n\n<section id=\"sc_comparisons\"><title>Comparisons</title>\n<para>\nIsn't this just Multi-Paxos? No, Multi-Paxos requires some way of assuring that \nthere is only a single coordinator. We do not count on such assurances. Instead \nwe use the leader activation to recover from leadership change or old leaders \nbelieving they are still active.\n</para>\n\n<para>\nIsn't this just Paxos? Your active messaging phase looks just like phase 2 of Paxos? \nActually, to us active messaging looks just like 2 phase commit without the need to \nhandle aborts. Active messaging is different from both in the sense that it has \ncross proposal ordering requirements. If we do not maintain strict FIFO ordering of \nall packets, it all falls apart. Also, our leader activation phase is different from \nboth of them. In particular, our use of epochs allows us to skip blocks of uncommitted\nproposals and to not worry about duplicate proposals for a given zxid.\n</para>\n\n</section>\n\n</section>\n\n<section id=\"sc_quorum\">\n<title>Quorums</title>\n\n<para>\nAtomic broadcast and leader election use the notion of quorum to guarantee a consistent\nview of the system. By default, ZooKeeper uses majority quorums, which means that every\nvoting that happens in one of these protocols requires a majority to vote on. One example is\nacknowledging a leader proposal: the leader can only commit once it receives an\nacknowledgement from a quorum of servers.\n</para>\n\n<para>\nIf we extract the properties that we really need from our use of majorities, we have that we only\nneed to guarantee that groups of processes used to validate an operation by voting (e.g., acknowledging\na leader proposal) pairwise intersect in at least one server. Using majorities guarantees such a property.\nHowever, there are other ways of constructing quorums different from majorities. For example, we can assign\nweights to the votes of servers, and say that the votes of some servers are more important. To obtain a quorum,\nwe get enough votes so that the sum of weights of all votes is larger than half of the total sum of all weights.    \n</para>\n\n<para>\nA different construction that uses weights and is useful in wide-area deployments (co-locations) is a hierarchical\none. With this construction, we split the servers into disjoint groups and assign weights to processes. To form \na quorum, we have to get a hold of enough servers from a majority of groups G, such that for each group g in G,\nthe sum of votes from g is larger than half of the sum of weights in g. Interestingly, this construction enables\nsmaller quorums. If we have, for example, 9 servers, we split them into 3 groups, and assign a weight of 1 to each\nserver, then we are able to form quorums of size 4. Note that two subsets of processes composed each of a majority\nof servers from each of a majority of groups necessarily have a non-empty intersection. It is reasonable to expect\nthat a majority of co-locations will have a majority of servers available with high probability. \n</para>  \n\n<para>\nWith ZooKeeper, we provide a user with the ability of configuring servers to use majority quorums, weights, or a \nhierarchy of groups.\n</para>\n</section>\n\n<section id=\"sc_logging\">\n\n<title>Logging</title>\n<para>\nZookeeper uses \n<ulink url=\"http://www.slf4j.org/index.html\">slf4j</ulink> as an abstraction layer for logging. \n<ulink url=\"http://logging.apache.org/log4j\">log4j</ulink> in version 1.2 is chosen as the final logging implementation for now.\nFor better embedding support, it is planned in the future to leave the decision of choosing the final logging implementation to the end user.\nTherefore, always use the slf4j api to write log statements in the code, but configure log4j for how to log at runtime.\nNote that slf4j has no FATAL level, former messages at FATAL level have been moved to ERROR level. \nFor information on configuring log4j for\nZooKeeper, see the <ulink url=\"zookeeperAdmin.html#sc_logging\">Logging</ulink> section \nof the <ulink url=\"zookeeperAdmin.html\">ZooKeeper Administrator's Guide.</ulink>\n\n</para>\n\n<section id=\"sc_developerGuidelines\"><title>Developer Guidelines</title>\n\n<para>Please follow the  \n<ulink url=\"http://www.slf4j.org/manual.html\">slf4j manual</ulink> when creating log statements within code.\nAlso read the\n<ulink url=\"http://www.slf4j.org/faq.html#logging_performance\">FAQ on performance</ulink>\n, when creating log statements. Patch reviewers will look for the following:</para>\n<section id=\"sc_rightLevel\"><title>Logging at the Right Level</title>\n<para>\nThere are several levels of logging in slf4j. \nIt's important to pick the right one. In order of higher to lower severity:</para>\n<orderedlist>\n   <listitem><para>ERROR level designates error events that might still allow the application to continue running.</para></listitem>\n   <listitem><para>WARN level designates potentially harmful situations.</para></listitem>\n   <listitem><para>INFO level designates informational messages that highlight the progress of the application at coarse-grained level.</para></listitem>\n   <listitem><para>DEBUG Level designates fine-grained informational events that are most useful to debug an application.</para></listitem>\n   <listitem><para>TRACE Level designates finer-grained informational events than the DEBUG.</para></listitem>\n</orderedlist>\n\n<para>\nZooKeeper is typically run in production such that log messages of INFO level \nseverity and higher (more severe) are output to the log.</para>\n\n\n</section>\n\n<section id=\"sc_slf4jIdioms\"><title>Use of Standard slf4j Idioms</title>\n\n<para><emphasis>Static Message Logging</emphasis></para>\n<programlisting>\nLOG.debug(\"process completed successfully!\");\n</programlisting>\n\n<para>\nHowever when creating parameterized messages are required, use formatting anchors.\n</para>\n\n<programlisting>\nLOG.debug(\"got {} messages in {} minutes\",new Object[]{count,time});    \n</programlisting>\n\n\n<para><emphasis>Naming</emphasis></para>\n\n<para>\nLoggers should be named after the class in which they are used.\n</para>\n\n<programlisting>\npublic class Foo {\n    private static final Logger LOG = LoggerFactory.getLogger(Foo.class);\n    ....\n    public Foo() {\n       LOG.info(\"constructing Foo\");\n</programlisting>\n\n<para><emphasis>Exception handling</emphasis></para>\n<programlisting>\ntry {\n  // code\n} catch (XYZException e) {\n  // do this\n  LOG.error(\"Something bad happened\", e);\n  // don't do this (generally)\n  // LOG.error(e);\n  // why? because \"don't do\" case hides the stack trace\n \n  // continue process here as you need... recover or (re)throw\n}\n</programlisting>\n</section>\n</section>\n\n</section>\n\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperJMX.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_zookeeperjmx\">\n  <title>ZooKeeper JMX</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>ZooKeeper support for JMX</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_jmx\">\n    <title>JMX</title>\n    <para>Apache ZooKeeper has extensive support for JMX, allowing you\n    to view and manage a ZooKeeper serving ensemble.</para>\n\n    <para>This document assumes that you have basic knowledge of\n    JMX. See <ulink\n    url=\"http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/\">\n    Sun JMX Technology</ulink> page to get started with JMX.\n    </para>\n\n    <para>See the <ulink\n    url=\"http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html\">\n    JMX Management Guide</ulink> for details on setting up local and\n    remote management of VM instances. By default the included\n    <emphasis>zkServer.sh</emphasis> supports only local management -\n    review the linked document to enable support for remote management\n    (beyond the scope of this document).\n    </para>\n\n  </section>\n\n  <section id=\"ch_starting\">\n    <title>Starting ZooKeeper with JMX enabled</title>\n\n    <para>The class\n      <emphasis>org.apache.zookeeper.server.quorum.QuorumPeerMain</emphasis>\n      will start a JMX manageable ZooKeeper server. This class\n      registers the proper MBeans during initalization to support JMX\n      monitoring and management of the\n      instance. See <emphasis>bin/zkServer.sh</emphasis> for one\n      example of starting ZooKeeper using QuorumPeerMain.</para>\n  </section>\n\n  <section id=\"ch_console\">\n    <title>Run a JMX console</title>\n\n    <para>There are a number of JMX consoles available which can connect\n      to the running server. For this example we will use Sun's\n      <emphasis>jconsole</emphasis>.</para>\n\n    <para>The Java JDK ships with a simple JMX console\n      named <ulink url=\"http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html\">jconsole</ulink>\n      which can be used to connect to ZooKeeper and inspect a running\n      server. Once you've started ZooKeeper using QuorumPeerMain\n      start <emphasis>jconsole</emphasis>, which typically resides in\n      <emphasis>JDK_HOME/bin/jconsole</emphasis></para>\n\n    <para>When the \"new connection\" window is displayed either connect\n      to local process (if jconsole started on same host as Server) or\n      use the remote process connection.</para>\n\n    <para>By default the \"overview\" tab for the VM is displayed (this\n      is a great way to get insight into the VM btw). Select\n      the \"MBeans\" tab.</para>\n\n    <para>You should now see <emphasis>org.apache.ZooKeeperService</emphasis>\n      on the left hand side. Expand this item and depending on how you've\n      started the server you will be able to monitor and manage various\n      service related features.</para>\n\n    <para>Also note that ZooKeeper will register log4j MBeans as\n    well. In the same section along the left hand side you will see\n    \"log4j\". Expand that to manage log4j through JMX. Of particular\n    interest is the ability to dynamically change the logging levels\n    used by editing the appender and root thresholds. Log4j MBean\n    registration can be disabled by passing\n    <emphasis>-Dzookeeper.jmx.log4j.disable=true</emphasis> to the JVM\n    when starting ZooKeeper.\n    </para>\n\n  </section>\n\n  <section id=\"ch_reference\">\n    <title>ZooKeeper MBean Reference</title>\n\n    <para>This table details JMX for a server participating in a\n    replicated ZooKeeper ensemble (ie not standalone). This is the\n    typical case for a production environment.</para>\n\n    <table>\n      <title>MBeans, their names and description</title>\n\n      <tgroup cols='4'>\n        <thead>\n          <row>\n            <entry>MBean</entry>\n            <entry>MBean Object Name</entry>\n            <entry>Description</entry>\n          </row>\n        </thead>\n        <tbody>\n          <row>\n            <entry>Quorum</entry>\n            <entry>ReplicatedServer_id&lt;#&gt;</entry>\n            <entry>Represents the Quorum, or Ensemble - parent of all\n            cluster members. Note that the object name includes the\n            \"myid\" of the server (name suffix) that your JMX agent has\n            connected to.</entry>\n          </row>\n          <row>\n            <entry>LocalPeer|RemotePeer</entry>\n            <entry>replica.&lt;#&gt;</entry>\n            <entry>Represents a local or remote peer (ie server\n            participating in the ensemble). Note that the object name\n            includes the \"myid\" of the server (name suffix).</entry>\n          </row>\n          <row>\n            <entry>LeaderElection</entry>\n            <entry>LeaderElection</entry>\n            <entry>Represents a ZooKeeper cluster leader election which is\n            in progress. Provides information about the election, such as\n            when it started.</entry>\n          </row>\n          <row>\n            <entry>Leader</entry>\n            <entry>Leader</entry>\n            <entry>Indicates that the parent replica is the leader and\n            provides attributes/operations for that server. Note that\n            Leader is a subclass of ZooKeeperServer, so it provides\n            all of the information normally associated with a\n            ZooKeeperServer node.</entry>\n          </row>\n          <row>\n            <entry>Follower</entry>\n            <entry>Follower</entry>\n            <entry>Indicates that the parent replica is a follower and\n            provides attributes/operations for that server. Note that\n            Follower is a subclass of ZooKeeperServer, so it provides\n            all of the information normally associated with a\n            ZooKeeperServer node.</entry>\n          </row>\n          <row>\n            <entry>DataTree</entry>\n            <entry>InMemoryDataTree</entry>\n            <entry>Statistics on the in memory znode database, also\n            operations to access finer (and more computationally\n            intensive) statistics on the data (such as ephemeral\n            count). InMemoryDataTrees are children of ZooKeeperServer\n            nodes.</entry>\n          </row>\n          <row>\n            <entry>ServerCnxn</entry>\n            <entry>&lt;session_id&gt;</entry>\n            <entry>Statistics on each client connection, also\n            operations on those connections (such as\n            termination). Note the object name is the session id of\n            the connection in hex form.</entry>\n          </row>\n    </tbody></tgroup></table>\n\n    <para>This table details JMX for a standalone server. Typically\n    standalone is only used in development situations.</para>\n\n    <table>\n      <title>MBeans, their names and description</title>\n\n      <tgroup cols='4'>\n        <thead>\n          <row>\n            <entry>MBean</entry>\n            <entry>MBean Object Name</entry>\n            <entry>Description</entry>\n          </row>\n        </thead>\n        <tbody>\n          <row>\n            <entry>ZooKeeperServer</entry>\n            <entry>StandaloneServer_port&lt;#&gt;</entry>\n            <entry>Statistics on the running server, also operations\n            to reset these attributes. Note that the object name\n            includes the client port of the server (name\n            suffix).</entry>\n          </row>\n          <row>\n            <entry>DataTree</entry>\n            <entry>InMemoryDataTree</entry>\n            <entry>Statistics on the in memory znode database, also\n            operations to access finer (and more computationally\n            intensive) statistics on the data (such as ephemeral\n            count).</entry>\n          </row>\n          <row>\n            <entry>ServerCnxn</entry>\n            <entry>&lt;session_id&gt;</entry>\n            <entry>Statistics on each client connection, also\n            operations on those connections (such as\n            termination). Note the object name is the session id of\n            the connection in hex form.</entry>\n          </row>\n    </tbody></tgroup></table>\n\n  </section>\n\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperObservers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_GettStartedGuide\">\n  <title>ZooKeeper Observers</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\"); you\n\tmay not use this file except in compliance with the License. You may\n\tobtain a copy of the License\n\tat <ulink url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n      \n      <para>Unless required by applicable law or agreed to in writing, software\n      distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n      WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n      License for the specific language governing permissions and limitations\n      under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains information about using non-voting servers, or\n      observers in your ZooKeeper ensembles.</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_Introduction\">\n    <title>Observers: Scaling ZooKeeper Without Hurting Write Performance\n      </title>\n    <para>\n      Although ZooKeeper performs very well by having clients connect directly\n      to voting members of the ensemble, this architecture makes it hard to\n      scale out to huge numbers of clients. The problem is that as we add more\n      voting members, the write performance drops. This is due to the fact that\n      a write operation requires the agreement of (in general) at least half the\n      nodes in an ensemble and therefore the cost of a vote can increase\n      significantly as more voters are added.\n    </para>\n    <para>\n      We have introduced a new type of ZooKeeper node called\n      an <emphasis>Observer</emphasis> which helps address this problem and\n      further improves ZooKeeper's scalability. Observers are non-voting members\n      of an ensemble which only hear the results of votes, not the agreement\n      protocol that leads up to them. Other than this simple distinction,\n      Observers function exactly the same as Followers - clients may connect to\n      them and send read and write requests to them. Observers forward these\n      requests to the Leader like Followers do, but they then simply wait to\n      hear the result of the vote. Because of this, we can increase the number\n      of Observers as much as we like without harming the performance of votes.\n    </para>\n    <para>\n      Observers have other advantages. Because they do not vote, they are not a\n      critical part of the ZooKeeper ensemble. Therefore they can fail, or be\n      disconnected from the cluster, without harming the availability of the\n      ZooKeeper service. The benefit to the user is that Observers may connect\n      over less reliable network links than Followers. In fact, Observers may be\n      used to talk to a ZooKeeper server from another data center. Clients of\n      the Observer will see fast reads, as all reads are served locally, and\n      writes result in minimal network traffic as the number of messages\n      required in the absence of the vote protocol is smaller.\n    </para>\n  </section>\n  <section id=\"sc_UsingObservers\">\n    <title>How to use Observers</title>\n    <para>Setting up a ZooKeeper ensemble that uses Observers is very simple,\n    and requires just two changes to your config files. Firstly, in the config\n    file of every node that is to be an Observer, you must place this line:\n    </para>\n    <programlisting>\n      peerType=observer\n    </programlisting>\n    \n    <para>\n      This line tells ZooKeeper that the server is to be an Observer. Secondly,\n      in every server config file, you must add :observer to the server\n      definition line of each Observer. For example:\n    </para>\n    \n    <programlisting>\n      server.1:localhost:2181:3181:observer\n    </programlisting>\n    \n    <para>\n      This tells every other server that server.1 is an Observer, and that they\n      should not expect it to vote. This is all the configuration you need to do\n      to add an Observer to your ZooKeeper cluster. Now you can connect to it as\n      though it were an ordinary Follower. Try it out, by running:</para>\n    <programlisting>\n      $ bin/zkCli.sh -server localhost:2181\n    </programlisting>\n    <para>\n      where localhost:2181 is the hostname and port number of the Observer as\n      specified in every config file. You should see a command line prompt\n      through which you can issue commands like <emphasis>ls</emphasis> to query\n      the ZooKeeper service.\n    </para>\n  </section>\n  \n  <section id=\"ch_UseCases\">\n    <title>Example use cases</title>\n    <para>\n      Two example use cases for Observers are listed below. In fact, wherever\n      you wish to scale the numbe of clients of your ZooKeeper ensemble, or\n      where you wish to insulate the critical part of an ensemble from the load\n      of dealing with client requests, Observers are a good architectural\n      choice.\n    </para>\n    <itemizedlist>\n      <listitem>\n\t<para> As a datacenter bridge: Forming a ZK ensemble between two\n\tdatacenters is a problematic endeavour as the high variance in latency\n\tbetween the datacenters could lead to false positive failure detection\n\tand partitioning. However if the ensemble runs entirely in one\n\tdatacenter, and the second datacenter runs only Observers, partitions\n\taren't problematic as the ensemble remains connected. Clients of the\n\tObservers may still see and issue proposals.</para>\n      </listitem>\n      <listitem>\n\t<para>As a link to a message bus: Some companies have expressed an\n\tinterest in using ZK as a component of a persistent reliable message\n\tbus. Observers would give a natural integration point for this work: a\n\tplug-in mechanism could be used to attach the stream of proposals an\n\tObserver sees to a publish-subscribe system, again without loading the\n\tcore ensemble.\n\t</para>\n      </listitem>\n    </itemizedlist>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperOtherInfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_OtherInfo\">\n  <title>ZooKeeper</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para> currently empty </para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_placeholder\">\n    <title>Other Info</title>\n    <para> currently empty </para>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperOver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_Overview\">\n  <title>ZooKeeper</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This document contains overview information about ZooKeeper. It\n      discusses design goals, key concepts, implementation, and\n      performance.</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_DesignOverview\">\n    <title>ZooKeeper: A Distributed Coordination Service for Distributed\n    Applications</title>\n\n    <para>ZooKeeper is a distributed, open-source coordination service for\n    distributed applications. It exposes a simple set of primitives that\n    distributed applications can build upon to implement higher level services\n    for synchronization, configuration maintenance, and groups and naming. It\n    is designed to be easy to program to, and uses a data model styled after\n    the familiar directory tree structure of file systems. It runs in Java and\n    has bindings for both Java and C.</para>\n\n    <para>Coordination services are notoriously hard to get right. They are\n    especially prone to errors such as race conditions and deadlock. The\n    motivation behind ZooKeeper is to relieve distributed applications the\n    responsibility of implementing coordination services from scratch.</para>\n\n    <section id=\"sc_designGoals\">\n      <title>Design Goals</title>\n\n      <para><emphasis role=\"bold\">ZooKeeper is simple.</emphasis> ZooKeeper\n      allows distributed processes to coordinate with each other through a\n      shared hierarchal namespace which is organized similarly to a standard\n      file system. The name space consists of data registers - called znodes,\n      in ZooKeeper parlance - and these are similar to files and directories.\n      Unlike a typical file system, which is designed for storage, ZooKeeper\n      data is kept in-memory, which means ZooKeeper can acheive high\n      throughput and low latency numbers.</para>\n\n      <para>The ZooKeeper implementation puts a premium on high performance,\n      highly available, strictly ordered access. The performance aspects of\n      ZooKeeper means it can be used in large, distributed systems. The\n      reliability aspects keep it from being a single point of failure. The\n      strict ordering means that sophisticated synchronization primitives can\n      be implemented at the client.</para>\n\n      <para><emphasis role=\"bold\">ZooKeeper is replicated.</emphasis> Like the\n      distributed processes it coordinates, ZooKeeper itself is intended to be\n      replicated over a sets of hosts called an ensemble.</para>\n\n      <figure>\n        <title>ZooKeeper Service</title>\n\n        <mediaobject>\n          <imageobject>\n            <imagedata fileref=\"images/zkservice.jpg\" />\n          </imageobject>\n        </mediaobject>\n      </figure>\n\n      <para>The servers that make up the ZooKeeper service must all know about\n      each other. They maintain an in-memory image of state, along with a\n      transaction logs and snapshots in a persistent store. As long as a\n      majority of the servers are available, the ZooKeeper service will be\n      available.</para>\n\n      <para>Clients connect to a single ZooKeeper server. The client maintains\n      a TCP connection through which it sends requests, gets responses, gets\n      watch events, and sends heart beats. If the TCP connection to the server\n      breaks, the client will connect to a different server.</para>\n\n      <para><emphasis role=\"bold\">ZooKeeper is ordered.</emphasis> ZooKeeper\n      stamps each update with a number that reflects the order of all\n      ZooKeeper transactions. Subsequent operations can use the order to\n      implement higher-level abstractions, such as synchronization\n      primitives.</para>\n\n      <para><emphasis role=\"bold\">ZooKeeper is fast.</emphasis> It is\n      especially fast in \"read-dominant\" workloads. ZooKeeper applications run\n      on thousands of machines, and it performs best where reads are more\n      common than writes, at ratios of around 10:1.</para>\n    </section>\n\n    <section id=\"sc_dataModelNameSpace\">\n      <title>Data model and the hierarchical namespace</title>\n\n      <para>The name space provided by ZooKeeper is much like that of a\n      standard file system. A name is a sequence of path elements separated by\n      a slash (/). Every node in ZooKeeper's name space is identified by a\n      path.</para>\n\n      <figure>\n        <title>ZooKeeper's Hierarchical Namespace</title>\n\n        <mediaobject>\n          <imageobject>\n            <imagedata fileref=\"images/zknamespace.jpg\" />\n          </imageobject>\n        </mediaobject>\n      </figure>\n    </section>\n\n    <section>\n      <title>Nodes and ephemeral nodes</title>\n\n      <para>Unlike is standard file systems, each node in a ZooKeeper\n      namespace can have data associated with it as well as children. It is\n      like having a file-system that allows a file to also be a directory.\n      (ZooKeeper was designed to store coordination data: status information,\n      configuration, location information, etc., so the data stored at each\n      node is usually small, in the byte to kilobyte range.) We use the term\n      <emphasis>znode</emphasis> to make it clear that we are talking about\n      ZooKeeper data nodes.</para>\n\n      <para>Znodes maintain a stat structure that includes version numbers for\n      data changes, ACL changes, and timestamps, to allow cache validations\n      and coordinated updates. Each time a znode's data changes, the version\n      number increases. For instance, whenever a client retrieves data it also\n      receives the version of the data.</para>\n\n      <para>The data stored at each znode in a namespace is read and written\n      atomically. Reads get all the data bytes associated with a znode and a\n      write replaces all the data. Each node has an Access Control List (ACL)\n      that restricts who can do what.</para>\n\n      <para>ZooKeeper also has the notion of ephemeral nodes. These znodes\n      exists as long as the session that created the znode is active. When the\n      session ends the znode is deleted. Ephemeral nodes are useful when you\n      want to implement <emphasis>[tbd]</emphasis>.</para>\n    </section>\n\n    <section>\n      <title>Conditional updates and watches</title>\n\n      <para>ZooKeeper supports the concept of <emphasis>watches</emphasis>.\n      Clients can set a watch on a znodes. A watch will be triggered and\n      removed when the znode changes. When a watch is triggered the client\n      receives a packet saying that the znode has changed. And if the\n      connection between the client and one of the Zoo Keeper servers is\n      broken, the client will receive a local notification. These can be used\n      to <emphasis>[tbd]</emphasis>.</para>\n    </section>\n\n    <section>\n      <title>Guarantees</title>\n\n      <para>ZooKeeper is very fast and very simple. Since its goal, though, is\n      to be a basis for the construction of more complicated services, such as\n      synchronization, it provides a set of guarantees. These are:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para>Sequential Consistency - Updates from a client will be applied\n          in the order that they were sent.</para>\n        </listitem>\n\n        <listitem>\n          <para>Atomicity - Updates either succeed or fail. No partial\n          results.</para>\n        </listitem>\n\n        <listitem>\n          <para>Single System Image - A client will see the same view of the\n          service regardless of the server that it connects to.</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>Reliability - Once an update has been applied, it will persist\n          from that time forward until a client overwrites the update.</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>Timeliness - The clients view of the system is guaranteed to\n          be up-to-date within a certain time bound.</para>\n        </listitem>\n      </itemizedlist>\n\n      <para>For more information on these, and how they can be used, see\n      <emphasis>[tbd]</emphasis></para>\n    </section>\n\n    <section>\n      <title>Simple API</title>\n\n      <para>One of the design goals of ZooKeeper is provide a very simple\n      programming interface. As a result, it supports only these\n      operations:</para>\n\n      <variablelist>\n        <varlistentry>\n          <term>create</term>\n\n          <listitem>\n            <para>creates a node at a location in the tree</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>delete</term>\n\n          <listitem>\n            <para>deletes a node</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>exists</term>\n\n          <listitem>\n            <para>tests if a node exists at a location</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>get data</term>\n\n          <listitem>\n            <para>reads the data from a node</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>set data</term>\n\n          <listitem>\n            <para>writes data to a node</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>get children</term>\n\n          <listitem>\n            <para>retrieves a list of children of a node</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term>sync</term>\n\n          <listitem>\n            <para>waits for data to be propagated</para>\n          </listitem>\n        </varlistentry>\n      </variablelist>\n\n      <para>For a more in-depth discussion on these, and how they can be used\n      to implement higher level operations, please refer to\n      <emphasis>[tbd]</emphasis></para>\n    </section>\n\n    <section>\n      <title>Implementation</title>\n\n      <para><xref linkend=\"fg_zkComponents\" /> shows the high-level components\n      of the ZooKeeper service. With the exception of the request processor,\n     each of\n      the servers that make up the ZooKeeper service replicates its own copy\n      of each of components.</para>\n\n      <figure id=\"fg_zkComponents\">\n        <title>ZooKeeper Components</title>\n\n        <mediaobject>\n          <imageobject>\n            <imagedata fileref=\"images/zkcomponents.jpg\" />\n          </imageobject>\n        </mediaobject>\n      </figure>\n\n      <para>The replicated database is an in-memory database containing the\n      entire data tree. Updates are logged to disk for recoverability, and\n      writes are serialized to disk before they are applied to the in-memory\n      database.</para>\n\n      <para>Every ZooKeeper server services clients. Clients connect to\n      exactly one server to submit irequests. Read requests are serviced from\n      the local replica of each server database. Requests that change the\n      state of the service, write requests, are processed by an agreement\n      protocol.</para>\n\n      <para>As part of the agreement protocol all write requests from clients\n      are forwarded to a single server, called the\n      <emphasis>leader</emphasis>. The rest of the ZooKeeper servers, called\n      <emphasis>followers</emphasis>, receive message proposals from the\n      leader and agree upon message delivery. The messaging layer takes care\n      of replacing leaders on failures and syncing followers with\n      leaders.</para>\n\n      <para>ZooKeeper uses a custom atomic messaging protocol. Since the\n      messaging layer is atomic, ZooKeeper can guarantee that the local\n      replicas never diverge. When the leader receives a write request, it\n      calculates what the state of the system is when the write is to be\n      applied and transforms this into a transaction that captures this new\n      state.</para>\n    </section>\n\n    <section>\n      <title>Uses</title>\n\n      <para>The programming interface to ZooKeeper is deliberately simple.\n      With it, however, you can implement higher order operations, such as\n      synchronizations primitives, group membership, ownership, etc. Some\n      distributed applications have used it to: <emphasis>[tbd: add uses from\n      white paper and video presentation.]</emphasis> For more information, see\n      <emphasis>[tbd]</emphasis></para>\n    </section>\n\n    <section>\n      <title>Performance</title>\n\n      <para>ZooKeeper is designed to be highly performant. But is it? The\n      results of the ZooKeeper's development team at Yahoo! Research indicate\n      that it is. (See <xref linkend=\"fg_zkPerfRW\" />.) It is especially high\n      performance in applications where reads outnumber writes, since writes\n      involve synchronizing the state of all servers. (Reads outnumbering\n      writes is typically the case for a coordination service.)</para>\n\n      <figure id=\"fg_zkPerfRW\">\n        <title>ZooKeeper Throughput as the Read-Write Ratio Varies</title>\n\n        <mediaobject>\n          <imageobject>\n            <imagedata fileref=\"images/zkperfRW-3.2.jpg\" />\n          </imageobject>\n        </mediaobject>\n      </figure>\n      <para>The figure <xref linkend=\"fg_zkPerfRW\"/> is a throughput\n      graph of ZooKeeper release 3.2 running on servers with dual 2Ghz\n      Xeon and two SATA 15K RPM drives.  One drive was used as a\n      dedicated ZooKeeper log device. The snapshots were written to\n      the OS drive. Write requests were 1K writes and the reads were\n      1K reads.  \"Servers\" indicate the size of the ZooKeeper\n      ensemble, the number of servers that make up the\n      service. Approximately 30 other servers were used to simulate\n      the clients. The ZooKeeper ensemble was configured such that\n      leaders do not allow connections from clients.</para>\n\n      <note><para>In version 3.2 r/w performance improved by ~2x\n      compared to the <ulink\n      url=\"http://zookeeper.apache.org/docs/r3.1.1/zookeeperOver.html#Performance\">previous\n      3.1 release</ulink>.</para></note>\n\n      <para>Benchmarks also indicate that it is reliable, too. <xref\n      linkend=\"fg_zkPerfReliability\" /> shows how a deployment responds to\n      various failures. The events marked in the figure are the\n      following:</para>\n\n      <orderedlist>\n        <listitem>\n          <para>Failure and recovery of a follower</para>\n        </listitem>\n\n        <listitem>\n          <para>Failure and recovery of a different follower</para>\n        </listitem>\n\n        <listitem>\n          <para>Failure of the leader</para>\n        </listitem>\n\n        <listitem>\n          <para>Failure and recovery of two followers</para>\n        </listitem>\n\n        <listitem>\n          <para>Failure of another leader</para>\n        </listitem>\n      </orderedlist>\n    </section>\n\n    <section>\n      <title>Reliability</title>\n\n      <para>To show the behavior of the system over time as\n        failures are injected we ran a ZooKeeper service made up of\n        7 machines. We ran the same saturation benchmark as before,\n        but this time we kept the write percentage at a constant\n        30%, which is a conservative ratio of our expected\n        workloads.\n      </para>\n      <figure id=\"fg_zkPerfReliability\">\n        <title>Reliability in the Presence of Errors</title>\n        <mediaobject>\n          <imageobject>\n            <imagedata fileref=\"images/zkperfreliability.jpg\" />\n          </imageobject>\n        </mediaobject>\n      </figure>\n\n      <para>The are a few important observations from this graph. First, if\n      followers fail and recover quickly, then ZooKeeper is able to sustain a\n      high throughput despite the failure. But maybe more importantly, the\n      leader election algorithm allows for the system to recover fast enough\n      to prevent throughput from dropping substantially. In our observations,\n      ZooKeeper takes less than 200ms to elect a new leader. Third, as\n      followers recover, ZooKeeper is able to raise throughput again once they\n      start processing requests.</para>\n    </section>\n\n    <section>\n      <title>The ZooKeeper Project</title>\n\n      <para>ZooKeeper has been\n          <ulink url=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/PoweredBy\">\n          successfully used\n        </ulink>\n        in many industrial applications.  It is used at Yahoo! as the\n        coordination and failure recovery service for Yahoo! Message\n        Broker, which is a highly scalable publish-subscribe system\n        managing thousands of topics for replication and data\n        delivery.  It is used by the Fetching Service for Yahoo!\n        crawler, where it also manages failure recovery. A number of\n        Yahoo! advertising systems also use ZooKeeper to implement\n        reliable services.\n      </para>\n\n      <para>All users and developers are encouraged to join the\n        community and contribute their expertise. See the\n        <ulink url=\"http://zookeeper.apache.org/\">\n          Zookeeper Project on Apache\n        </ulink>\n        for more information.\n      </para>\n    </section>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperProgrammers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_programmersGuide\">\n  <title>ZooKeeper Programmer's Guide</title>\n\n  <subtitle>Developing Distributed Applications that use ZooKeeper</subtitle>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about creating\n      distributed applications that use ZooKeeper. It discusses the basic\n      operations ZooKeeper supports, and how these can be used to build\n      higher-level abstractions. It contains solutions to common tasks, a\n      troubleshooting guide, and links to other information.</para>\n\n      <para>$Revision: 1.14 $ $Date: 2008/09/19 05:31:45 $</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"_introduction\">\n    <title>Introduction</title>\n\n    <para>This document is a guide for developers wishing to create\n    distributed applications that take advantage of ZooKeeper's coordination\n    services. It contains conceptual and practical information.</para>\n\n    <para>The first four sections of this guide present higher level\n    discussions of various ZooKeeper concepts. These are necessary both for an\n    understanding of how ZooKeeper works as well how to work with it. It does\n    not contain source code, but it does assume a familiarity with the\n    problems associated with distributed computing. The sections in this first\n    group are:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"ch_zkDataModel\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_zkSessions\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_zkWatches\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_zkGuarantees\" /></para>\n      </listitem>\n    </itemizedlist>\n\n    <para>The next four sections provide practical programming\n    information. These are:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"ch_guideToZkOperations\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_bindings\" /></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_programStructureWithExample\" />\n        <emphasis>[tbd]</emphasis></para>\n      </listitem>\n\n      <listitem>\n        <para><xref linkend=\"ch_gotchas\" /></para>\n      </listitem>\n    </itemizedlist>\n\n    <para>The book concludes with an <ulink\n    url=\"#apx_linksToOtherInfo\">appendix</ulink> containing links to other\n    useful, ZooKeeper-related information.</para>\n\n    <para>Most of information in this document is written to be accessible as\n    stand-alone reference material. However, before starting your first\n    ZooKeeper application, you should probably at least read the chaptes on\n    the <ulink url=\"#ch_zkDataModel\">ZooKeeper Data Model</ulink> and <ulink\n    url=\"#ch_guideToZkOperations\">ZooKeeper Basic Operations</ulink>. Also,\n    the <ulink url=\"#ch_programStructureWithExample\">Simple Programmming\n    Example</ulink> <emphasis>[tbd]</emphasis> is helpful for understanding the basic\n    structure of a ZooKeeper client application.</para>\n  </section>\n\n  <section id=\"ch_zkDataModel\">\n    <title>The ZooKeeper Data Model</title>\n\n    <para>ZooKeeper has a hierarchal name space, much like a distributed file\n    system. The only difference is that each node in the namespace can have\n    data associated with it as well as children. It is like having a file\n    system that allows a file to also be a directory. Paths to nodes are\n    always expressed as canonical, absolute, slash-separated paths; there are\n    no relative reference. Any unicode character can be used in a path subject\n    to the following constraints:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para>The null character (\\u0000) cannot be part of a path name. (This\n        causes problems with the C binding.)</para>\n      </listitem>\n\n      <listitem>\n        <para>The following characters can't be used because they don't\n        display well, or render in confusing ways: \\u0001 - \\u0019 and \\u007F\n        - \\u009F.</para>\n      </listitem>\n\n      <listitem>\n        <para>The following characters are not allowed: \\ud800 -uF8FFF,\n        \\uFFF0 - uFFFF.</para>\n      </listitem>\n\n      <listitem>\n        <para>The \".\" character can be used as part of another name, but \".\"\n        and \"..\" cannot alone be used to indicate a node along a path,\n        because ZooKeeper doesn't use relative paths. The following would be\n        invalid: \"/a/b/./c\" or \"/a/b/../c\".</para>\n      </listitem>\n\n      <listitem>\n        <para>The token \"zookeeper\" is reserved.</para>\n      </listitem>\n    </itemizedlist>\n\n    <section id=\"sc_zkDataModel_znodes\">\n      <title>ZNodes</title>\n\n      <para>Every node in a ZooKeeper tree is referred to as a\n      <emphasis>znode</emphasis>. Znodes maintain a stat structure that\n      includes version numbers for data changes, acl changes. The stat\n      structure also has timestamps. The version number, together with the\n      timestamp, allows ZooKeeper to validate the cache and to coordinate\n      updates. Each time a znode's data changes, the version number increases.\n      For instance, whenever a client retrieves data, it also receives the\n      version of the data. And when a client performs an update or a delete,\n      it must supply the version of the data of the znode it is changing. If\n      the version it supplies doesn't match the actual version of the data,\n      the update will fail. (This behavior can be overridden. For more\n      information see... )<emphasis>[tbd...]</emphasis></para>\n\n      <note>\n        <para>In distributed application engineering, the word\n        <emphasis>node</emphasis> can refer to a generic host machine, a\n        server, a member of an ensemble, a client process, etc. In the ZooKeeper\n        documentation, <emphasis>znodes</emphasis> refer to the data nodes.\n        <emphasis>Servers</emphasis>  refer to machines that make up the\n        ZooKeeper service; <emphasis>quorum peers</emphasis> refer to the\n        servers that make up an ensemble; client refers to any host or process\n        which uses a ZooKeeper service.</para>\n      </note>\n\n      <para> A znode is the main abstraction a programmer needs to be aware of. Znodes have\n      several characteristics that are worth mentioning here.</para>\n\n      <section id=\"sc_zkDataMode_watches\">\n        <title>Watches</title>\n\n        <para>Clients can set watches on znodes. Changes to that znode trigger\n        the watch and then clear the watch. When a watch triggers, ZooKeeper\n        sends the client a notification. More information about watches can be\n        found in the section \n\t    <ulink url=\"#ch_zkWatches\">ZooKeeper Watches</ulink>.</para>\n      </section>\n\n      <section>\n        <title>Data Access</title>\n\n        <para>The data stored at each znode in a namespace is read and written\n        atomically. Reads get all the data bytes associated with a znode and a\n        write replaces all the data. Each node has an Access Control List\n        (ACL) that restricts who can do what.</para>\n        \n        <para>ZooKeeper was not designed to be a general database or large\n        object store. Instead, it manages coordination data. This data can\n        come in the form of configuration, status information, rendezvous, etc.\n        A common property of the various forms of coordination data is that\n        they are relatively small: measured in kilobytes.\n        The ZooKeeper client and the server implementations have sanity checks\n        to ensure that znodes have less than 1M of data, but the data should\n        be much less than that on average. Operating on relatively large data\n        sizes will cause some operations to take much more time than others and\n        will affect the latencies of some operations because of the extra time\n        needed to move more data over the network and onto storage media. If\n        large data storage is needed, the usually pattern of dealing with such\n        data is to store it on a bulk storage system, such as NFS or HDFS, and\n        store pointers to the storage locations in ZooKeeper.</para> \n      </section>\n\n      <section>\n        <title>Ephemeral Nodes</title>\n\n        <para>ZooKeeper also has the notion of ephemeral nodes. These znodes\n        exists as long as the session that created the znode is active. When\n        the session ends the znode is deleted. Because of this behavior\n        ephemeral znodes are not allowed to have children.</para>\n      </section>\n\n      <section>\n        <title>Sequence Nodes -- Unique Naming</title>\n\n        <para>When creating a znode you can also request that\n        ZooKeeper append a monotonically increasing counter to the end\n        of path. This counter is unique to the parent znode. The\n        counter has a format of %010d -- that is 10 digits with 0\n        (zero) padding (the counter is formatted in this way to\n        simplify sorting), i.e. \"&lt;path&gt;0000000001\". See\n        <ulink url=\"recipes.html#sc_recipes_Queues\">Queue\n        Recipe</ulink> for an example use of this feature. Note: the\n        counter used to store the next sequence number is a signed int\n        (4bytes) maintained by the parent node, the counter will\n        overflow when incremented beyond 2147483647 (resulting in a\n        name \"&lt;path&gt;-2147483648\").</para>\n      </section>\n    </section>\n\n    <section id=\"sc_timeInZk\">\n      <title>Time in ZooKeeper</title>\n\n      <para>ZooKeeper tracks time multiple ways:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para><emphasis role=\"bold\">Zxid</emphasis></para>\n\n          <para>Every change to the ZooKeeper state receives a stamp in the\n          form of a <emphasis>zxid</emphasis> (ZooKeeper Transaction Id).\n          This exposes the total ordering of all changes to ZooKeeper. Each\n          change will have a unique zxid and if zxid1 is smaller than zxid2\n          then zxid1 happened before zxid2.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">Version numbers</emphasis></para>\n\n          <para>Every change to a node will cause an increase to one of the\n          version numbers of that node. The three version numbers are version\n          (number of changes to the data of a znode), cversion (number of\n          changes to the children of a znode), and aversion (number of changes\n          to the ACL of a znode).</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">Ticks</emphasis></para>\n\n          <para>When using multi-server ZooKeeper, servers use ticks to define\n          timing of events such as status uploads, session timeouts,\n          connection timeouts between peers, etc. The tick time is only\n          indirectly exposed through the minimum session timeout (2 times the\n          tick time); if a client requests a session timeout less than the\n          minimum session timeout, the server will tell the client that the\n          session timeout is actually the minimum session timeout.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">Real time</emphasis></para>\n\n          <para>ZooKeeper doesn't use real time, or clock time, at all except\n          to put timestamps into the stat structure on znode creation and\n          znode modification.</para>\n        </listitem>\n      </itemizedlist>\n    </section>\n\n    <section id=\"sc_zkStatStructure\">\n      <title>ZooKeeper Stat Structure</title>\n\n      <para>The Stat structure for each znode in ZooKeeper is made up of the\n      following fields:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para><emphasis role=\"bold\">czxid</emphasis></para>\n\n          <para>The zxid of the change that caused this znode to be\n          created.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">mzxid</emphasis></para>\n\n          <para>The zxid of the change that last modified this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">pzxid</emphasis></para>\n\n          <para>The zxid of the change that last modified children of this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">ctime</emphasis></para>\n\n          <para>The time in milliseconds from epoch when this znode was\n          created.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">mtime</emphasis></para>\n\n          <para>The time in milliseconds from epoch when this znode was last\n          modified.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">version</emphasis></para>\n\n          <para>The number of changes to the data of this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">cversion</emphasis></para>\n\n          <para>The number of changes to the children of this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">aversion</emphasis></para>\n\n          <para>The number of changes to the ACL of this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">ephemeralOwner</emphasis></para>\n\n          <para>The session id of the owner of this znode if the znode is an\n          ephemeral node. If it is not an ephemeral node, it will be\n          zero.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">dataLength</emphasis></para>\n\n          <para>The length of the data field of this znode.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis role=\"bold\">numChildren</emphasis></para>\n\n          <para>The number of children of this znode.</para>\n        </listitem>\n\n      </itemizedlist>\n    </section>\n  </section>\n\n  <section id=\"ch_zkSessions\">\n    <title>ZooKeeper Sessions</title>\n\n    <para>A ZooKeeper client establishes a session with the ZooKeeper\n    service by creating a handle to the service using a language\n    binding. Once created, the handle starts of in the CONNECTING state\n    and the client library tries to connect to one of the servers that\n    make up the ZooKeeper service at which point it switches to the\n    CONNECTED state. During normal operation will be in one of these\n    two states. If an unrecoverable error occurs, such as session\n    expiration or authentication failure, or if the application explicitly\n    closes the handle, the handle will move to the CLOSED state.\n    The following figure shows the possible state transitions of a\n    ZooKeeper client:</para>\n    \n    <mediaobject id=\"fg_states\" >\n  \t\t<imageobject>\n    \t\t<imagedata fileref=\"images/state_dia.jpg\"/>\n  \t\t</imageobject>\n\t</mediaobject>\n    \n    <para>To create a client session the application code must provide\n    a connection string containing a comma separated list of host:port pairs,\n    each corresponding to a ZooKeeper server (e.g. \"127.0.0.1:4545\" or\n    \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"). The ZooKeeper\n    client library will pick an arbitrary server and try to connect to\n    it. If this connection fails, or if the client becomes\n    disconnected from the server for any reason, the client will\n    automatically try the next server in the list, until a connection\n    is (re-)established.</para>\n\n    <para> <emphasis role=\"bold\">Added in 3.2.0</emphasis>: An\n    optional \"chroot\" suffix may also be appended to the connection\n    string. This will run the client commands while interpreting all\n    paths relative to this root (similar to the unix chroot\n    command). If used the example would look like:\n    \"127.0.0.1:4545/app/a\" or\n    \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\" where the\n    client would be rooted at \"/app/a\" and all paths would be relative\n    to this root - ie getting/setting/etc...  \"/foo/bar\" would result\n    in operations being run on \"/app/a/foo/bar\" (from the server\n    perspective). This feature is particularly useful in multi-tenant\n    environments where each user of a particular ZooKeeper service\n    could be rooted differently. This makes re-use much simpler as\n    each user can code his/her application as if it were rooted at\n    \"/\", while actual location (say /app/a) could be determined at\n    deployment time.</para>\n\n    <para>When a client gets a handle to the ZooKeeper service,\n    ZooKeeper creates a ZooKeeper session, represented as a 64-bit\n    number, that it assigns to the client. If the client connects to a\n    different ZooKeeper server, it will send the session id as a part\n    of the connection handshake.  As a security measure, the server\n    creates a password for the session id that any ZooKeeper server\n    can validate.The password is sent to the client with the session\n    id when the client establishes the session. The client sends this\n    password with the session id whenever it reestablishes the session\n    with a new server.</para>\n\n    <para>One of the parameters to the ZooKeeper client library call\n    to create a ZooKeeper session is the session timeout in\n    milliseconds. The client sends a requested timeout, the server\n    responds with the timeout that it can give the client. The current\n    implementation requires that the timeout be a minimum of 2 times\n    the tickTime (as set in the server configuration) and a maximum of\n    20 times the tickTime. The ZooKeeper client API allows access to\n    the negotiated timeout.</para>\n\n    <para>When a client (session) becomes partitioned from the ZK\n    serving cluster it will begin searching the list of servers that\n    were specified during session creation. Eventually, when\n    connectivity between the client and at least one of the servers is\n    re-established, the session will either again transition to the\n    \"connected\" state (if reconnected within the session timeout\n    value) or it will transition to the \"expired\" state (if\n    reconnected after the session timeout). It is not advisable to\n    create a new session object (a new ZooKeeper.class or zookeeper\n    handle in the c binding) for disconnection. The ZK client library\n    will handle reconnect for you. In particular we have heuristics\n    built into the client library to handle things like \"herd effect\",\n    etc... Only create a new session when you are notified of session\n    expiration (mandatory).</para>\n\n    <para>Session expiration is managed by the ZooKeeper cluster\n    itself, not by the client. When the ZK client establishes a\n    session with the cluster it provides a \"timeout\" value detailed\n    above. This value is used by the cluster to determine when the\n    client's session expires. Expirations happens when the cluster\n    does not hear from the client within the specified session timeout\n    period (i.e. no heartbeat). At session expiration the cluster will\n    delete any/all ephemeral nodes owned by that session and\n    immediately notify any/all connected clients of the change (anyone\n    watching those znodes). At this point the client of the expired\n    session is still disconnected from the cluster, it will not be\n    notified of the session expiration until/unless it is able to\n    re-establish a connection to the cluster. The client will stay in\n    disconnected state until the TCP connection is re-established with\n    the cluster, at which point the watcher of the expired session\n    will receive the \"session expired\" notification.</para>\n\n    <para>Example state transitions for an expired session as seen by\n    the expired session's watcher:</para>\n\n    <orderedlist>\n      <listitem><para>'connected' : session is established and client\n      is communicating with cluster (client/server communication is\n      operating properly)</para></listitem>\n      <listitem><para>.... client is partitioned from the\n      cluster</para></listitem>\n      <listitem><para>'disconnected' : client has lost connectivity\n      with the cluster</para></listitem>\n      <listitem><para>.... time elapses, after 'timeout' period the\n      cluster expires the session, nothing is seen by client as it is\n      disconnected from cluster</para></listitem>\n      <listitem><para>.... time elapses, the client regains network\n      level connectivity with the cluster</para></listitem>\n      <listitem><para>'expired' : eventually the client reconnects to\n      the cluster, it is then notified of the\n      expiration</para></listitem>\n    </orderedlist>\n\n    <para>Another parameter to the ZooKeeper session establishment\n    call is the default watcher. Watchers are notified when any state\n    change occurs in the client. For example if the client loses\n    connectivity to the server the client will be notified, or if the\n    client's session expires, etc... This watcher should consider the\n    initial state to be disconnected (i.e. before any state changes\n    events are sent to the watcher by the client lib). In the case of\n    a new connection, the first event sent to the watcher is typically\n    the session connection event.</para>\n\n    <para>The session is kept alive by requests sent by the client. If\n    the session is idle for a period of time that would timeout the\n    session, the client will send a PING request to keep the session\n    alive. This PING request not only allows the ZooKeeper server to\n    know that the client is still active, but it also allows the\n    client to verify that its connection to the ZooKeeper server is\n    still active. The timing of the PING is conservative enough to\n    ensure reasonable time to detect a dead connection and reconnect\n    to a new server.</para>\n\n    <para>\n      Once a connection to the server is successfully established\n      (connected) there are basically two cases where the client lib generates\n      connectionloss (the result code in c binding, exception in Java -- see \n      the API documentation for binding specific details) when either a synchronous or\n      asynchronous operation is performed and one of the following holds:\n    </para>\n\n    <orderedlist>\n      <listitem><para>The application calls an operation on a session that is no\n      longer alive/valid</para></listitem>\n      <listitem><para>The ZooKeeper client disconnects from a server when there\n      are pending operations to that server, i.e., there is a pending asynchronous call.\n      </para></listitem>\n    </orderedlist>\n\n    <para> <emphasis role=\"bold\">Added in 3.2.0 -- SessionMovedException</emphasis>. There is an internal\n      exception that is generally not seen by clients called the SessionMovedException.\n      This exception occurs because a request was received on a connection for a session\n      which has been reestablished on a different server. The normal cause of this error is\n      a client that sends a request to a server, but the network packet gets delayed, so\n      the client times out and connects to a new server. When the delayed packet arrives at\n      the first server, the old server detects that the session has moved, and closes the\n      client connection. Clients normally do not see this error since they do not read\n      from those old connections. (Old connections are usually closed.) One situation in which this\n      condition can be seen is when two clients try to reestablish the same connection using\n      a saved session id and password. One of the clients will reestablish the connection\n      and the second client will be disconnected (causing the pair to attempt to re-establish\n      its connection/session indefinitely).</para>\n\n  </section>\n\n  <section id=\"ch_zkWatches\">\n    <title>ZooKeeper Watches</title>\n\n    <para>All of the read operations in ZooKeeper - <emphasis\n    role=\"bold\">getData()</emphasis>, <emphasis\n    role=\"bold\">getChildren()</emphasis>, and <emphasis\n    role=\"bold\">exists()</emphasis> - have the option of setting a watch as a\n    side effect. Here is ZooKeeper's definition of a watch: a watch event is\n    one-time trigger, sent to the client that set the watch, which occurs when\n    the data for which the watch was set changes. There are three key points\n    to consider in this definition of a watch:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><emphasis role=\"bold\">One-time trigger</emphasis></para>\n\n        <para>One watch event will be sent to the client when the data has changed.\n        For example, if a client does a getData(\"/znode1\", true) and later the\n        data for /znode1 is changed or deleted, the client will get a watch\n        event for /znode1. If /znode1 changes again, no watch event will be\n        sent unless the client has done another read that sets a new\n        watch.</para>\n      </listitem>\n\n      <listitem>\n        <para><emphasis role=\"bold\">Sent to the client</emphasis></para>\n\n        <para>This implies that an event is on the way to the client, but may\n        not reach the client before the successful return code to the change\n        operation reaches the client that initiated the change. Watches are\n        sent asynchronously to watchers. ZooKeeper provides an ordering\n        guarantee: a client will never see a change for which it has set a\n        watch until it first sees the watch event. Network delays or other\n        factors may cause different clients to see watches and return codes\n        from updates at different times. The key point is that everything seen\n        by the different clients will have a consistent order.</para>\n      </listitem>\n\n      <listitem>\n        <para><emphasis role=\"bold\">The data for which the watch was\n        set</emphasis></para>\n\n        <para>This refers to the different ways a node can change.  It\n        helps to think of ZooKeeper as maintaining two lists of\n        watches: data watches and child watches.  getData() and\n        exists() set data watches. getChildren() sets child\n        watches. Alternatively, it may help to think of watches being\n        set according to the kind of data returned. getData() and\n        exists() return information about the data of the node,\n        whereas getChildren() returns a list of children.  Thus,\n        setData() will trigger data watches for the znode being set\n        (assuming the set is successful). A successful create() will\n        trigger a data watch for the znode being created and a child\n        watch for the parent znode. A successful delete() will trigger\n        both a data watch and a child watch (since there can be no\n        more children) for a znode being deleted as well as a child\n        watch for the parent znode.</para>\n      </listitem>\n    </itemizedlist>\n\n    <para>Watches are maintained locally at the ZooKeeper server to which the\n    client is connected. This allows watches to be lightweight to set,\n    maintain, and dispatch. When a client connects to a new server, the watch\n    will be triggered for any session events. Watches will not be received\n    while disconnected from a server. When a client reconnects, any previously\n    registered watches will be reregistered and triggered if needed. In\n    general this all occurs transparently. There is one case where a watch\n    may be missed: a watch for the existence of a znode not yet created will\n    be missed if the znode is created and deleted while disconnected.</para>\n\n\t<section id=\"sc_WatchSemantics\">\n      <title>Semantics of Watches</title>\n\t  \n\t  <para> We can set watches with the three calls that read the state of \n\t  ZooKeeper: exists, getData, and getChildren. The following list details\n\t  the events that a watch can trigger and the calls that enable them:\n\t  </para>\n\t  \n\t  <itemizedlist>\n        <listitem>\n          <para><emphasis role=\"bold\">Created event:</emphasis></para>\n          <para>Enabled with a call to exists.</para>\n        </listitem>\n        \n        <listitem>\n          <para><emphasis role=\"bold\">Deleted event:</emphasis></para>\n          <para>Enabled with a call to exists, getData, and getChildren.</para>\n        </listitem>\n        \n        <listitem>\n          <para><emphasis role=\"bold\">Changed event:</emphasis></para>\n          <para>Enabled with a call to exists and getData.</para>\n        </listitem>\n        \n        <listitem>\n          <para><emphasis role=\"bold\">Child event:</emphasis></para>\n          <para>Enabled with a call to getChildren.</para>\n        </listitem>\n      </itemizedlist>\n\t</section>\n\t\n    <section id=\"sc_WatchGuarantees\">\n      <title>What ZooKeeper Guarantees about Watches</title>\n\n      <para>With regard to watches, ZooKeeper maintains these\n      guarantees:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para>Watches are ordered with respect to other events, other\n          watches, and asynchronous replies. The ZooKeeper client libraries\n          ensures that everything is dispatched in order.</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>A client will see a watch event for a znode it is watching\n          before seeing the new data that corresponds to that znode.</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>The order of watch events from ZooKeeper corresponds to the\n          order of the updates as seen by the ZooKeeper service.</para>\n        </listitem>\n      </itemizedlist>\n    </section>\n\n    <section id=\"sc_WatchRememberThese\">\n      <title>Things to Remember about Watches</title>\n\n      <itemizedlist>\n        <listitem>\n          <para>Watches are one time triggers; if you get a watch event and\n          you want to get notified of future changes, you must set another\n          watch.</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>Because watches are one time triggers and there is latency\n          between getting the event and sending a new request to get a watch\n          you cannot reliably see every change that happens to a node in\n          ZooKeeper. Be prepared to handle the case where the znode changes\n          multiple times between getting the event and setting the watch\n          again. (You may not care, but at least realize it may\n          happen.)</para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>A watch object, or function/context pair, will only be\n          triggered once for a given notification. For example, if the same\n          watch object is registered for an exists and a getData call for the\n          same file and that file is then deleted, the watch object would\n          only be invoked once with the deletion notification for the file.\n          </para>\n        </listitem>\n      </itemizedlist>\n\n      <itemizedlist>\n        <listitem>\n          <para>When you disconnect from a server (for example, when the\n          server fails), you will not get any watches until the connection\n          is reestablished. For this reason session events are sent to all\n          outstanding watch handlers. Use session events to go into a safe\n          mode: you will not be receiving events while disconnected, so your\n          process should act conservatively in that mode.</para>\n        </listitem>\n      </itemizedlist>\n    </section>\n  </section>\n\n  <section id=\"sc_ZooKeeperAccessControl\">\n    <title>ZooKeeper access control using ACLs</title>\n\n    <para>ZooKeeper uses ACLs to control access to its znodes (the\n    data nodes of a ZooKeeper data tree). The ACL implementation is\n    quite similar to UNIX file access permissions: it employs\n    permission bits to allow/disallow various operations against a\n    node and the scope to which the bits apply. Unlike standard UNIX\n    permissions, a ZooKeeper node is not limited by the three standard\n    scopes for user (owner of the file), group, and world\n    (other). ZooKeeper does not have a notion of an owner of a\n    znode. Instead, an ACL specifies sets of ids and permissions that\n    are associated with those ids.</para>\n\n    <para>Note also that an ACL pertains only to a specific znode. In\n    particular it does not apply to children. For example, if\n    <emphasis>/app</emphasis> is only readable by ip:172.16.16.1 and\n    <emphasis>/app/status</emphasis> is world readable, anyone will\n    be able to read <emphasis>/app/status</emphasis>; ACLs are not\n    recursive.</para>\n\n    <para>ZooKeeper supports pluggable authentication schemes. Ids are\n    specified using the form <emphasis>scheme:id</emphasis>,\n    where <emphasis>scheme</emphasis> is a the authentication scheme\n    that the id corresponds to. For\n    example, <emphasis>ip:172.16.16.1</emphasis> is an id for a\n    host with the address <emphasis>172.16.16.1</emphasis>.</para>\n\n    <para>When a client connects to ZooKeeper and authenticates\n    itself, ZooKeeper associates all the ids that correspond to a\n    client with the clients connection. These ids are checked against\n    the ACLs of znodes when a clients tries to access a node. ACLs are\n    made up of pairs of <emphasis>(scheme:expression,\n    perms)</emphasis>. The format of\n    the <emphasis>expression</emphasis> is specific to the scheme. For\n    example, the pair <emphasis>(ip:19.22.0.0/16, READ)</emphasis>\n    gives the <emphasis>READ</emphasis> permission to any clients with\n    an IP address that starts with 19.22.</para>\n\n    <section id=\"sc_ACLPermissions\">\n      <title>ACL Permissions</title>\n                               \n      <para>ZooKeeper supports the following permissions:</para>\n\n      <itemizedlist>\n        <listitem><para><emphasis role=\"bold\">CREATE</emphasis>: you can create a child node</para></listitem>\n        <listitem><para><emphasis role=\"bold\">READ</emphasis>: you can get data from a node and list its children.</para></listitem>\n        <listitem><para><emphasis role=\"bold\">WRITE</emphasis>: you can set data for a node</para></listitem>\n        <listitem><para><emphasis role=\"bold\">DELETE</emphasis>: you can delete a child node</para></listitem>\n        <listitem><para><emphasis role=\"bold\">ADMIN</emphasis>: you can set permissions</para></listitem>\n      </itemizedlist>\n\n      <para>The <emphasis>CREATE</emphasis>\n      and <emphasis>DELETE</emphasis> permissions have been broken out\n      of the <emphasis>WRITE</emphasis> permission for finer grained\n      access controls. The cases for <emphasis>CREATE</emphasis>\n      and <emphasis>DELETE</emphasis> are the following:</para>\n\n      <para>You want A to be able to do a set on a ZooKeeper node, but\n      not be able to <emphasis>CREATE</emphasis>\n      or <emphasis>DELETE</emphasis> children.</para>\n\n      <para><emphasis>CREATE</emphasis>\n      without <emphasis>DELETE</emphasis>: clients create requests by\n      creating ZooKeeper nodes in a parent directory. You want all\n      clients to be able to add, but only request processor can\n      delete. (This is kind of like the APPEND permission for\n      files.)</para>\n\n      <para>Also, the <emphasis>ADMIN</emphasis> permission is there\n      since ZooKeeper doesn’t have a notion of file owner. In some\n      sense the <emphasis>ADMIN</emphasis> permission designates the\n      entity as the owner. ZooKeeper doesn’t support the LOOKUP\n      permission (execute permission bit on directories to allow you\n      to LOOKUP even though you can't list the directory). Everyone\n      implicitly has LOOKUP permission. This allows you to stat a\n      node, but nothing more. (The problem is, if you want to call\n      zoo_exists() on a node that doesn't exist, there is no\n      permission to check.)</para>\n\n    <section id=\"sc_BuiltinACLSchemes\">\n      <title>Builtin ACL Schemes</title>\n\n      <para>ZooKeeeper has the following built in schemes:</para>\n\n      <itemizedlist>\n        <listitem><para><emphasis role=\"bold\">world</emphasis> has a\n        single id, <emphasis>anyone</emphasis>, that represents\n        anyone.</para></listitem>\n\n        <listitem><para><emphasis role=\"bold\">auth</emphasis> doesn't\n        use any id, represents any authenticated\n        user.</para></listitem>\n\n        <listitem><para><emphasis role=\"bold\">digest</emphasis> uses\n        a <emphasis>username:password</emphasis> string to generate\n        MD5 hash which is then used as an ACL ID\n        identity. Authentication is done by sending\n        the <emphasis>username:password</emphasis> in clear text. When\n        used in the ACL the expression will be\n        the <emphasis>username:base64</emphasis>\n        encoded <emphasis>SHA1</emphasis>\n        password <emphasis>digest</emphasis>.</para>\n        </listitem>\n\n        <listitem><para><emphasis role=\"bold\">ip</emphasis> uses the\n        client host IP as an ACL ID identity. The ACL expression is of\n        the form <emphasis>addr/bits</emphasis> where the most\n        significant <emphasis>bits</emphasis>\n        of <emphasis>addr</emphasis> are matched against the most\n        significant <emphasis>bits</emphasis> of the client host\n        IP.</para></listitem>\n\n      </itemizedlist>\n    </section>\n\n    <section>\n      <title>ZooKeeper C client API</title>\n\n      <para>The following constants are provided by the ZooKeeper C\n      library:</para>\n\n      <itemizedlist>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_READ; //can read node’s value and list its children</para></listitem>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_WRITE;// can set the node’s value</para></listitem>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_CREATE; //can create children</para></listitem>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_DELETE;// can delete children</para></listitem>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_ADMIN; //can execute set_acl()</para></listitem>\n        <listitem><para><emphasis>const</emphasis> <emphasis>int</emphasis> ZOO_PERM_ALL;// all of the above flags OR’d together</para></listitem>\n      </itemizedlist>\n\n      <para>The following are the standard ACL IDs:</para>\n\n      <itemizedlist>\n        <listitem><para><emphasis>struct</emphasis> Id ZOO_ANYONE_ID_UNSAFE; //(‘world’,’anyone’)</para></listitem>\n        <listitem><para><emphasis>struct</emphasis> Id ZOO_AUTH_IDS;// (‘auth’,’’)</para></listitem>\n      </itemizedlist>\n\n      <para>ZOO_AUTH_IDS empty identity string should be interpreted as “the identity of the creator”.</para>\n\n      <para>ZooKeeper client comes with three standard ACLs:</para>\n\n      <itemizedlist>\n        <listitem><para><emphasis>struct</emphasis> ACL_vector ZOO_OPEN_ACL_UNSAFE; //(ZOO_PERM_ALL,ZOO_ANYONE_ID_UNSAFE)</para></listitem>\n        <listitem><para><emphasis>struct</emphasis> ACL_vector ZOO_READ_ACL_UNSAFE;// (ZOO_PERM_READ, ZOO_ANYONE_ID_UNSAFE)</para></listitem>\n        <listitem><para><emphasis>struct</emphasis> ACL_vector ZOO_CREATOR_ALL_ACL; //(ZOO_PERM_ALL,ZOO_AUTH_IDS)</para></listitem>\n      </itemizedlist>\n\n      <para>The ZOO_OPEN_ACL_UNSAFE is completely open free for all\n      ACL: any application can execute any operation on the node and\n      can create, list and delete its children. The\n      ZOO_READ_ACL_UNSAFE is read-only access for any\n      application. CREATE_ALL_ACL grants all permissions to the\n      creator of the node. The creator must have been authenticated by\n      the server (for example, using “<emphasis>digest</emphasis>”\n      scheme) before it can create nodes with this ACL.</para>\n\n      <para>The following ZooKeeper operations deal with ACLs:</para>\n\n      <itemizedlist><listitem>\n          <para><emphasis>int</emphasis> <emphasis>zoo_add_auth</emphasis>\n            (zhandle_t *zh,<emphasis>const</emphasis> <emphasis>char</emphasis>*\n            scheme,<emphasis>const</emphasis> <emphasis>char</emphasis>*\n            cert, <emphasis>int</emphasis> certLen, void_completion_t\n            completion, <emphasis>const</emphasis> <emphasis>void</emphasis>\n            *data);</para>\n      </listitem></itemizedlist>\n\n      <para>The application uses the zoo_add_auth function to\n      authenticate itself to the server. The function can be called\n      multiple times if the application wants to authenticate using\n      different schemes and/or identities.</para>\n\n      <itemizedlist><listitem>\n          <para><emphasis>int</emphasis> <emphasis>zoo_create</emphasis>\n            (zhandle_t *zh, <emphasis>const</emphasis> <emphasis>char</emphasis>\n            *path, <emphasis>const</emphasis> <emphasis>char</emphasis>\n            *value,<emphasis>int</emphasis>\n            valuelen, <emphasis>const</emphasis> <emphasis>struct</emphasis>\n            ACL_vector *acl, <emphasis>int</emphasis>\n            flags,<emphasis>char</emphasis>\n            *realpath, <emphasis>int</emphasis>\n            max_realpath_len);</para>\n      </listitem></itemizedlist>\n\n      <para>zoo_create(...) operation creates a new node. The acl\n      parameter is a list of ACLs associated with the node. The parent\n      node must have the CREATE permission bit set.</para>\n\n      <itemizedlist><listitem>\n          <para><emphasis>int</emphasis> <emphasis>zoo_get_acl</emphasis>\n            (zhandle_t *zh, <emphasis>const</emphasis> <emphasis>char</emphasis>\n            *path,<emphasis>struct</emphasis> ACL_vector\n            *acl, <emphasis>struct</emphasis> Stat *stat);</para>\n      </listitem></itemizedlist>\n\n      <para>This operation returns a node’s ACL info.</para>\n\n      <itemizedlist><listitem>\n          <para><emphasis>int</emphasis> <emphasis>zoo_set_acl</emphasis>\n            (zhandle_t *zh, <emphasis>const</emphasis> <emphasis>char</emphasis>\n            *path, <emphasis>int</emphasis>\n            version,<emphasis>const</emphasis> <emphasis>struct</emphasis>\n            ACL_vector *acl);</para>\n      </listitem></itemizedlist>\n\n      <para>This function replaces node’s ACL list with a new one. The\n      node must have the ADMIN permission set.</para>\n\n      <para>Here is a sample code that makes use of the above APIs to\n      authenticate itself using the “<emphasis>foo</emphasis>” scheme\n      and create an ephemeral node “/xyz” with create-only\n      permissions.</para>\n\n      <note><para>This is a very simple example which is intended to show\n        how to interact with ZooKeeper ACLs\n        specifically. See <filename>.../trunk/src/c/src/cli.c</filename>\n        for an example of a C client implementation</para>\n      </note>\n\n      <programlisting>\n#include &lt;string.h>\n#include &lt;errno.h>\n\n#include \"zookeeper.h\"\n\nstatic zhandle_t *zh;\n\n/**\n * In this example this method gets the cert for your\n *   environment -- you must provide\n */\nchar *foo_get_cert_once(char* id) { return 0; }\n\n/** Watcher function -- empty for this example, not something you should\n * do in real code */\nvoid watcher(zhandle_t *zzh, int type, int state, const char *path,\n             void *watcherCtx) {}\n\nint main(int argc, char argv) {\n  char buffer[512];\n  char p[2048];\n  char *cert=0;\n  char appId[64];\n\n  strcpy(appId, \"example.foo_test\");\n  cert = foo_get_cert_once(appId);\n  if(cert!=0) {\n    fprintf(stderr,\n            \"Certificate for appid [%s] is [%s]\\n\",appId,cert);\n    strncpy(p,cert, sizeof(p)-1);\n    free(cert);\n  } else {\n    fprintf(stderr, \"Certificate for appid [%s] not found\\n\",appId);\n    strcpy(p, \"dummy\");\n  }\n\n  zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);\n\n  zh = zookeeper_init(\"localhost:3181\", watcher, 10000, 0, 0, 0);\n  if (!zh) {\n    return errno;\n  }\n  if(zoo_add_auth(zh,\"foo\",p,strlen(p),0,0)!=ZOK)\n    return 2;\n\n  struct ACL CREATE_ONLY_ACL[] = {{ZOO_PERM_CREATE, ZOO_AUTH_IDS}};\n  struct ACL_vector CREATE_ONLY = {1, CREATE_ONLY_ACL};\n  int rc = zoo_create(zh,\"/xyz\",\"value\", 5, &amp;CREATE_ONLY, ZOO_EPHEMERAL,\n                      buffer, sizeof(buffer)-1);\n\n  /** this operation will fail with a ZNOAUTH error */\n  int buflen= sizeof(buffer);\n  struct Stat stat;\n  rc = zoo_get(zh, \"/xyz\", 0, buffer, &amp;buflen, &amp;stat);\n  if (rc) {\n    fprintf(stderr, \"Error %d for %s\\n\", rc, __LINE__);\n  }\n\n  zookeeper_close(zh);\n  return 0;\n}\n      </programlisting>\n    </section>\n    </section>\n  </section>\n\n  <section id=\"sc_ZooKeeperPluggableAuthentication\">\n    <title>Pluggable ZooKeeper authentication</title>\n\n    <para>ZooKeeper runs in a variety of different environments with\n    various different authentication schemes, so it has a completely\n    pluggable authentication framework. Even the builtin authentication\n    schemes use the pluggable authentication framework.</para>\n\n    <para>To understand how the authentication framework works, first you must\n    understand the two main authentication operations. The framework \n    first must authenticate the client. This is usually done as soon as\n    the client connects to a server and consists of validating information\n    sent from or gathered about a client and associating it with the connection.\n    The second operation handled by the framework is finding the entries in an\n    ACL that correspond to client. ACL entries are &lt;<emphasis>idspec, \n    permissions</emphasis>&gt; pairs. The <emphasis>idspec</emphasis> may be\n    a simple string match against the authentication information associated\n    with the connection or it may be a expression that is evaluated against that\n    information. It is up to the implementation of the authentication plugin\n    to do the match. Here is the interface that an authentication plugin must\n    implement:</para>\n\n    <programlisting>\npublic interface AuthenticationProvider {\n    String getScheme();\n    KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte authData[]);\n    boolean isValid(String id);\n    boolean matches(String id, String aclExpr);\n    boolean isAuthenticated();\n}\n    </programlisting>\n\n    <para>The first method <emphasis>getScheme</emphasis> returns the string\n    that identifies the plugin. Because we support multiple methods of authentication,\n    an authentication credential or an <emphasis>idspec</emphasis> will always be\n    prefixed with <emphasis>scheme:</emphasis>. The ZooKeeper server uses the scheme\n    returned by the authentication plugin to determine which ids the scheme\n    applies to.</para>\n\n    <para><emphasis>handleAuthentication</emphasis> is called when a client\n    sends authentication information to be associated with a connection. The\n    client specifies the scheme to which the information corresponds. The\n    ZooKeeper server passes the information to the authentication plugin whose\n    <emphasis>getScheme</emphasis> matches the scheme passed by the client. The\n    implementor of <emphasis>handleAuthentication</emphasis> will usually return\n    an error if it determines that the information is bad, or it will associate information\n    with the connection using <emphasis>cnxn.getAuthInfo().add(new Id(getScheme(), data))</emphasis>.\n    </para>\n\n    <para>The authentication plugin is involved in both setting and using ACLs. When an\n    ACL is set for a znode, the ZooKeeper server will pass the id part of the entry to\n    the <emphasis>isValid(String id)</emphasis> method. It is up to the plugin to verify\n    that the id has a correct form. For example, <emphasis>ip:172.16.0.0/16</emphasis>\n    is a valid id, but <emphasis>ip:host.com</emphasis> is not. If the new ACL includes\n    an \"auth\" entry, <emphasis>isAuthenticated</emphasis> is used to see if the \n    authentication information for this scheme that is assocatied with the connection\n    should be added to the ACL. Some schemes\n    should not be included in auth. For example, the IP address of the client is not\n    considered as an id that should be added to the ACL if auth is specified.</para>\n\n    <para>ZooKeeper invokes\n    <emphasis>matches(String id, String aclExpr)</emphasis> when checking an ACL. It\n    needs to match authentication information of the client against the relevant ACL\n    entries. To find the entries which apply to the client, the ZooKeeper server will\n    find the scheme of each entry and if there is authentication information\n    from that client for that scheme, <emphasis>matches(String id, String aclExpr)</emphasis>\n    will be called with <emphasis>id</emphasis> set to the authentication information\n    that was previously added to the connection by <emphasis>handleAuthentication</emphasis> and\n    <emphasis>aclExpr</emphasis> set to the id of the ACL entry. The authentication plugin\n    uses its own logic and matching scheme to determine if <emphasis>id</emphasis> is included\n    in <emphasis>aclExpr</emphasis>. \n    </para>\n\n    <para>There are two built in authentication plugins: <emphasis>ip</emphasis> and\n    <emphasis>digest</emphasis>. Additional plugins can adding using system properties. At\n    startup the ZooKeeper server will look for system properties that start with\n    \"zookeeper.authProvider.\" and interpret the value of those properties as the class name\n    of an authentication plugin. These properties can be set using the\n    <emphasis>-Dzookeeeper.authProvider.X=com.f.MyAuth</emphasis> or adding entries such as\n    the following in the server configuration file:</para>\n\n    <programlisting>\nauthProvider.1=com.f.MyAuth\nauthProvider.2=com.f.MyAuth2\n    </programlisting>\n \n    <para>Care should be taking to ensure that the suffix on the property is unique. If there are \n    duplicates such as <emphasis>-Dzookeeeper.authProvider.X=com.f.MyAuth -Dzookeeper.authProvider.X=com.f.MyAuth2</emphasis>,\n    only one will be used. Also all servers must have the same plugins defined, otherwise clients using\n    the authentication schemes provided by the plugins will have problems connecting to some servers.\n    </para>\n  </section>\n      \n  <section id=\"ch_zkGuarantees\">\n    <title>Consistency Guarantees</title>\n\n    <para>ZooKeeper is a high performance, scalable service. Both reads and\n    write operations are designed to be fast, though reads are faster than\n    writes. The reason for this is that in the case of reads, ZooKeeper can\n    serve older data, which in turn is due to ZooKeeper's consistency\n    guarantees:</para>\n\n    <variablelist>\n      <varlistentry>\n        <term>Sequential Consistency</term>\n\n        <listitem>\n          <para>Updates from a client will be applied in the order that they\n          were sent.</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>Atomicity</term>\n\n        <listitem>\n          <para>Updates either succeed or fail -- there are no partial\n          results.</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>Single System Image</term>\n\n        <listitem>\n          <para>A client will see the same view of the service regardless of\n          the server that it connects to.</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>Reliability</term>\n\n        <listitem>\n          <para>Once an update has been applied, it will persist from that\n          time forward until a client overwrites the update. This guarantee\n          has two corollaries:</para>\n\n          <orderedlist>\n            <listitem>\n              <para>If a client gets a successful return code, the update will\n              have been applied. On some failures (communication errors,\n              timeouts, etc) the client will not know if the update has\n              applied or not. We take steps to minimize the failures, but the\n              guarantee is only present with successful return codes.\n              (This is called the <emphasis>monotonicity condition</emphasis> in Paxos.)</para>\n            </listitem>\n\n            <listitem>\n              <para>Any updates that are seen by the client, through a read\n              request or successful update, will never be rolled back when\n              recovering from server failures.</para>\n            </listitem>\n          </orderedlist>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>Timeliness</term>\n\n        <listitem>\n          <para>The clients view of the system is guaranteed to be up-to-date\n          within a certain time bound (on the order of tens of seconds).\n          Either system changes will be seen by a client within this bound, or\n          the client will detect a service outage.</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n\n    <para>Using these consistency guarantees it is easy to build higher level\n    functions such as leader election, barriers, queues, and read/write\n    revocable locks solely at the ZooKeeper client (no additions needed to\n    ZooKeeper). See <ulink url=\"recipes.html\">Recipes and Solutions</ulink>\n    for more details.</para>\n\n    <note>\n        <para>Sometimes developers mistakenly assume one other guarantee that\n        ZooKeeper does <emphasis>not</emphasis> in fact make. This is:</para>\n\n        <variablelist>\n          <varlistentry>\n            <term>Simultaneously Consistent Cross-Client Views</term>\n\n            <listitem>\n              <para>ZooKeeper does not guarantee that at every instance in\n              time, two different clients will have identical views of\n              ZooKeeper data. Due to factors like network delays, one client\n              may perform an update before another client gets notified of the\n              change. Consider the scenario of two clients, A and B. If client\n              A sets the value of a znode /a from 0 to 1, then tells client B\n              to read /a, client B may read the old value of 0, depending on\n              which server it is connected to. If it\n              is important that Client A and Client B read the same value,\n              Client B should should call the <emphasis\n              role=\"bold\">sync()</emphasis> method from the ZooKeeper API\n              method before it performs its read.</para>\n\n              <para>So, ZooKeeper by itself doesn't guarantee that changes occur \n              synchronously across all servers, but ZooKeeper\n              primitives can be used to construct higher level functions that\n              provide useful client synchronization. (For more information,\n              see the <ulink\n              url=\"recipes.html\">ZooKeeper Recipes</ulink>.\n              <emphasis>[tbd:..]</emphasis>).</para>\n            </listitem>\n          </varlistentry>\n        </variablelist>\n      </note>\n  </section>\n\n  <section id=\"ch_bindings\">\n    <title>Bindings</title>\n\n    <para>The ZooKeeper client libraries come in two languages: Java and C.\n    The following sections describe these.</para>\n\n    <section>\n      <title>Java Binding</title>\n\n      <para>There are two packages that make up the ZooKeeper Java binding:\n      <emphasis role=\"bold\">org.apache.zookeeper</emphasis> and <emphasis\n      role=\"bold\">org.apache.zookeeper.data</emphasis>. The rest of the\n      packages that make up ZooKeeper are used internally or are part of the\n      server implementation. The <emphasis\n      role=\"bold\">org.apache.zookeeper.data</emphasis> package is made up of\n      generated classes that are used simply as containers.</para>\n\n      <para>The main class used by a ZooKeeper Java client is the <emphasis\n      role=\"bold\">ZooKeeper</emphasis> class. Its two constructors differ only\n      by an optional session id and password. ZooKeeper supports session\n      recovery accross instances of a process. A Java program may save its\n      session id and password to stable storage, restart, and recover the\n      session that was used by the earlier instance of the program.</para>\n\n      <para>When a ZooKeeper object is created, two threads are created as\n      well: an IO thread and an event thread. All IO happens on the IO thread\n      (using Java NIO). All event callbacks happen on the event thread.\n      Session maintenance such as reconnecting to ZooKeeper servers and\n      maintaining heartbeat is done on the IO thread. Responses for\n      synchronous methods are also processed in the IO thread. All responses\n      to asynchronous methods and watch events are processed on the event\n      thread. There are a few things to notice that result from this\n      design:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para>All completions for asynchronous calls and watcher callbacks\n          will be made in order, one at a time. The caller can do any\n          processing they wish, but no other callbacks will be processed\n          during that time.</para>\n        </listitem>\n\n        <listitem>\n          <para>Callbacks do not block the processing of the IO thread or the\n          processing of the synchronous calls.</para>\n        </listitem>\n\n        <listitem>\n          <para>Synchronous calls may not return in the correct order. For\n          example, assume a client does the following processing: issues an\n          asynchronous read of node <emphasis role=\"bold\">/a</emphasis> with\n          <emphasis>watch</emphasis> set to true, and then in the completion\n          callback of the read it does a synchronous read of <emphasis\n          role=\"bold\">/a</emphasis>. (Maybe not good practice, but not illegal\n          either, and it makes for a simple example.)</para>\n\n          <para>Note that if there is a change to <emphasis\n          role=\"bold\">/a</emphasis> between the asynchronous read and the\n          synchronous read, the client library will receive the watch event\n          saying <emphasis role=\"bold\">/a</emphasis> changed before the\n          response for the synchronous read, but because the completion\n          callback is blocking the event queue, the synchronous read will\n          return with the new value of <emphasis role=\"bold\">/a</emphasis>\n          before the watch event is processed.</para>\n        </listitem>\n      </itemizedlist>\n\n      <para>Finally, the rules associated with shutdown are straightforward:\n      once a ZooKeeper object is closed or receives a fatal event\n      (SESSION_EXPIRED and AUTH_FAILED), the ZooKeeper object becomes invalid.\n      On a close, the two threads shut down and any further access on zookeeper\n      handle is undefined behavior and should be avoided. </para>\n    </section>\n\n    <section>\n      <title>C Binding</title>\n\n      <para>The C binding has a single-threaded and multi-threaded library.\n      The multi-threaded library is easiest to use and is most similar to the\n      Java API. This library will create an IO thread and an event dispatch\n      thread for handling connection maintenance and callbacks. The\n      single-threaded library allows ZooKeeper to be used in event driven\n      applications by exposing the event loop used in the multi-threaded\n      library.</para>\n\n      <para>The package includes two shared libraries: zookeeper_st and\n      zookeeper_mt. The former only provides the asynchronous APIs and\n      callbacks for integrating into the application's event loop. The only\n      reason this library exists is to support the platforms were a\n      <emphasis>pthread</emphasis> library is not available or is unstable\n      (i.e. FreeBSD 4.x). In all other cases, application developers should\n      link with zookeeper_mt, as it includes support for both Sync and Async\n      API.</para>\n\n      <section>\n        <title>Installation</title>\n\n        <para>If you're building the client from a check-out from the Apache\n        repository, follow the steps outlined below. If you're building from a\n        project source package downloaded from apache, skip to step <emphasis\n        role=\"bold\">3</emphasis>.</para>\n\n        <orderedlist>\n          <listitem>\n            <para>Run <command>ant compile_jute</command> from the ZooKeeper\n            top level directory (<filename>.../trunk</filename>).\n            This will create a directory named \"generated\" under\n            <filename>.../trunk/src/c</filename>.</para>\n          </listitem>\n\n          <listitem>\n            <para>Change directory to the<filename>.../trunk/src/c</filename>\n            and run <command>autoreconf -if</command> to bootstrap <emphasis\n            role=\"bold\">autoconf</emphasis>, <emphasis\n            role=\"bold\">automake</emphasis> and <emphasis\n            role=\"bold\">libtool</emphasis>. Make sure you have <emphasis\n            role=\"bold\">autoconf version 2.59</emphasis> or greater installed.\n            Skip to step<emphasis role=\"bold\"> 4</emphasis>.</para>\n          </listitem>\n\n          <listitem>\n            <para>If you are building from a project source package,\n            unzip/untar the source tarball and cd to the<filename>\n            zookeeper-x.x.x/src/c</filename> directory.</para>\n          </listitem>\n\n          <listitem>\n            <para>Run <command>./configure &lt;your-options&gt;</command> to\n            generate the makefile. Here are some of options the <emphasis\n            role=\"bold\">configure</emphasis> utility supports that can be\n            useful in this step:</para>\n\n            <itemizedlist>\n              <listitem>\n                <para><command>--enable-debug</command></para>\n\n                <para>Enables optimization and enables debug info compiler\n                options. (Disabled by default.)</para>\n              </listitem>\n\n              <listitem>\n                <para><command>--without-syncapi </command></para>\n\n                <para>Disables Sync API support; zookeeper_mt library won't be\n                built. (Enabled by default.)</para>\n              </listitem>\n\n              <listitem>\n                <para><command>--disable-static </command></para>\n\n                <para>Do not build static libraries. (Enabled by\n                default.)</para>\n              </listitem>\n\n              <listitem>\n                <para><command>--disable-shared</command></para>\n\n                <para>Do not build shared libraries. (Enabled by\n                default.)</para>\n              </listitem>\n            </itemizedlist>\n\n            <note>\n              <para>See INSTALL for general information about running\n              <emphasis role=\"bold\">configure</emphasis>.</para>\n            </note>\n          </listitem>\n\n          <listitem>\n            <para>Run <command>make</command> or <command>make\n            install</command> to build the libraries and install them.</para>\n          </listitem>\n\n          <listitem>\n            <para>To generate doxygen documentation for the ZooKeeper API, run\n            <command>make doxygen-doc</command>. All documentation will be\n            placed in a new subfolder named docs. By default, this command\n            only generates HTML. For information on other document formats,\n            run <command>./configure --help</command></para>\n          </listitem>\n        </orderedlist>\n      </section>\n\n      <section>\n        <title>Building Your Own C Client</title>\n\n        <para>In order to be able to use the ZooKeeper API in your application\n        you have to remember to</para>\n\n        <orderedlist>\n          <listitem>\n            <para>Include ZooKeeper header: #include\n              &lt;zookeeper/zookeeper.h&gt;</para>\n          </listitem>\n\n          <listitem>\n            <para>If you are building a multithreaded client, compile with\n            -DTHREADED compiler flag to enable the multi-threaded version of\n            the library, and then link against against the\n            <emphasis>zookeeper_mt</emphasis> library. If you are building a\n            single-threaded client, do not compile with -DTHREADED, and be\n            sure to link against the<emphasis> zookeeper_st\n            </emphasis>library.</para>\n          </listitem>\n        </orderedlist>\n\n        <note><para>\n          See <filename>.../trunk/src/c/src/cli.c</filename>\n            for an example of a C client implementation</para>\n        </note>\n      </section>\n    </section>\n  </section>\n\n   <section id=\"ch_guideToZkOperations\">\n    <title>Building Blocks: A Guide to ZooKeeper Operations</title>\n\n    <para>This section surveys all the operations a developer can perform\n    against a ZooKeeper server. It is lower level information than the earlier\n    concepts chapters in this manual, but higher level than the ZooKeeper API\n    Reference. It covers these topics:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para><xref linkend=\"sc_connectingToZk\" /></para>\n      </listitem>\n    </itemizedlist>\n\n    <section id=\"sc_errorsZk\">\n      <title>Handling Errors</title>\n\n      <para>Both the Java and C client bindings may report errors. The Java client binding does so by throwing KeeperException, calling code() on the exception will return the specific error code. The C client binding returns an error code as defined in the enum ZOO_ERRORS. API callbacks indicate result code for both language bindings. See the API documentation (javadoc for Java, doxygen for C) for full details on the possible errors and their meaning.</para>\n    </section>\n    \n    <section id=\"sc_connectingToZk\">\n      <title>Connecting to ZooKeeper</title>\n\n      <para></para>\n    </section>\n    \n    <section id=\"sc_readOps\">\n      <title>Read Operations</title>\n\n      <para></para>\n    </section>\n    \n    <section id=\"sc_writeOps\">\n      <title>Write Operations</title>\n\n      <para></para>\n    </section>\n    \n    <section id=\"sc_handlingWatches\">\n      <title>Handling Watches</title>\n\n      <para></para>\n    </section>\n    \n    <section id=\"sc_miscOps\">\n      <title>Miscelleaneous ZooKeeper Operations</title>\n      <para></para>\n    </section>\n    \n\n  </section>\n\n  <section id=\"ch_programStructureWithExample\">\n    <title>Program Structure, with Simple Example</title>\n\n    <para><emphasis>[tbd]</emphasis></para>\n  </section>\n\n  <section id=\"ch_gotchas\">\n    <title>Gotchas: Common Problems and Troubleshooting</title>\n\n    <para>So now you know ZooKeeper. It's fast, simple, your application\n    works, but wait ... something's wrong. Here are some pitfalls that\n    ZooKeeper users fall into:</para>\n\n    <orderedlist>\n      <listitem>\n        <para>If you are using watches, you must look for the connected watch\n        event. When a ZooKeeper client disconnects from a server, you will\n        not receive notification of changes until reconnected. If you are\n        watching for a znode to come into existence, you will miss the event\n        if the znode is created and deleted while you are disconnected.</para>\n      </listitem>\n\n      <listitem>\n        <para>You must test ZooKeeper server failures. The ZooKeeper service\n        can survive failures as long as a majority of servers are active. The\n        question to ask is: can your application handle it? In the real world\n        a client's connection to ZooKeeper can break. (ZooKeeper server\n        failures and network partitions are common reasons for connection\n        loss.) The ZooKeeper client library takes care of recovering your\n        connection and letting you know what happened, but you must make sure\n        that you recover your state and any outstanding requests that failed.\n        Find out if you got it right in the test lab, not in production - test\n        with a ZooKeeper service made up of a several of servers and subject\n        them to reboots.</para>\n      </listitem>\n\n      <listitem>\n        <para>The list of ZooKeeper servers used by the client must match the\n        list of ZooKeeper servers that each ZooKeeper server has. Things can\n        work, although not optimally, if the client list is a subset of the\n        real list of ZooKeeper servers, but not if the client lists ZooKeeper\n        servers not in the ZooKeeper cluster.</para>\n      </listitem>\n\n      <listitem>\n        <para>Be careful where you put that transaction log. The most\n        performance-critical part of ZooKeeper is the transaction log.\n        ZooKeeper must sync transactions to media before it returns a\n        response. A dedicated transaction log device is key to consistent good\n        performance. Putting the log on a busy device will adversely effect\n        performance. If you only have one storage device, put trace files on\n        NFS and increase the snapshotCount; it doesn't eliminate the problem,\n        but it can mitigate it.</para>\n      </listitem>\n\n      <listitem>\n        <para>Set your Java max heap size correctly. It is very important to\n        <emphasis>avoid swapping.</emphasis> Going to disk unnecessarily will\n        almost certainly degrade your performance unacceptably. Remember, in\n        ZooKeeper, everything is ordered, so if one request hits the disk, all\n        other queued requests hit the disk.</para>\n\n        <para>To avoid swapping, try to set the heapsize to the amount of\n        physical memory you have, minus the amount needed by the OS and cache.\n        The best way to determine an optimal heap size for your configurations\n        is to <emphasis>run load tests</emphasis>. If for some reason you\n        can't, be conservative in your estimates and choose a number well\n        below the limit that would cause your machine to swap. For example, on\n        a 4G machine, a 3G heap is a conservative estimate to start\n        with.</para>\n      </listitem>\n    </orderedlist>\n  </section>\n\n  <appendix id=\"apx_linksToOtherInfo\">\n    <title>Links to Other Information</title>\n\n    <para>Outside the formal documentation, there're several other sources of\n    information for ZooKeeper developers.</para>\n\n    <variablelist>\n      <varlistentry>\n        <term>ZooKeeper Whitepaper <emphasis>[tbd: find url]</emphasis></term>\n\n        <listitem>\n          <para>The definitive discussion of ZooKeeper design and performance,\n          by Yahoo! Research</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>API Reference <emphasis>[tbd: find url]</emphasis></term>\n\n        <listitem>\n          <para>The complete reference to the ZooKeeper API</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term><ulink\n        url=\"http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/zookeeper.m4v\">ZooKeeper\n        Talk at the Hadoup Summit 2008</ulink></term>\n\n        <listitem>\n          <para>A video introduction to ZooKeeper, by Benjamin Reed of Yahoo!\n          Research</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term><ulink\n                url=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/Tutorial\">Barrier and\n        Queue Tutorial</ulink></term>\n\n        <listitem>\n          <para>The excellent Java tutorial by Flavio Junqueira, implementing\n          simple barriers and producer-consumer queues using ZooKeeper.</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term><ulink\n                url=\"https://cwiki.apache.org/confluence/display/ZOOKEEPER/ZooKeeperArticles\">ZooKeeper\n        - A Reliable, Scalable Distributed Coordination System</ulink></term>\n\n        <listitem>\n          <para>An article by Todd Hoff (07/15/2008)</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term><ulink url=\"recipes.html\">ZooKeeper Recipes</ulink></term>\n\n        <listitem>\n          <para>Pseudo-level discussion of the implementation of various\n          synchronization solutions with ZooKeeper: Event Handles, Queues,\n          Locks, and Two-phase Commits.</para>\n        </listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term><emphasis>[tbd]</emphasis></term>\n\n        <listitem>\n          <para>Any other good sources anyone can think of...</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n  </appendix>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperQuotas.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t<!--\n\t\tCopyright 2002-2004 The Apache Software Foundation Licensed under the\n\t\tApache License, Version 2.0 (the \"License\"); you may not use this file\n\t\texcept in compliance with the License. You may obtain a copy of the\n\t\tLicense at http://www.apache.org/licenses/LICENSE-2.0 Unless required\n\t\tby applicable law or agreed to in writing, software distributed under\n\t\tthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n\t\tCONDITIONS OF ANY KIND, either express or implied. See the License for\n\t\tthe specific language governing permissions and limitations under the\n\t\tLicense.\n\t-->\n                        <!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n                        \"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_Quota\">\n\t<title>ZooKeeper Quota's Guide</title>\n\t<subtitle>A Guide to Deployment and Administration</subtitle>\n\t<articleinfo>\n\t\t<legalnotice>\n\t\t\t<para>\n\t\t\t\tLicensed under the Apache License, Version 2.0 (the \"License\"); you\n\t\t\t\tmay not use this file except in compliance with the License. You may\n\t\t\t\tobtain a copy of the License at\n\t\t\t\t<ulink url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0\n\t\t\t\t</ulink>\n\t\t\t\t.\n\t\t\t</para>\n\t\t\t<para>Unless required by applicable law or agreed to in\n\t\t\t\twriting, software distributed under the License is distributed on an\n\t\t\t\t\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n\t\t\t\texpress or implied. See the License for the specific language\n\t\t\t\tgoverning permissions and limitations under the License.</para>\n\t\t</legalnotice>\n\t\t<abstract>\n\t\t\t<para>This document contains information about deploying,\n\t\t\t\tadministering and mantaining ZooKeeper. It also discusses best\n\t\t\t\tpractices and common problems.</para>\n\t\t</abstract>\n\t</articleinfo>\n\t<section id=\"zookeeper_quotas\">\n\t<title>Quotas</title>\n\t<para> ZooKeeper has both namespace and bytes quotas. You can use the ZooKeeperMain class to setup quotas.\n\tZooKeeper prints <emphasis>WARN</emphasis> messages if users exceed the quota assigned to them. The messages \n\tare printed in the log of the ZooKeeper. \n\t</para>\n\t<para><computeroutput>$ bin/zkCli.sh -server host:port</computeroutput></para>\n\t <para> The above command gives you a command line option of using quotas.</para>\n\t <section>\n\t <title>Setting Quotas</title>\n\t<para>You can use \n\t <emphasis>setquota</emphasis> to set a quota on a ZooKeeper node. It has an option of setting quota with\n\t  -n (for namespace)\n\t and -b (for bytes). </para>\n\t<para> The ZooKeeper quota are stored in ZooKeeper itself in /zookeeper/quota. To disable other people from\n\tchanging the quota's set the ACL for /zookeeper/quota such that only admins are able to read and write to it.\n\t</para>\n\t</section>\n\t<section>\n\t<title>Listing Quotas</title>\n\t<para> You can use\n\t<emphasis>listquota</emphasis> to list a quota on a ZooKeeper node.\n\t</para>\n\t</section>\n\t<section>\n\t<title> Deleting Quotas</title>\n\t<para> You can use\n\t<emphasis>delquota</emphasis> to delete quota on a ZooKeeper node.\n\t</para>\n\t</section>\n\t</section>\n\t</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperStarted.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"bk_GettStartedGuide\">\n  <title>ZooKeeper Getting Started Guide</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This guide contains detailed information about creating\n      distributed applications that use ZooKeeper. It discusses the basic\n      operations ZooKeeper supports, and how these can be used to build\n      higher-level abstractions. It contains solutions to common tasks, a\n      troubleshooting guide, and links to other information.</para>\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_GettingStarted\">\n    <title>Getting Started: Coordinating Distributed Applications with\n      ZooKeeper</title>\n\n    <para>This document contains information to get you started quickly with\n    ZooKeeper. It is aimed primarily at developers hoping to try it out, and\n    contains simple installation instructions for a single ZooKeeper server, a\n    few commands to verify that it is running, and a simple programming\n    example. Finally, as a convenience, there are a few sections regarding\n    more complicated installations, for example running replicated\n    deployments, and optimizing the transaction log. However for the complete\n    instructions for commercial deployments, please refer to the <ulink\n    url=\"zookeeperAdmin.html\">ZooKeeper\n    Administrator's Guide</ulink>.</para>\n\n    <section id=\"sc_Prerequisites\">\n      <title>Pre-requisites</title>\n\n      <para>See <ulink url=\"zookeeperAdmin.html#sc_systemReq\">\n          System Requirements</ulink> in the Admin guide.</para>\n    </section>\n\n    <section id=\"sc_Download\">\n      <title>Download</title>\n\n      <para>To get a ZooKeeper distribution, download a recent\n        <ulink url=\"http://zookeeper.apache.org/releases.html\">\n          stable</ulink> release from one of the Apache Download\n        Mirrors.</para>\n    </section>\n\t\n    <section id=\"sc_InstallingSingleMode\">\n      <title>Standalone Operation</title>\n\n      <para>Setting up a ZooKeeper server in standalone mode is\n      straightforward. The server is contained in a single JAR file,\n      so installation consists of creating a configuration.</para>\n\n      <para>Once you've downloaded a stable ZooKeeper release unpack\n      it and cd to the root</para>\n\n      <para>To start ZooKeeper you need a configuration file. Here is a sample,\n      create it in <emphasis role=\"bold\">conf/zoo.cfg</emphasis>:</para>\n\n<programlisting>\ntickTime=2000\ndataDir=/var/lib/zookeeper\nclientPort=2181\n</programlisting>\n\n      <para>This file can be called anything, but for the sake of this\n      discussion call\n      it <emphasis role=\"bold\">conf/zoo.cfg</emphasis>. Change the\n      value of <emphasis role=\"bold\">dataDir</emphasis> to specify an\n      existing (empty to start with) directory.  Here are the meanings\n      for each of the fields:</para>\n\n      <variablelist>\n        <varlistentry>\n          <term><emphasis role=\"bold\">tickTime</emphasis></term>\n\n          <listitem>\n            <para>the basic time unit in milliseconds used by ZooKeeper. It is\n            used to do heartbeats and the minimum session timeout will be\n            twice the tickTime.</para>\n          </listitem>\n        </varlistentry>\n      </variablelist>\n\n      <variablelist>\n        <varlistentry>\n          <term><emphasis role=\"bold\">dataDir</emphasis></term>\n\n          <listitem>\n            <para>the location to store the in-memory database snapshots and,\n            unless specified otherwise, the transaction log of updates to the\n            database.</para>\n          </listitem>\n        </varlistentry>\n\n        <varlistentry>\n          <term><emphasis role=\"bold\">clientPort</emphasis></term>\n\n          <listitem>\n            <para>the port to listen for client connections</para>\n          </listitem>\n        </varlistentry>\n      </variablelist>\n\n      <para>Now that you created the configuration file, you can start\n      ZooKeeper:</para>\n\n      <programlisting>bin/zkServer.sh start</programlisting>\n\n      <para>ZooKeeper logs messages using log4j -- more detail\n      available in the\n      <ulink url=\"zookeeperProgrammers.html#Logging\">Logging</ulink>\n      section of the Programmer's Guide. You will see log messages\n      coming to the console (default) and/or a log file depending on\n      the log4j configuration.</para>\n\n      <para>The steps outlined here run ZooKeeper in standalone mode. There is\n      no replication, so if ZooKeeper process fails, the service will go down.\n      This is fine for most development situations, but to run ZooKeeper in\n      replicated mode, please see <ulink\n      url=\"#sc_RunningReplicatedZooKeeper\">Running Replicated\n      ZooKeeper</ulink>.</para>\n    </section>\n\t\n    <section id=\"sc_FileManagement\">\n      <title>Managing ZooKeeper Storage</title>\n      <para>For long running production systems ZooKeeper storage must\n      be managed externally (dataDir and logs). See the section on\n      <ulink\n      url=\"zookeeperAdmin.html#sc_maintenance\">maintenance</ulink> for\n      more details.</para>\n    </section>\n\n    <section id=\"sc_ConnectingToZooKeeper\">\n      <title>Connecting to ZooKeeper</title>\n\n      <programlisting>$ bin/zkCli.sh -server 127.0.0.1:2181</programlisting>\n\n      <para>This lets you perform simple, file-like operations.</para>\n\n      <para>Once you have connected, you should see something like:\n        </para>\n      <programlisting>\n<![CDATA[\nConnecting to localhost:2181\nlog4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).\nlog4j:WARN Please initialize the log4j system properly.\nWelcome to ZooKeeper!\nJLine support is enabled\n[zkshell: 0]\n]]>        </programlisting>\n      <para>\n        From the shell, type <command>help</command> to get a listing of commands that can be executed from the client, as in:\n      </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 0] help\nZooKeeper host:port cmd args\n        get path [watch]\n        ls path [watch]\n        set path data [version]\n        delquota [-n|-b] path\n        quit\n        printwatches on|off\n        createpath data acl\n        stat path [watch]\n        listquota path\n        history\n        setAcl path acl\n        getAcl path\n        sync path\n        redo cmdno\n        addauth scheme auth\n        delete path [version]\n        setquota -n|-b val path\n\n]]>        </programlisting>\n      <para>From here, you can try a few simple commands to get a feel for this simple command line interface.  First, start by issuing the list command, as\n      in <command>ls</command>, yielding:\n      </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 8] ls /\n[zookeeper]\n]]>        </programlisting>\n      <para>Next, create a new znode by running <command>create /zk_test my_data</command>. This creates a new znode and associates the string \"my_data\" with the node.\n      You should see:</para>\n      <programlisting>\n<![CDATA[\n[zkshell: 9] create /zk_test my_data\nCreated /zk_test\n]]>      </programlisting>\n      <para>  Issue another <command>ls /</command> command to see what the directory looks like:\n        </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 11] ls /\n[zookeeper, zk_test]\n\n]]>        </programlisting><para>\n      Notice that the zk_test directory has now been created.\n      </para>\n      <para>Next, verify that the data was associated with the znode by running the <command>get</command> command, as in:\n      </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 12] get /zk_test\nmy_data\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 5\nmtime = Fri Jun 05 13:57:06 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 0\naclVersion = 0\nephemeralOwner = 0\ndataLength = 7\nnumChildren = 0\n]]>        </programlisting>\n      <para>We can change the data associated with zk_test by issuing the <command>set</command> command, as in:\n        </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 14] set /zk_test junk\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 6\nmtime = Fri Jun 05 14:01:52 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 1\naclVersion = 0\nephemeralOwner = 0\ndataLength = 4\nnumChildren = 0\n[zkshell: 15] get /zk_test\njunk\ncZxid = 5\nctime = Fri Jun 05 13:57:06 PDT 2009\nmZxid = 6\nmtime = Fri Jun 05 14:01:52 PDT 2009\npZxid = 5\ncversion = 0\ndataVersion = 1\naclVersion = 0\nephemeralOwner = 0\ndataLength = 4\nnumChildren = 0\n]]>      </programlisting>\n      <para>\n       (Notice we did a <command>get</command> after setting the data and it did, indeed, change.</para>\n      <para>Finally, let's <command>delete</command> the node by issuing:\n      </para>\n      <programlisting>\n<![CDATA[\n[zkshell: 16] delete /zk_test\n[zkshell: 17] ls /\n[zookeeper]\n[zkshell: 18]\n]]></programlisting>\n      <para>That's it for now.  To explore more, continue with the rest of this document and see the <ulink url=\"zookeeperProgrammers.html\">Programmer's Guide</ulink>. </para>\n    </section>\n\n    <section id=\"sc_ProgrammingToZooKeeper\">\n      <title>Programming to ZooKeeper</title>\n\n      <para>ZooKeeper has a Java bindings and C bindings. They are\n      functionally equivalent. The C bindings exist in two variants: single\n      threaded and multi-threaded. These differ only in how the messaging loop\n      is done. For more information, see the <ulink\n      url=\"zookeeperProgrammers.html#ch_programStructureWithExample\">Programming\n      Examples in the ZooKeeper Programmer's Guide</ulink> for\n      sample code using of the different APIs.</para>\n    </section>\n\n    <section id=\"sc_RunningReplicatedZooKeeper\">\n      <title>Running Replicated ZooKeeper</title>\n\n      <para>Running ZooKeeper in standalone mode is convenient for evaluation,\n      some development, and testing. But in production, you should run\n      ZooKeeper in replicated mode. A replicated group of servers in the same\n      application is called a <emphasis>quorum</emphasis>, and in replicated\n      mode, all servers in the quorum have copies of the same configuration\n      file.</para>\n   <note>\n      <para>\n         For replicated mode, a minimum of three servers are required,\n         and it is strongly recommended that you have an odd number of\n         servers. If you only have two servers, then you are in a\n         situation where if one of them fails, there are not enough\n         machines to form a majority quorum. Two servers is inherently\n         <emphasis role=\"bold\">less</emphasis>\n         stable than a single server, because there are two single\n         points of failure.\n      </para>\n   </note>\n   <para>\n      The required\n      <emphasis role=\"bold\">conf/zoo.cfg</emphasis>\n      file for replicated mode is similar to the one used in standalone\n      mode, but with a few differences. Here is an example:\n   </para>\n\n<programlisting>\ntickTime=2000\ndataDir=/var/lib/zookeeper\nclientPort=2181\ninitLimit=5\nsyncLimit=2\nserver.1=zoo1:2888:3888\nserver.2=zoo2:2888:3888\nserver.3=zoo3:2888:3888\n</programlisting>\n\n      <para>The new entry, <emphasis role=\"bold\">initLimit</emphasis> is\n      timeouts ZooKeeper uses to limit the length of time the ZooKeeper\n      servers in quorum have to connect to a leader. The entry <emphasis\n      role=\"bold\">syncLimit</emphasis> limits how far out of date a server can\n      be from a leader.</para>\n\n      <para>With both of these timeouts, you specify the unit of time using\n      <emphasis role=\"bold\">tickTime</emphasis>. In this example, the timeout\n      for initLimit is 5 ticks at 2000 milleseconds a tick, or 10\n      seconds.</para>\n\n      <para>The entries of the form <emphasis>server.X</emphasis> list the\n      servers that make up the ZooKeeper service. When the server starts up,\n      it knows which server it is by looking for the file\n      <emphasis>myid</emphasis> in the data directory. That file has the \n      contains the server number, in ASCII.</para>\n\n       <para>Finally, note the two port numbers after each server\n       name: \" 2888\" and \"3888\". Peers use the former port to connect\n       to other peers. Such a connection is necessary so that peers\n       can communicate, for example, to agree upon the order of\n       updates. More specifically, a ZooKeeper server uses this port\n       to connect followers to the leader. When a new leader arises, a\n       follower opens a TCP connection to the leader using this\n       port. Because the default leader election also uses TCP, we\n       currently require another port for leader election. This is the\n       second port in the server entry.\n       </para>\n\n      <note>\n        <para>If you want to test multiple servers on a single\n        machine, specify the servername\n        as <emphasis>localhost</emphasis> with unique quorum &amp;\n        leader election ports (i.e. 2888:3888, 2889:3889, 2890:3890 in\n        the example above) for each server.X in that server's config\n        file. Of course separate <emphasis>dataDir</emphasis>s and\n        distinct <emphasis>clientPort</emphasis>s are also necessary\n        (in the above replicated example, running on a\n        single <emphasis>localhost</emphasis>, you would still have\n        three config files).</para>\n        <para>Please be aware that setting up multiple servers on a single\n            machine will not create any redundancy. If something were to\n            happen which caused the machine to die, all of the zookeeper\n            servers would be offline. Full redundancy requires that each\n            server have its own machine. It must be a completely separate\n            physical server. Multiple virtual machines on the same physical\n            host are still vulnerable to the complete failure of that host.</para>\n      </note>\n    </section>\n\n    <section>\n      <title>Other Optimizations</title>\n\n      <para>There are a couple of other configuration parameters that can\n      greatly increase performance:</para>\n\n      <itemizedlist>\n        <listitem>\n          <para>To get low latencies on updates it is important to\n          have a dedicated transaction log directory. By default\n          transaction logs are put in the same directory as the data\n          snapshots and <emphasis>myid</emphasis> file. The dataLogDir\n          parameters indicates a different directory to use for the\n          transaction logs.</para>\n        </listitem>\n\n        <listitem>\n          <para><emphasis>[tbd: what is the other config param?]</emphasis></para>\n        </listitem>\n      </itemizedlist>\n    </section>\n  </section>\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/content/xdocs/zookeeperTutorial.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!DOCTYPE article PUBLIC \"-//OASIS//DTD Simplified DocBook XML V1.0//EN\"\n\"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd\">\n<article id=\"ar_Tutorial\">\n  <title>Programming with ZooKeeper - A basic tutorial</title>\n\n  <articleinfo>\n    <legalnotice>\n      <para>Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License. You may\n      obtain a copy of the License at <ulink\n      url=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>\n\n      <para>Unless required by applicable law or agreed to in writing,\n      software distributed under the License is distributed on an \"AS IS\"\n      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied. See the License for the specific language governing permissions\n      and limitations under the License.</para>\n    </legalnotice>\n\n    <abstract>\n      <para>This article contains sample Java code for simple implementations of barrier\n      and consumers queues..</para>\n\n    </abstract>\n  </articleinfo>\n\n  <section id=\"ch_Introduction\">\n    <title>Introduction</title>\n\n    <para>In this tutorial, we show simple implementations of barriers and \n    producer-consumer queues using ZooKeeper. We call the respective classes Barrier and Queue. \n    These examples assume that you have at least one ZooKeeper server running.</para>\n    \n    <para>Both primitives use the following common excerpt of code:</para>\n    \n    <programlisting>\n    static ZooKeeper zk = null;\n    static Integer mutex;\n\n    String root;\n\n    SyncPrimitive(String address) {\n        if(zk == null){\n            try {\n                System.out.println(\"Starting ZK:\");\n                zk = new ZooKeeper(address, 3000, this);\n                mutex = new Integer(-1);\n                System.out.println(\"Finished starting ZK: \" + zk);\n            } catch (IOException e) {\n                System.out.println(e.toString());\n                zk = null;\n            }\n        }\n    }\n\n    synchronized public void process(WatchedEvent event) {\n        synchronized (mutex) {\n            mutex.notify();\n        }\n    }\n</programlisting>\n\n<para>Both classes extend SyncPrimitive. In this way, we execute steps that are \ncommon to all primitives in the constructor of SyncPrimitive. To keep the examples \nsimple, we create a ZooKeeper object the first time we instantiate either a barrier \nobject or a queue object, and we declare a static variable that is a reference \nto this object. The subsequent instances of Barrier and Queue check whether a \nZooKeeper object exists. Alternatively, we could have the application creating a\nZooKeeper object and passing it to the constructor of Barrier and Queue.</para>\n<para>\nWe use the process() method to process notifications triggered due to watches. \nIn the following discussion, we present code that sets watches. A watch is internal \nstructure that enables ZooKeeper to notify a client of a change to a node. For example, \nif a client is waiting for other clients to leave a barrier, then it can set a watch and \nwait for modifications to a particular node, which can indicate that it is the end of the wait. \nThis point becomes clear once we go over the examples.\n</para>\n</section>\n   \n <section id=\"sc_barriers\"><title>Barriers</title>\n \n <para>\n A barrier is a primitive that enables a group of processes to synchronize the \n beginning and the end of a computation. The general idea of this implementation \n is to have a barrier node that serves the purpose of being a parent for individual \n process nodes. Suppose that we call the barrier node \"/b1\". Each process \"p\" then \n creates a node \"/b1/p\". Once enough processes have created their corresponding \n nodes, joined processes can start the computation.\n </para>\n \n <para>In this example, each process instantiates a Barrier object, and its constructor takes as parameters:</para>\n\n <itemizedlist><listitem><para>the address of a ZooKeeper server (e.g., \"zoo1.foo.com:2181\")</para></listitem>\n<listitem><para>the path of the barrier node on ZooKeeper (e.g., \"/b1\")</para></listitem>\n<listitem><para>the size of the group of processes</para></listitem>\n</itemizedlist>\n\n<para>The constructor of Barrier passes the address of the Zookeeper server to the \nconstructor of the parent class. The parent class creates a ZooKeeper instance if \none does not exist. The constructor of Barrier then creates a \nbarrier node on ZooKeeper, which is the parent node of all process nodes, and \nwe call root (<emphasis role=\"bold\">Note:</emphasis> This is not the ZooKeeper root \"/\").</para>\n\n<programlisting>\n        /**\n         * Barrier constructor\n         *\n         * @param address\n         * @param root\n         * @param size\n         */\n        Barrier(String address, String root, int size) {\n            super(address);\n            this.root = root;\n            this.size = size;\n\n            // Create barrier node\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n\n            // My node name\n            try {\n                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());\n            } catch (UnknownHostException e) {\n                System.out.println(e.toString());\n            }\n\n        }\n</programlisting>\n<para>\nTo enter the barrier, a process calls enter(). The process creates a node under \nthe root to represent it, using its host name to form the node name. It then wait \nuntil enough processes have entered the barrier. A process does it by checking \nthe number of children the root node has with \"getChildren()\", and waiting for \nnotifications in the case it does not have enough. To receive a notification when \nthere is a change to the root node, a process has to set a watch, and does it \nthrough the call to \"getChildren()\". In the code, we have that \"getChildren()\" \nhas two parameters. The first one states the node to read from, and the second is\na boolean flag that enables the process to set a watch. In the code the flag is true.\n</para>\n\n<programlisting>\n        /**\n         * Join barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean enter() throws KeeperException, InterruptedException{\n            zk.create(root + \"/\" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL_SEQUENTIAL);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n\n                    if (list.size() &lt; size) {\n                        mutex.wait();\n                    } else {\n                        return true;\n                    }\n                }\n            }\n        }\n</programlisting>\n<para>\nNote that enter() throws both KeeperException and InterruptedException, so it is \nthe reponsability of the application to catch and handle such exceptions.</para>\n\n<para>\nOnce the computation is finished, a process calls leave() to leave the barrier. \nFirst it deletes its corresponding node, and then it gets the children of the root \nnode. If there is at least one child, then it waits for a notification (obs: note \nthat the second parameter of the call to getChildren() is true, meaning that \nZooKeeper has to set a watch on the the root node). Upon reception of a notification, \nit checks once more whether the root node has any child.</para>\n\n<programlisting>\n        /**\n         * Wait until all reach barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean leave() throws KeeperException, InterruptedException{\n            zk.delete(root + \"/\" + name, 0);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                        if (list.size() &gt; 0) {\n                            mutex.wait();\n                        } else {\n                            return true;\n                        }\n                    }\n                }\n        }\n    }\n</programlisting>\n</section>\n<section id=\"sc_producerConsumerQueues\"><title>Producer-Consumer Queues</title>\n<para>\nA producer-consumer queue is a distributed data estructure thata group of processes \nuse to generate and consume items. Producer processes create new elements and add \nthem to the queue. Consumer processes remove elements from the list, and process them. \nIn this implementation, the elements are simple integers. The queue is represented \nby a root node, and to add an element to the queue, a producer process creates a new node, \na child of the root node.\n</para>\n\n<para>\nThe following excerpt of code corresponds to the constructor of the object. As \nwith Barrier objects, it first calls the constructor of the parent class, SyncPrimitive, \nthat creates a ZooKeeper object if one doesn't exist. It then verifies if the root \nnode of the queue exists, and creates if it doesn't.\n</para>\n<programlisting>\n        /**\n         * Constructor of producer-consumer queue\n         *\n         * @param address\n         * @param name\n         */\n        Queue(String address, String name) {\n            super(address);\n            this.root = name;\n            // Create ZK node name\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n        }\n</programlisting>\n \n<para>\nA producer process calls \"produce()\" to add an element to the queue, and passes \nan integer as an argument. To add an element to the queue, the method creates a \nnew node using \"create()\", and uses the SEQUENCE flag to instruct ZooKeeper to \nappend the value of the sequencer counter associated to the root node. In this way, \nwe impose a total order on the elements of the queue, thus guaranteeing that the \noldest element of the queue is the next one consumed.\n</para>\n\n<programlisting>\n        /**\n         * Add element to the queue.\n         *\n         * @param i\n         * @return\n         */\n\n        boolean produce(int i) throws KeeperException, InterruptedException{\n            ByteBuffer b = ByteBuffer.allocate(4);\n            byte[] value;\n\n            // Add child with value i\n            b.putInt(i);\n            value = b.array();\n            zk.create(root + \"/element\", value, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT_SEQUENTIAL);\n\n            return true;\n        }\n</programlisting>\n<para>\nTo consume an element, a consumer process obtains the children of the root node, \nreads the node with smallest counter value, and returns the element. Note that \nif there is a conflict, then one of the two contending processes won't be able to \ndelete the node and the delete operation will throw an exception.</para>\n\n<para>\nA call to getChildren() returns the list of children in lexicographic order. \nAs lexicographic order does not necessary follow the numerical order of the counter \nvalues, we need to decide which element is the smallest. To decide which one has \nthe smallest counter value, we traverse the list, and remove the prefix \"element\" \nfrom each one.</para>\n\n<programlisting>\n        /**\n         * Remove first element from the queue.\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n        int consume() throws KeeperException, InterruptedException{\n            int retvalue = -1;\n            Stat stat = null;\n\n            // Get the first element available\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                    if (list.size() == 0) {\n                        System.out.println(\"Going to wait\");\n                        mutex.wait();\n                    } else {\n                        Integer min = new Integer(list.get(0).substring(7));\n                        for(String s : list){\n                            Integer tempValue = new Integer(s.substring(7));\n                            //System.out.println(\"Temporary value: \" + tempValue);\n                            if(tempValue &lt; min) min = tempValue;\n                        }\n                        System.out.println(\"Temporary value: \" + root + \"/element\" + min);\n                        byte[] b = zk.getData(root + \"/element\" + min,\n                                    false, stat);\n                        zk.delete(root + \"/element\" + min, 0);\n                        ByteBuffer buffer = ByteBuffer.wrap(b);\n                        retvalue = buffer.getInt();\n\n                        return retvalue;\n                    }\n                }\n            }\n        }\n    }\n</programlisting>\n \n</section>\n\n<section>\n<title>Complete example</title>\n<para>\nIn the following section you can find a complete command line application to demonstrate the above mentioned\nrecipes. Use the following command to run it.\n</para>\n<programlisting>\nZOOBINDIR=\"[path_to_distro]/bin\"\n. \"$ZOOBINDIR\"/zkEnv.sh\njava SyncPrimitive [Test Type] [ZK server] [No of elements] [Client type]\n</programlisting>\n\n<section>\n<title>Queue test</title>\n<para>Start a producer to create 100 elements</para>\n<programlisting>\njava SyncPrimitive qTest localhost 100 p\n</programlisting>\n\n<para>Start a consumer to consume 100 elements</para>\n<programlisting>\njava SyncPrimitive qTest localhost 100 c\n</programlisting>\n</section>\n\n<section>\n<title>Barrier test</title>\n<para>Start a barrier with 2 participants (start as many times as many participants you'd like to enter)</para>\n<programlisting>\njava SyncPrimitive bTest localhost 2\n</programlisting>\n</section>\n\n<section id=\"sc_sourceListing\"><title>Source Listing</title>\n<example id=\"eg_SyncPrimitive_java\">\n<title>SyncPrimitive.Java</title>\n<programlisting>\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.nio.ByteBuffer;\nimport java.util.List;\nimport java.util.Random;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\n\npublic class SyncPrimitive implements Watcher {\n\n    static ZooKeeper zk = null;\n    static Integer mutex;\n\n    String root;\n\n    SyncPrimitive(String address) {\n        if(zk == null){\n            try {\n                System.out.println(\"Starting ZK:\");\n                zk = new ZooKeeper(address, 3000, this);\n                mutex = new Integer(-1);\n                System.out.println(\"Finished starting ZK: \" + zk);\n            } catch (IOException e) {\n                System.out.println(e.toString());\n                zk = null;\n            }\n        }\n        //else mutex = new Integer(-1);\n    }\n\n    synchronized public void process(WatchedEvent event) {\n        synchronized (mutex) {\n            //System.out.println(\"Process: \" + event.getType());\n            mutex.notify();\n        }\n    }\n\n    /**\n     * Barrier\n     */\n    static public class Barrier extends SyncPrimitive {\n        int size;\n        String name;\n\n        /**\n         * Barrier constructor\n         *\n         * @param address\n         * @param root\n         * @param size\n         */\n        Barrier(String address, String root, int size) {\n            super(address);\n            this.root = root;\n            this.size = size;\n\n            // Create barrier node\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n\n            // My node name\n            try {\n                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());\n            } catch (UnknownHostException e) {\n                System.out.println(e.toString());\n            }\n\n        }\n\n        /**\n         * Join barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean enter() throws KeeperException, InterruptedException{\n            zk.create(root + \"/\" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL_SEQUENTIAL);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n\n                    if (list.size() &lt; size) {\n                        mutex.wait();\n                    } else {\n                        return true;\n                    }\n                }\n            }\n        }\n\n        /**\n         * Wait until all reach barrier\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n\n        boolean leave() throws KeeperException, InterruptedException{\n            zk.delete(root + \"/\" + name, 0);\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                        if (list.size() &gt; 0) {\n                            mutex.wait();\n                        } else {\n                            return true;\n                        }\n                    }\n                }\n        }\n    }\n\n    /**\n     * Producer-Consumer queue\n     */\n    static public class Queue extends SyncPrimitive {\n\n        /**\n         * Constructor of producer-consumer queue\n         *\n         * @param address\n         * @param name\n         */\n        Queue(String address, String name) {\n            super(address);\n            this.root = name;\n            // Create ZK node name\n            if (zk != null) {\n                try {\n                    Stat s = zk.exists(root, false);\n                    if (s == null) {\n                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                CreateMode.PERSISTENT);\n                    }\n                } catch (KeeperException e) {\n                    System.out\n                            .println(\"Keeper exception when instantiating queue: \"\n                                    + e.toString());\n                } catch (InterruptedException e) {\n                    System.out.println(\"Interrupted exception\");\n                }\n            }\n        }\n\n        /**\n         * Add element to the queue.\n         *\n         * @param i\n         * @return\n         */\n\n        boolean produce(int i) throws KeeperException, InterruptedException{\n            ByteBuffer b = ByteBuffer.allocate(4);\n            byte[] value;\n\n            // Add child with value i\n            b.putInt(i);\n            value = b.array();\n            zk.create(root + \"/element\", value, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT_SEQUENTIAL);\n\n            return true;\n        }\n\n\n        /**\n         * Remove first element from the queue.\n         *\n         * @return\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n        int consume() throws KeeperException, InterruptedException{\n            int retvalue = -1;\n            Stat stat = null;\n\n            // Get the first element available\n            while (true) {\n                synchronized (mutex) {\n                    List&lt;String&gt; list = zk.getChildren(root, true);\n                    if (list.size() == 0) {\n                        System.out.println(\"Going to wait\");\n                        mutex.wait();\n                    } else {\n                        Integer min = new Integer(list.get(0).substring(7));\n                        String minNode = list.get(0);\n                        for(String s : list){\n                            Integer tempValue = new Integer(s.substring(7));\n                            //System.out.println(\"Temporary value: \" + tempValue);\n                            if(tempValue &lt; min) {\n                                min = tempValue;\n                                minNode = s;\n                            }\n                        }\n                        System.out.println(\"Temporary value: \" + root + \"/\" + minNode);\n                        byte[] b = zk.getData(root + \"/\" + minNode,\n                        false, stat);\n                        zk.delete(root + \"/\" + minNode, 0);\n                        ByteBuffer buffer = ByteBuffer.wrap(b);\n                        retvalue = buffer.getInt();\n\n                        return retvalue;\n                    }\n                }\n            }\n        }\n    }\n\n    public static void main(String args[]) {\n        if (args[0].equals(\"qTest\"))\n            queueTest(args);\n        else\n            barrierTest(args);\n\n    }\n\n    public static void queueTest(String args[]) {\n        Queue q = new Queue(args[1], \"/app1\");\n\n        System.out.println(\"Input: \" + args[1]);\n        int i;\n        Integer max = new Integer(args[2]);\n\n        if (args[3].equals(\"p\")) {\n            System.out.println(\"Producer\");\n            for (i = 0; i &lt; max; i++)\n                try{\n                    q.produce(10 + i);\n                } catch (KeeperException e){\n\n                } catch (InterruptedException e){\n\n                }\n        } else {\n            System.out.println(\"Consumer\");\n\n            for (i = 0; i &lt; max; i++) {\n                try{\n                    int r = q.consume();\n                    System.out.println(\"Item: \" + r);\n                } catch (KeeperException e){\n                    i--;\n                } catch (InterruptedException e){\n\n                }\n            }\n        }\n    }\n\n    public static void barrierTest(String args[]) {\n        Barrier b = new Barrier(args[1], \"/b1\", new Integer(args[2]));\n        try{\n            boolean flag = b.enter();\n            System.out.println(\"Entered barrier: \" + args[2]);\n            if(!flag) System.out.println(\"Error when entering the barrier\");\n        } catch (KeeperException e){\n\n        } catch (InterruptedException e){\n\n        }\n\n        // Generate random integer\n        Random rand = new Random();\n        int r = rand.nextInt(100);\n        // Loop for rand iterations\n        for (int i = 0; i &lt; r; i++) {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n\n            }\n        }\n        try{\n            b.leave();\n        } catch (KeeperException e){\n\n        } catch (InterruptedException e){\n\n        }\n        System.out.println(\"Left barrier\");\n    }\n}\n</programlisting></example>\n</section>\n</section>\n\n</article>\n"
  },
  {
    "path": "src/docs/src/documentation/skinconf.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n\n<!--\nSkin configuration file. This file contains details of your project,\nwhich will be used to configure the chosen Forrest skin.\n-->\n\n<!DOCTYPE skinconfig PUBLIC \"-//APACHE//DTD Skin Configuration V0.6-3//EN\" \"http://forrest.apache.org/dtd/skinconfig-v06-3.dtd\">\n<skinconfig>\n  <!-- To enable lucene search add provider=\"lucene\" (default is google).\n    Add box-location=\"alt\" to move the search box to an alternate location\n    (if the skin supports it) and box-location=\"all\" to show it in all\n    available locations on the page.  Remove the <search> element to show\n    no search box. @domain will enable sitesearch for the specific domain with google.\n    In other words google will search the @domain for the query string.\n\n  -->\n  <search name=\"ZooKeeper\" domain=\"zookeeper.apache.org\" provider=\"google\"/>\n\n  <!-- Disable the print link? If enabled, invalid HTML 4.0.1 -->\n  <disable-print-link>true</disable-print-link>  \n  <!-- Disable the PDF link? -->\n  <disable-pdf-link>false</disable-pdf-link>\n  <!-- Disable the POD link? -->\n  <disable-pod-link>true</disable-pod-link>\n  <!-- Disable the Text link? FIXME: NOT YET IMPLEMENETED. -->\n  <disable-txt-link>true</disable-txt-link>\n  <!-- Disable the xml source link? -->\n  <!-- The xml source link makes it possible to access the xml rendition\n    of the source frim the html page, and to have it generated statically.\n    This can be used to enable other sites and services to reuse the\n    xml format for their uses. Keep this disabled if you don't want other\n    sites to easily reuse your pages.-->\n  <disable-xml-link>true</disable-xml-link>\n\n  <!-- Disable navigation icons on all external links? -->\n  <disable-external-link-image>true</disable-external-link-image>\n\n  <!-- Disable w3c compliance links? \n    Use e.g. align=\"center\" to move the compliance links logos to \n    an alternate location default is left.\n    (if the skin supports it) -->\n  <disable-compliance-links>true</disable-compliance-links>\n\n  <!-- Render mailto: links unrecognisable by spam harvesters? -->\n  <obfuscate-mail-links>false</obfuscate-mail-links>\n\n  <!-- Disable the javascript facility to change the font size -->\n  <disable-font-script>true</disable-font-script>\n\n  <!-- project logo -->\n  <project-name>ZooKeeper</project-name>\n  <project-description>ZooKeeper: distributed coordination</project-description>\n  <project-url>http://zookeeper.apache.org/</project-url>\n  <project-logo>images/zookeeper_small.gif</project-logo>\n\n  <!-- group logo -->\n  <group-name>Hadoop</group-name>\n  <group-description>Apache Hadoop</group-description>\n  <group-url>http://hadoop.apache.org/</group-url>\n  <group-logo>images/hadoop-logo.jpg</group-logo>\n\n  <!-- optional host logo (e.g. sourceforge logo)\n       default skin: renders it at the bottom-left corner -->\n  <host-url></host-url>\n  <host-logo></host-logo>\n\n  <!-- relative url of a favicon file, normally favicon.ico -->\n  <favicon-url>images/favicon.ico</favicon-url>\n\n  <!-- The following are used to construct a copyright statement -->\n  <year></year>\n  <vendor>The Apache Software Foundation.</vendor>\n  <copyright-link>http://www.apache.org/licenses/</copyright-link>\n\n  <!-- Some skins use this to form a 'breadcrumb trail' of links.\n    Use location=\"alt\" to move the trail to an alternate location\n    (if the skin supports it).\n\t  Omit the location attribute to display the trail in the default location.\n\t  Use location=\"none\" to not display the trail (if the skin supports it).\n    For some skins just set the attributes to blank.\n  -->\n   <trail>\n    <link1 name=\"Apache\" href=\"http://www.apache.org/\"/>\n    <link2 name=\"ZooKeeper\" href=\"http://zookeeper.apache.org/\"/>\n    <link3 name=\"ZooKeeper\" href=\"http://zookeeper.apache.org/\"/>\n  </trail>\n\n  <!-- Configure the TOC, i.e. the Table of Contents.\n  @max-depth\n   how many \"section\" levels need to be included in the\n   generated Table of Contents (TOC). \n  @min-sections\n   Minimum required to create a TOC.\n  @location (\"page\",\"menu\",\"page,menu\", \"none\")\n   Where to show the TOC.\n  -->\n  <toc max-depth=\"2\" min-sections=\"1\" location=\"page\"/>\n\n  <!-- Heading types can be clean|underlined|boxed  -->\n  <headings type=\"clean\"/>\n  \n  <!-- The optional feedback element will be used to construct a\n    feedback link in the footer with the page pathname appended:\n    <a href=\"@href\">{@to}</a>\n  <feedback to=\"webmaster@foo.com\"\n    href=\"mailto:webmaster@foo.com?subject=Feedback&#160;\" >\n    Send feedback about the website to:\n  </feedback>\n    -->\n  <!--\n    extra-css - here you can define custom css-elements that are \n    a. overriding the fallback elements or \n    b. adding the css definition from new elements that you may have \n       used in your documentation.\n    -->\n  <extra-css>\n    <!--Example of b. \n        To define the css definition of a new element that you may have used\n        in the class attribute of a <p> node. \n        e.g. <p class=\"quote\"/>\n    -->\n    p.quote {\n      margin-left: 2em;\n      padding: .5em;\n      background-color: #f0f0f0;\n      font-family: monospace;\n    }\n\n    pre.code {\n      margin-left: 0em;\n      padding: 0.5em;\n      background-color: #f0f0f0;\n      font-family: monospace;\n    }\n\n<!-- patricks\n    .code {\n      font-family: \"Courier New\", Courier, monospace;\n      font-size: 110%;\n    }\n-->\n\n  </extra-css>\n\n  <colors>\n  <!-- These values are used for the generated CSS files. -->\n\n  <!-- Krysalis -->\n<!--\n    <color name=\"header\"    value=\"#FFFFFF\"/>\n\n    <color name=\"tab-selected\" value=\"#a5b6c6\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"tab-unselected\" value=\"#F7F7F7\"  link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"subtab-selected\" value=\"#a5b6c6\"  link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"subtab-unselected\" value=\"#a5b6c6\"  link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n\n    <color name=\"heading\" value=\"#a5b6c6\"/>\n    <color name=\"subheading\" value=\"#CFDCED\"/>\n        \n    <color name=\"navstrip\" value=\"#CFDCED\" font=\"#000000\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"toolbox\" value=\"#a5b6c6\"/>\n    <color name=\"border\" value=\"#a5b6c6\"/>\n        \n    <color name=\"menu\" value=\"#F7F7F7\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>    \n    <color name=\"dialog\" value=\"#F7F7F7\"/>\n            \n    <color name=\"body\"    value=\"#ffffff\" link=\"#0F3660\" vlink=\"#009999\" hlink=\"#000066\"/>\n    \n    <color name=\"table\" value=\"#a5b6c6\"/>    \n    <color name=\"table-cell\" value=\"#ffffff\"/>    \n    <color name=\"highlight\" value=\"#ffff00\"/>\n    <color name=\"fixme\" value=\"#cc6600\"/>\n    <color name=\"note\" value=\"#006699\"/>\n    <color name=\"warning\" value=\"#990000\"/>\n    <color name=\"code\" value=\"#a5b6c6\"/>\n        \n    <color name=\"footer\" value=\"#a5b6c6\"/>\n-->\n  \n  <!-- Forrest -->\n<!--\n    <color name=\"header\"    value=\"#294563\"/>\n\n    <color name=\"tab-selected\" value=\"#4a6d8c\" link=\"#0F3660\" vlink=\"#0F3660\" hlink=\"#000066\"/>\n    <color name=\"tab-unselected\" value=\"#b5c7e7\" link=\"#0F3660\" vlink=\"#0F3660\" hlink=\"#000066\"/>\n    <color name=\"subtab-selected\" value=\"#4a6d8c\" link=\"#0F3660\" vlink=\"#0F3660\" hlink=\"#000066\"/>\n    <color name=\"subtab-unselected\" value=\"#4a6d8c\" link=\"#0F3660\" vlink=\"#0F3660\" hlink=\"#000066\"/>\n\n    <color name=\"heading\" value=\"#294563\"/>\n    <color name=\"subheading\" value=\"#4a6d8c\"/>\n        \n    <color name=\"navstrip\" value=\"#cedfef\" font=\"#0F3660\" link=\"#0F3660\" vlink=\"#0F3660\" hlink=\"#000066\"/>\n    <color name=\"toolbox\" value=\"#4a6d8c\"/>\n    <color name=\"border\" value=\"#294563\"/>\n    \n    <color name=\"menu\" value=\"#4a6d8c\" font=\"#cedfef\" link=\"#ffffff\" vlink=\"#ffffff\" hlink=\"#ffcf00\"/>    \n    <color name=\"dialog\" value=\"#4a6d8c\"/>\n            \n    <color name=\"body\" value=\"#ffffff\"  link=\"#0F3660\" vlink=\"#009999\" hlink=\"#000066\"/>\n    \n    <color name=\"table\" value=\"#7099C5\"/>    \n    <color name=\"table-cell\" value=\"#f0f0ff\"/>    \n    <color name=\"highlight\" value=\"#ffff00\"/>\n    <color name=\"fixme\" value=\"#cc6600\"/>\n    <color name=\"note\" value=\"#006699\"/>\n    <color name=\"warning\" value=\"#990000\"/>\n    <color name=\"code\" value=\"#CFDCED\"/>\n        \n    <color name=\"footer\" value=\"#cedfef\"/>\n-->\n\n  <!-- Collabnet --> \n<!--\n    <color name=\"header\"    value=\"#003366\"/>\n\n    <color name=\"tab-selected\" value=\"#dddddd\" link=\"#555555\" vlink=\"#555555\" hlink=\"#555555\"/>\n    <color name=\"tab-unselected\" value=\"#999999\" link=\"#ffffff\" vlink=\"#ffffff\" hlink=\"#ffffff\"/>\n    <color name=\"subtab-selected\" value=\"#cccccc\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"subtab-unselected\" value=\"#cccccc\" link=\"#555555\" vlink=\"#555555\" hlink=\"#555555\"/>\n\n    <color name=\"heading\" value=\"#003366\"/>\n    <color name=\"subheading\" value=\"#888888\"/>\n    \n    <color name=\"navstrip\" value=\"#dddddd\" font=\"#555555\"/>\n    <color name=\"toolbox\" value=\"#dddddd\" font=\"#555555\"/>\n    <color name=\"border\" value=\"#999999\"/>\n    \n    <color name=\"menu\" value=\"#ffffff\"/>    \n    <color name=\"dialog\" value=\"#eeeeee\"/>\n            \n    <color name=\"body\"      value=\"#ffffff\"/>\n    \n    <color name=\"table\" value=\"#ccc\"/>    \n    <color name=\"table-cell\" value=\"#ffffff\"/>   \n    <color name=\"highlight\" value=\"#ffff00\"/>\n    <color name=\"fixme\" value=\"#cc6600\"/>\n    <color name=\"note\" value=\"#006699\"/>\n    <color name=\"warning\" value=\"#990000\"/>\n    <color name=\"code\" value=\"#003366\"/>\n        \n    <color name=\"footer\" value=\"#ffffff\"/>\n-->\n <!-- Lenya using pelt-->\n<!--\n    <color name=\"header\" value=\"#ffffff\"/>\n\n    <color name=\"tab-selected\" value=\"#4C6C8F\" link=\"#ffffff\" vlink=\"#ffffff\" hlink=\"#ffffff\"/>\n    <color name=\"tab-unselected\" value=\"#E5E4D9\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"subtab-selected\" value=\"#000000\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n    <color name=\"subtab-unselected\" value=\"#E5E4D9\" link=\"#000000\" vlink=\"#000000\" hlink=\"#000000\"/>\n\n    <color name=\"heading\" value=\"#E5E4D9\"/>\n    <color name=\"subheading\" value=\"#000000\"/>\n    <color name=\"published\" value=\"#4C6C8F\" font=\"#FFFFFF\"/>\n    <color name=\"feedback\" value=\"#4C6C8F\" font=\"#FFFFFF\" align=\"center\"/>\n    <color name=\"navstrip\" value=\"#E5E4D9\" font=\"#000000\"/>\n\n    <color name=\"toolbox\" value=\"#CFDCED\" font=\"#000000\"/>\n\n    <color name=\"border\" value=\"#999999\"/>\n    <color name=\"menu\" value=\"#4C6C8F\" font=\"#ffffff\" link=\"#ffffff\" vlink=\"#ffffff\" hlink=\"#ffffff\" current=\"#FFCC33\" />    \n    <color name=\"menuheading\" value=\"#cfdced\" font=\"#000000\" />\n    <color name=\"searchbox\" value=\"#E5E4D9\" font=\"#000000\"/>\n    \n    <color name=\"dialog\" value=\"#CFDCED\"/>\n    <color name=\"body\" value=\"#ffffff\" />            \n    \n    <color name=\"table\" value=\"#ccc\"/>    \n    <color name=\"table-cell\" value=\"#ffffff\"/>   \n    <color name=\"highlight\" value=\"#ffff00\"/>\n    <color name=\"fixme\" value=\"#cc6600\"/>\n    <color name=\"note\" value=\"#006699\"/>\n    <color name=\"warning\" value=\"#990000\"/>\n    <color name=\"code\" value=\"#003366\"/>\n        \n    <color name=\"footer\" value=\"#E5E4D9\"/>\n-->\n  </colors>\n \n  <!-- Settings specific to PDF output. -->\n  <pdf>\n    <!-- \n       Supported page sizes are a0, a1, a2, a3, a4, a5, executive,\n       folio, legal, ledger, letter, quarto, tabloid (default letter).\n       Supported page orientations are portrait, landscape (default\n       portrait).\n       Supported text alignments are left, right, justify (default left).\n    -->\n    <page size=\"letter\" orientation=\"portrait\" text-align=\"left\"/>\n\n    <!--\n       Margins can be specified for top, bottom, inner, and outer\n       edges. If double-sided=\"false\", the inner edge is always left\n       and the outer is always right. If double-sided=\"true\", the\n       inner edge will be left on odd pages, right on even pages,\n       the outer edge vice versa.\n       Specified below are the default settings.\n    -->\n    <margins double-sided=\"false\">\n      <top>1in</top>\n      <bottom>1in</bottom>\n      <inner>1.25in</inner>\n      <outer>1in</outer>\n    </margins>\n\n    <!--\n      Print the URL text next to all links going outside the file\n    -->\n    <show-external-urls>false</show-external-urls>\n\n    <!--\n      Disable the copyright footer on each page of the PDF.\n      A footer is composed for each page. By default, a \"credit\" with role=pdf\n      will be used, as explained below. Otherwise a copyright statement\n      will be generated. This latter can be disabled.\n    -->\n    <disable-copyright-footer>false</disable-copyright-footer>\n  </pdf>\n\n  <!-- Credits are typically rendered as a set of small clickable\n    images in the page footer.\n    Use box-location=\"alt\" to move the credit to an alternate location\n    (if the skin supports it). \n  -->\n  <credits>\n    <credit box-location=\"alt\">\n      <name>Built with Apache Forrest</name>\n      <url>http://forrest.apache.org/</url>\n      <image>images/built-with-forrest-button.png</image>\n      <width>88</width>\n      <height>31</height>\n    </credit>\n    <!-- A credit with @role=\"pdf\" will be used to compose a footer\n     for each page in the PDF, using either \"name\" or \"url\" or both.\n    -->\n    <!--\n    <credit role=\"pdf\">\n      <name>Built with Apache Forrest</name>\n      <url>http://forrest.apache.org/</url>\n    </credit>\n    -->\n  </credits>\n\n</skinconfig>\n"
  },
  {
    "path": "src/docs/status.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  Copyright 2002-2004 The Apache Software Foundation\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<status>\n\n  <developers>\n    <person name=\"Joe Bloggs\"      email=\"joe@joescompany.org\"      id=\"JB\" />\n    <!-- Add more people here -->\n  </developers>\n\n  <changes>\n    <!-- Add new releases here -->\n    <release version=\"0.1\" date=\"unreleased\">\n      <!-- Some action types have associated images. By default, images are\n      defined for 'add', 'fix', 'remove', 'update' and 'hack'. If you add\n      src/documentation/resources/images/<foo>.jpg images, these will\n      automatically be used for entries of type <foo>. -->\n\n      <action dev=\"JB\" type=\"add\" context=\"admin\">\n        Initial Import\n      </action>\n      <!-- Sample action:\n      <action dev=\"JB\" type=\"fix\" due-to=\"Joe Contributor\"\n          due-to-email=\"joec@apache.org\" fixes-bug=\"123\">\n          Fixed a bug in the Foo class.\n        </action>\n        -->\n    </release>\n  </changes>\n\n  <todo>\n    <actions priority=\"high\">\n      <action context=\"docs\" dev=\"JB\">\n        Customize this template project with your project's details.  This\n        TODO list is generated from 'status.xml'.\n      </action>\n      <action context=\"docs\" dev=\"JB\">\n        Add lots of content.  XML content goes in\n        <code>src/documentation/content/xdocs</code>, or wherever the\n        <code>${project.xdocs-dir}</code> property (set in\n        <code>forrest.properties</code>) points.\n      </action>\n      <action context=\"feedback\" dev=\"JB\">\n        Mail <link\n          href=\"mailto:forrest-dev@xml.apache.org\">forrest-dev@xml.apache.org</link>\n        with feedback.\n      </action>\n    </actions>\n    <!-- Add todo items. @context is an arbitrary string. Eg:\n    <actions priority=\"high\">\n      <action context=\"code\" dev=\"SN\">\n      </action>\n    </actions>\n    <actions priority=\"medium\">\n      <action context=\"docs\" dev=\"open\">\n      </action>\n    </actions>\n    -->\n  </todo>\n\n</status>\n"
  },
  {
    "path": "src/java/OldChangeLog",
    "content": ""
  },
  {
    "path": "src/java/lib/cobertura/README.txt",
    "content": "Download the cobertura binary from the following location and unpack it into this directory. Run \"cobertura-report\" target from build.xml to generate coverage report.\n\nhttp://cobertura.sourceforge.net/download.html\n"
  },
  {
    "path": "src/java/lib/jdiff/zookeeper_3.1.1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n<!-- Generated by the JDiff Javadoc doclet -->\n<!-- (http://www.jdiff.org) -->\n<!-- on Wed Apr 22 05:04:00 UTC 2009 -->\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<api\n  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n  xsi:noNamespaceSchemaLocation='api.xsd'\n  name=\"zookeeper 3.1.1\"\n  jdversion=\"1.0.9\">\n\n<!--  Command line arguments =  -doclet jdiff.JDiff -docletpath /home/gkesavan/zk-3.1/src/java/lib/jdiff-1.0.9.jar:/home/gkesavan/zk-3.1/src/java/lib/xerces-1.4.4.jar -classpath /home/gkesavan/zk-3.1/src/java/lib/jdiff-1.0.9.jar:/home/gkesavan/zk-3.1/src/java/lib/junit-4.4.jar:/home/gkesavan/zk-3.1/src/java/lib/log4j-1.2.15.jar:/home/gkesavan/zk-3.1/src/java/lib/xerces-1.4.4.jar:/home/gkesavan/zk-3.1/build/classes -sourcepath /home/gkesavan/zk-3.1/src/java/main -apidir /home/gkesavan/zk-3.1/src/java/lib/jdiff -apiname zookeeper 3.1.1 -->\n<package name=\"org.apache.zookeeper\">\n  <!-- start interface org.apache.zookeeper.AsyncCallback -->\n  <interface name=\"AsyncCallback\"    abstract=\"true\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.ACLCallback -->\n  <interface name=\"AsyncCallback.ACLCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <param name=\"acl\" type=\"java.util.List\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.ACLCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.ChildrenCallback -->\n  <interface name=\"AsyncCallback.ChildrenCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <param name=\"children\" type=\"java.util.List\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.ChildrenCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.DataCallback -->\n  <interface name=\"AsyncCallback.DataCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <param name=\"data\" type=\"byte[]\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.DataCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.StatCallback -->\n  <interface name=\"AsyncCallback.StatCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.StatCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.StringCallback -->\n  <interface name=\"AsyncCallback.StringCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.StringCallback -->\n  <!-- start interface org.apache.zookeeper.AsyncCallback.VoidCallback -->\n  <interface name=\"AsyncCallback.VoidCallback\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.AsyncCallback\"/>\n    <method name=\"processResult\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"rc\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.AsyncCallback.VoidCallback -->\n  <!-- start class org.apache.zookeeper.ClientCnxn -->\n  <class name=\"ClientCnxn\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"ClientCnxn\" type=\"java.lang.String, int, org.apache.zookeeper.ZooKeeper, org.apache.zookeeper.ClientWatchManager\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n    </constructor>\n    <constructor name=\"ClientCnxn\" type=\"java.lang.String, int, org.apache.zookeeper.ZooKeeper, org.apache.zookeeper.ClientWatchManager, long, byte[]\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <doc>\n      <![CDATA[Creates a connection object. The actual network connect doesn't get\n established until needed.\n\n @param hosts\n                a comma separated list of hosts that can be connected to.\n @param sessionTimeout\n                the timeout for connections.\n @param zooKeeper\n                the zookeeper object that this connection is related to.\n @throws KeeperException\n @throws IOException]]>\n      </doc>\n    </constructor>\n    <method name=\"getSessionId\" return=\"long\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getSessionPasswd\" return=\"byte[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"toString\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"disconnect\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Shutdown the send/event threads. This method should not be called\n directly - rather it should be called as part of close operation. This\n method is primarily here to allow the tests to verify disconnection\n behavior.]]>\n      </doc>\n    </method>\n    <method name=\"close\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <doc>\n      <![CDATA[Close the connection, which includes; send session disconnect to the\n server, shutdown the send/event threads.\n \n @throws IOException]]>\n      </doc>\n    </method>\n    <method name=\"submitRequest\" return=\"org.apache.zookeeper.proto.ReplyHeader\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"h\" type=\"org.apache.zookeeper.proto.RequestHeader\"/>\n      <param name=\"request\" type=\"org.apache.jute.Record\"/>\n      <param name=\"response\" type=\"org.apache.jute.Record\"/>\n      <param name=\"watchRegistration\" type=\"org.apache.zookeeper.ZooKeeper.WatchRegistration\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n    </method>\n    <method name=\"addAuthInfo\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"scheme\" type=\"java.lang.String\"/>\n      <param name=\"auth\" type=\"byte[]\"/>\n    </method>\n    <field name=\"disableAutoWatchReset\" type=\"boolean\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This controls whether automatic watch resetting is enabled.\n Clients automatically reset watches during session reconnect, this\n option allows the client to turn off this behavior by setting\n the environment variable \"zookeeper.disableAutoWatchReset\" to \"true\"]]>\n      </doc>\n    </field>\n    <field name=\"packetLen\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <doc>\n    <![CDATA[This class manages the socket i/o for the client. ClientCnxn maintains a list\n of available servers to connect to and \"transparently\" switches servers it is\n connected to as needed.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.ClientCnxn -->\n  <!-- start interface org.apache.zookeeper.ClientWatchManager -->\n  <interface name=\"ClientWatchManager\"    abstract=\"true\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"materialize\" return=\"java.util.Set\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"state\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"/>\n      <param name=\"type\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <doc>\n      <![CDATA[Return a set of watchers that should be notified of the event. The \n manager must not notify the watcher(s), however it will update it's \n internal structure as if the watches had triggered. The intent being \n that the callee is now responsible for notifying the watchers of the \n event, possibly at some later time.\n \n @param state event state\n @param type event type\n @param path event path\n @return]]>\n      </doc>\n    </method>\n  </interface>\n  <!-- end interface org.apache.zookeeper.ClientWatchManager -->\n  <!-- start class org.apache.zookeeper.CreateMode -->\n  <class name=\"CreateMode\" extends=\"java.lang.Enum\"\n    abstract=\"false\"\n    static=\"false\" final=\"true\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"values\" return=\"org.apache.zookeeper.CreateMode[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"valueOf\" return=\"org.apache.zookeeper.CreateMode\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"isEphemeral\" return=\"boolean\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"isSequential\" return=\"boolean\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"toFlag\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"fromFlag\" return=\"org.apache.zookeeper.CreateMode\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"flag\" type=\"int\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <doc>\n      <![CDATA[Map an integer value to a CreateMode value]]>\n      </doc>\n    </method>\n    <field name=\"PERSISTENT\" type=\"org.apache.zookeeper.CreateMode\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The znode will not be automatically deleted upon client's disconnect.]]>\n      </doc>\n    </field>\n    <field name=\"PERSISTENT_SEQUENTIAL\" type=\"org.apache.zookeeper.CreateMode\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The znode will not be automatically deleted upon client's disconnect,\n and its name will be appended with a monotonically increasing number.]]>\n      </doc>\n    </field>\n    <field name=\"EPHEMERAL\" type=\"org.apache.zookeeper.CreateMode\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The znode will be deleted upon the client's disconnect.]]>\n      </doc>\n    </field>\n    <field name=\"EPHEMERAL_SEQUENTIAL\" type=\"org.apache.zookeeper.CreateMode\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The znode will be deleted upon the client's disconnect, and its name\n will be appended with a monotonically increasing number.]]>\n      </doc>\n    </field>\n    <doc>\n    <![CDATA[CreateMode value determines how the znode is created on ZooKeeper.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.CreateMode -->\n  <!-- start class org.apache.zookeeper.Environment -->\n  <class name=\"Environment\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"Environment\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"list\" return=\"java.util.List\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"logEnv\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"msg\" type=\"java.lang.String\"/>\n      <param name=\"log\" type=\"org.apache.log4j.Logger\"/>\n    </method>\n    <doc>\n    <![CDATA[Provide insight into the runtime environment.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.Environment -->\n  <!-- start class org.apache.zookeeper.Environment.Entry -->\n  <class name=\"Environment.Entry\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"Environment.Entry\" type=\"java.lang.String, java.lang.String\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"getKey\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getValue\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"toString\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n  </class>\n  <!-- end class org.apache.zookeeper.Environment.Entry -->\n  <!-- start class org.apache.zookeeper.KeeperException -->\n  <class name=\"KeeperException\" extends=\"java.lang.Exception\"\n    abstract=\"true\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"create\" return=\"org.apache.zookeeper.KeeperException\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"code\" type=\"org.apache.zookeeper.KeeperException.Code\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <doc>\n      <![CDATA[All non-specific keeper exceptions should be constructed via\n this factory method in order to guarantee consistency in error\n codes and such.  If you know the error code, then you should\n construct the special purpose exception directly.  That will\n allow you to have the most specific possible declarations of\n what exceptions might actually be thrown.\n\n @param code The error code.\n @param path The ZooKeeper path being operated on.\n @return The specialized exception, presumably to be thrown by\n  the caller.]]>\n      </doc>\n    </method>\n    <method name=\"create\" return=\"org.apache.zookeeper.KeeperException\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link #create(Code, String)}\n instead\">\n      <param name=\"code\" type=\"int\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link #create(Code, String)}\n instead]]>\n      </doc>\n    </method>\n    <method name=\"create\" return=\"org.apache.zookeeper.KeeperException\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link #create(Code)}\n instead\">\n      <param name=\"code\" type=\"int\"/>\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link #create(Code)}\n instead]]>\n      </doc>\n    </method>\n    <method name=\"create\" return=\"org.apache.zookeeper.KeeperException\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"code\" type=\"org.apache.zookeeper.KeeperException.Code\"/>\n      <doc>\n      <![CDATA[All non-specific keeper exceptions should be constructed via\n this factory method in order to guarantee consistency in error\n codes and such.  If you know the error code, then you should\n construct the special purpose exception directly.  That will\n allow you to have the most specific possible declarations of\n what exceptions might actually be thrown.\n\n @param code The error code of your new exception.  This will\n also determine the specific type of the exception that is\n returned.\n @return The specialized exception, presumably to be thrown by\n the caller.]]>\n      </doc>\n    </method>\n    <method name=\"setCode\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, exceptions should be immutable, this\n method should not be used\">\n      <param name=\"code\" type=\"int\"/>\n      <doc>\n      <![CDATA[Set the code for this exception\n @param code error code\n @deprecated deprecated in 3.1.0, exceptions should be immutable, this\n method should not be used]]>\n      </doc>\n    </method>\n    <method name=\"getCode\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link #code()} instead\">\n      <doc>\n      <![CDATA[Read the error code for this exception\n @return the error code for this exception\n @deprecated deprecated in 3.1.0, use {@link #code()} instead]]>\n      </doc>\n    </method>\n    <method name=\"code\" return=\"org.apache.zookeeper.KeeperException.Code\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Read the error Code for this exception\n @return the error Code for this exception]]>\n      </doc>\n    </method>\n    <method name=\"getPath\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Read the path for this exception\n @return the path associated with this error, null if none]]>\n      </doc>\n    </method>\n    <method name=\"getMessage\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException -->\n  <!-- start class org.apache.zookeeper.KeeperException.APIErrorException -->\n  <class name=\"KeeperException.APIErrorException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.APIErrorException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.APIERROR]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.APIErrorException -->\n  <!-- start class org.apache.zookeeper.KeeperException.AuthFailedException -->\n  <class name=\"KeeperException.AuthFailedException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.AuthFailedException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.AUTHFAILED]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.AuthFailedException -->\n  <!-- start class org.apache.zookeeper.KeeperException.BadArgumentsException -->\n  <class name=\"KeeperException.BadArgumentsException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.BadArgumentsException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.BADARGUMENTS]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.BadArgumentsException -->\n  <!-- start class org.apache.zookeeper.KeeperException.BadVersionException -->\n  <class name=\"KeeperException.BadVersionException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.BadVersionException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.BADVERSION]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.BadVersionException -->\n  <!-- start class org.apache.zookeeper.KeeperException.Code -->\n  <class name=\"KeeperException.Code\" extends=\"java.lang.Enum\"\n    abstract=\"false\"\n    static=\"true\" final=\"true\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.KeeperException.CodeDeprecated\"/>\n    <method name=\"values\" return=\"org.apache.zookeeper.KeeperException.Code[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"valueOf\" return=\"org.apache.zookeeper.KeeperException.Code\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"intValue\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Get the int value for a particular Code.\n @return error code as integer]]>\n      </doc>\n    </method>\n    <method name=\"get\" return=\"org.apache.zookeeper.KeeperException.Code\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"code\" type=\"int\"/>\n      <doc>\n      <![CDATA[Get the Code value for a particular integer error code\n @param code int error code\n @return Code value corresponding to specified int code, or null]]>\n      </doc>\n    </method>\n    <field name=\"OK\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Everything is OK]]>\n      </doc>\n    </field>\n    <field name=\"SYSTEMERROR\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[System and server-side errors.\n This is never thrown by the server, it shouldn't be used other than\n to indicate a range. Specifically error codes greater than this\n value, but lesser than {@link #APIERROR}, are system errors.]]>\n      </doc>\n    </field>\n    <field name=\"RUNTIMEINCONSISTENCY\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[A runtime inconsistency was found]]>\n      </doc>\n    </field>\n    <field name=\"DATAINCONSISTENCY\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[A data inconsistency was found]]>\n      </doc>\n    </field>\n    <field name=\"CONNECTIONLOSS\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Connection to the server has been lost]]>\n      </doc>\n    </field>\n    <field name=\"MARSHALLINGERROR\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Error while marshalling or unmarshalling data]]>\n      </doc>\n    </field>\n    <field name=\"UNIMPLEMENTED\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Operation is unimplemented]]>\n      </doc>\n    </field>\n    <field name=\"OPERATIONTIMEOUT\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Operation timeout]]>\n      </doc>\n    </field>\n    <field name=\"BADARGUMENTS\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Invalid arguments]]>\n      </doc>\n    </field>\n    <field name=\"APIERROR\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[API errors.\n This is never thrown by the server, it shouldn't be used other than\n to indicate a range. Specifically error codes greater than this\n value are API errors (while values less than this indicate a\n {@link #SYSTEMERROR}).]]>\n      </doc>\n    </field>\n    <field name=\"NONODE\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Node does not exist]]>\n      </doc>\n    </field>\n    <field name=\"NOAUTH\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Not authenticated]]>\n      </doc>\n    </field>\n    <field name=\"BADVERSION\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Version conflict]]>\n      </doc>\n    </field>\n    <field name=\"NOCHILDRENFOREPHEMERALS\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Ephemeral nodes may not have children]]>\n      </doc>\n    </field>\n    <field name=\"NODEEXISTS\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The node already exists]]>\n      </doc>\n    </field>\n    <field name=\"NOTEMPTY\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The node has children]]>\n      </doc>\n    </field>\n    <field name=\"SESSIONEXPIRED\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The session has been expired by the server]]>\n      </doc>\n    </field>\n    <field name=\"INVALIDCALLBACK\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Invalid callback specified]]>\n      </doc>\n    </field>\n    <field name=\"INVALIDACL\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Invalid ACL specified]]>\n      </doc>\n    </field>\n    <field name=\"AUTHFAILED\" type=\"org.apache.zookeeper.KeeperException.Code\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Client authentication failed]]>\n      </doc>\n    </field>\n    <doc>\n    <![CDATA[Codes which represent the various KeeperException\n types. This enum replaces the deprecated earlier static final int\n constants. The old, deprecated, values are in \"camel case\" while the new\n enum values are in all CAPS.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.Code -->\n  <!-- start interface org.apache.zookeeper.KeeperException.CodeDeprecated -->\n  <interface name=\"KeeperException.CodeDeprecated\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <field name=\"Ok\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#OK} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#OK} instead]]>\n      </doc>\n    </field>\n    <field name=\"SystemError\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#SYSTEMERROR} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#SYSTEMERROR} instead]]>\n      </doc>\n    </field>\n    <field name=\"RuntimeInconsistency\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use\n {@link Code#RUNTIMEINCONSISTENCY} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use\n {@link Code#RUNTIMEINCONSISTENCY} instead]]>\n      </doc>\n    </field>\n    <field name=\"DataInconsistency\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#DATAINCONSISTENCY}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#DATAINCONSISTENCY}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"ConnectionLoss\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#CONNECTIONLOSS}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#CONNECTIONLOSS}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"MarshallingError\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#MARSHALLINGERROR}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#MARSHALLINGERROR}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"Unimplemented\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#UNIMPLEMENTED}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#UNIMPLEMENTED}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"OperationTimeout\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#OPERATIONTIMEOUT}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#OPERATIONTIMEOUT}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"BadArguments\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#BADARGUMENTS}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#BADARGUMENTS}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"APIError\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#APIERROR} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#APIERROR} instead]]>\n      </doc>\n    </field>\n    <field name=\"NoNode\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#NONODE} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#NONODE} instead]]>\n      </doc>\n    </field>\n    <field name=\"NoAuth\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#NOAUTH} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#NOAUTH} instead]]>\n      </doc>\n    </field>\n    <field name=\"BadVersion\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#BADVERSION} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#BADVERSION} instead]]>\n      </doc>\n    </field>\n    <field name=\"NoChildrenForEphemerals\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use\n {@link Code#NOCHILDRENFOREPHEMERALS}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use\n {@link Code#NOCHILDRENFOREPHEMERALS}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"NodeExists\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#NODEEXISTS} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#NODEEXISTS} instead]]>\n      </doc>\n    </field>\n    <field name=\"NotEmpty\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#NOTEMPTY} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#NOTEMPTY} instead]]>\n      </doc>\n    </field>\n    <field name=\"SessionExpired\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#SESSIONEXPIRED} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#SESSIONEXPIRED} instead]]>\n      </doc>\n    </field>\n    <field name=\"InvalidCallback\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#INVALIDCALLBACK}\n instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#INVALIDCALLBACK}\n instead]]>\n      </doc>\n    </field>\n    <field name=\"InvalidACL\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#INVALIDACL} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#INVALIDACL} instead]]>\n      </doc>\n    </field>\n    <field name=\"AuthFailed\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"deprecated in 3.1.0, use {@link Code#AUTHFAILED} instead\">\n      <doc>\n      <![CDATA[@deprecated deprecated in 3.1.0, use {@link Code#AUTHFAILED} instead]]>\n      </doc>\n    </field>\n    <doc>\n    <![CDATA[This interface contains the original static final int constants\n which have now been replaced with an enumeration in Code. Do not\n reference this class directly, if necessary (legacy code) continue\n to access the constants through Code.\n Note: an interface is used here due to the fact that enums cannot\n reference constants defined within the same enum as said constants\n are considered initialized _after_ the enum itself. By using an\n interface as a super type this allows the deprecated constants to\n be initialized first and referenced when constructing the enums. I\n didn't want to have constants declared twice. This\n interface should be private, but it's declared public to enable\n javadoc to include in the user API spec.]]>\n    </doc>\n  </interface>\n  <!-- end interface org.apache.zookeeper.KeeperException.CodeDeprecated -->\n  <!-- start class org.apache.zookeeper.KeeperException.ConnectionLossException -->\n  <class name=\"KeeperException.ConnectionLossException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.ConnectionLossException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.CONNECTIONLOSS]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.ConnectionLossException -->\n  <!-- start class org.apache.zookeeper.KeeperException.DataInconsistencyException -->\n  <class name=\"KeeperException.DataInconsistencyException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.DataInconsistencyException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.DATAINCONSISTENCY]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.DataInconsistencyException -->\n  <!-- start class org.apache.zookeeper.KeeperException.InvalidACLException -->\n  <class name=\"KeeperException.InvalidACLException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.InvalidACLException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.INVALIDACL]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.InvalidACLException -->\n  <!-- start class org.apache.zookeeper.KeeperException.InvalidCallbackException -->\n  <class name=\"KeeperException.InvalidCallbackException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.InvalidCallbackException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.INVALIDCALLBACK]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.InvalidCallbackException -->\n  <!-- start class org.apache.zookeeper.KeeperException.MarshallingErrorException -->\n  <class name=\"KeeperException.MarshallingErrorException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.MarshallingErrorException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.MARSHALLINGERROR]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.MarshallingErrorException -->\n  <!-- start class org.apache.zookeeper.KeeperException.NoAuthException -->\n  <class name=\"KeeperException.NoAuthException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.NoAuthException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.NOAUTH]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.NoAuthException -->\n  <!-- start class org.apache.zookeeper.KeeperException.NoChildrenForEphemeralsException -->\n  <class name=\"KeeperException.NoChildrenForEphemeralsException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.NoChildrenForEphemeralsException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.NOCHILDRENFOREPHEMERALS]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.NoChildrenForEphemeralsException -->\n  <!-- start class org.apache.zookeeper.KeeperException.NodeExistsException -->\n  <class name=\"KeeperException.NodeExistsException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.NodeExistsException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.NODEEXISTS]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.NodeExistsException -->\n  <!-- start class org.apache.zookeeper.KeeperException.NoNodeException -->\n  <class name=\"KeeperException.NoNodeException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.NoNodeException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.NONODE]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.NoNodeException -->\n  <!-- start class org.apache.zookeeper.KeeperException.NotEmptyException -->\n  <class name=\"KeeperException.NotEmptyException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.NotEmptyException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.NOTEMPTY]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.NotEmptyException -->\n  <!-- start class org.apache.zookeeper.KeeperException.OperationTimeoutException -->\n  <class name=\"KeeperException.OperationTimeoutException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.OperationTimeoutException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.OPERATIONTIMEOUT]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.OperationTimeoutException -->\n  <!-- start class org.apache.zookeeper.KeeperException.RuntimeInconsistencyException -->\n  <class name=\"KeeperException.RuntimeInconsistencyException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.RuntimeInconsistencyException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.RUNTIMEINCONSISTENCY]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.RuntimeInconsistencyException -->\n  <!-- start class org.apache.zookeeper.KeeperException.SessionExpiredException -->\n  <class name=\"KeeperException.SessionExpiredException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.SessionExpiredException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.SESSIONEXPIRED]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.SessionExpiredException -->\n  <!-- start class org.apache.zookeeper.KeeperException.SystemErrorException -->\n  <class name=\"KeeperException.SystemErrorException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.SystemErrorException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.SYSTEMERROR]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.SystemErrorException -->\n  <!-- start class org.apache.zookeeper.KeeperException.UnimplementedException -->\n  <class name=\"KeeperException.UnimplementedException\" extends=\"org.apache.zookeeper.KeeperException\"\n    abstract=\"false\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"KeeperException.UnimplementedException\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <doc>\n    <![CDATA[@see Code.UNIMPLEMENTED]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.KeeperException.UnimplementedException -->\n  <!-- start class org.apache.zookeeper.Quotas -->\n  <class name=\"Quotas\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"Quotas\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"quotaPath\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <doc>\n      <![CDATA[return the quota path associated with this\n prefix\n @param path the actual path in zookeeper.\n @return the limit quota path]]>\n      </doc>\n    </method>\n    <method name=\"statPath\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <doc>\n      <![CDATA[return the stat quota path associated with this\n prefix.\n @param path the actual path in zookeeper\n @return the stat quota path]]>\n      </doc>\n    </method>\n    <field name=\"procZookeeper\" type=\"java.lang.String\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[the zookeeper nodes that acts as the management and status node]]>\n      </doc>\n    </field>\n    <field name=\"quotaZookeeper\" type=\"java.lang.String\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[the zookeeper quota node that acts as the quota\n management node for zookeeper]]>\n      </doc>\n    </field>\n    <field name=\"limitNode\" type=\"java.lang.String\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[the limit node that has the limit of\n a subtree]]>\n      </doc>\n    </field>\n    <field name=\"statNode\" type=\"java.lang.String\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[the stat node that monitors the limit of\n a subtree.]]>\n      </doc>\n    </field>\n    <doc>\n    <![CDATA[this class manages quotas\n and has many other utils\n for quota]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.Quotas -->\n  <!-- start class org.apache.zookeeper.ServerAdminClient -->\n  <class name=\"ServerAdminClient\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"ServerAdminClient\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"ruok\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n    </method>\n    <method name=\"dump\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n    </method>\n    <method name=\"stat\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n    </method>\n    <method name=\"kill\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n    </method>\n    <method name=\"setTraceMask\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n      <param name=\"traceMaskStr\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"getTraceMask\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"host\" type=\"java.lang.String\"/>\n      <param name=\"port\" type=\"int\"/>\n    </method>\n    <method name=\"main\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"args\" type=\"java.lang.String[]\"/>\n    </method>\n  </class>\n  <!-- end class org.apache.zookeeper.ServerAdminClient -->\n  <!-- start class org.apache.zookeeper.StatsTrack -->\n  <class name=\"StatsTrack\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"StatsTrack\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[a default constructor for\n stats]]>\n      </doc>\n    </constructor>\n    <constructor name=\"StatsTrack\" type=\"java.lang.String\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[the stat string should be of the form count=int,bytes=long\n if stats is called with null the count and bytes are initialized\n to -1.\n @param stats the stat string to be intialized with]]>\n      </doc>\n    </constructor>\n    <method name=\"getCount\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[get the count of nodes allowed as part of quota\n\n @return the count as part of this string]]>\n      </doc>\n    </method>\n    <method name=\"setCount\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"count\" type=\"int\"/>\n      <doc>\n      <![CDATA[set the count for this stat tracker.\n\n @param count\n            the count to set with]]>\n      </doc>\n    </method>\n    <method name=\"getBytes\" return=\"long\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[get the count of bytes allowed as part of quota\n\n @return the bytes as part of this string]]>\n      </doc>\n    </method>\n    <method name=\"setBytes\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"bytes\" type=\"long\"/>\n      <doc>\n      <![CDATA[set teh bytes for this stat tracker.\n\n @param bytes\n            the bytes to set with]]>\n      </doc>\n    </method>\n    <method name=\"toString\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <doc>\n    <![CDATA[a class that represents the stats associated with quotas]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.StatsTrack -->\n  <!-- start class org.apache.zookeeper.Version -->\n  <class name=\"Version\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <implements name=\"org.apache.zookeeper.version.Info\"/>\n    <constructor name=\"Version\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"getRevision\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getBuildDate\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getVersion\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getVersionRevision\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getFullVersion\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"printUsage\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"main\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"args\" type=\"java.lang.String[]\"/>\n      <doc>\n      <![CDATA[Prints the current version, revision and build date to the standard out.\n \n @param args\n            <ul>\n            <li> --short - prints a short version string \"1.2.3\"\n            <li> --revision - prints a short version string with the SVN\n            repository revision \"1.2.3-94\"\n            <li> --full - prints the revision and the build date\n            </ul>]]>\n      </doc>\n    </method>\n  </class>\n  <!-- end class org.apache.zookeeper.Version -->\n  <!-- start class org.apache.zookeeper.WatchedEvent -->\n  <class name=\"WatchedEvent\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"WatchedEvent\" type=\"org.apache.zookeeper.Watcher.Event.EventType, org.apache.zookeeper.Watcher.Event.KeeperState, java.lang.String\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Create a WatchedEvent with specified type, state and path]]>\n      </doc>\n    </constructor>\n    <constructor name=\"WatchedEvent\" type=\"org.apache.zookeeper.proto.WatcherEvent\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Convert a WatcherEvent sent over the wire into a full-fledged WatcherEvent]]>\n      </doc>\n    </constructor>\n    <method name=\"getState\" return=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getType\" return=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getPath\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"toString\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"getWrapper\" return=\"org.apache.zookeeper.proto.WatcherEvent\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Convert WatchedEvent to type that can be sent over network]]>\n      </doc>\n    </method>\n    <doc>\n    <![CDATA[A WatchedEvent represents a change on the ZooKeeper that a Watcher\n  is able to respond to.  The WatchedEvent includes exactly what happened,\n  the current state of the ZooKeeper, and the path of the znode that\n  was involved in the event.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.WatchedEvent -->\n  <!-- start interface org.apache.zookeeper.Watcher -->\n  <interface name=\"Watcher\"    abstract=\"true\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"process\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"event\" type=\"org.apache.zookeeper.WatchedEvent\"/>\n    </method>\n    <doc>\n    <![CDATA[This interface specifies the public interface an event handler class must\n implement. A ZooKeeper client will get various events from the ZooKeepr\n server it connects to. An application using such a client handles these\n events by registering a callback object with the client. The callback object\n is expected to be an instance of a class that implements Watcher interface.]]>\n    </doc>\n  </interface>\n  <!-- end interface org.apache.zookeeper.Watcher -->\n  <!-- start interface org.apache.zookeeper.Watcher.Event -->\n  <interface name=\"Watcher.Event\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <doc>\n    <![CDATA[This interface defines the possible states an Event may represent]]>\n    </doc>\n  </interface>\n  <!-- end interface org.apache.zookeeper.Watcher.Event -->\n  <!-- start class org.apache.zookeeper.Watcher.Event.EventType -->\n  <class name=\"Watcher.Event.EventType\" extends=\"java.lang.Enum\"\n    abstract=\"false\"\n    static=\"true\" final=\"true\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"values\" return=\"org.apache.zookeeper.Watcher.Event.EventType[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"valueOf\" return=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"getIntValue\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"fromInt\" return=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"intValue\" type=\"int\"/>\n    </method>\n    <field name=\"None\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"NodeCreated\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"NodeDeleted\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"NodeDataChanged\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"NodeChildrenChanged\" type=\"org.apache.zookeeper.Watcher.Event.EventType\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <doc>\n    <![CDATA[Enumeration of types of events that may occur on the ZooKeeper]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.Watcher.Event.EventType -->\n  <!-- start class org.apache.zookeeper.Watcher.Event.KeeperState -->\n  <class name=\"Watcher.Event.KeeperState\" extends=\"java.lang.Enum\"\n    abstract=\"false\"\n    static=\"true\" final=\"true\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"values\" return=\"org.apache.zookeeper.Watcher.Event.KeeperState[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"valueOf\" return=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"getIntValue\" return=\"int\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"fromInt\" return=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"intValue\" type=\"int\"/>\n    </method>\n    <field name=\"Unknown\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Unused, this state is never generated by the server]]>\n      </doc>\n    </field>\n    <field name=\"Disconnected\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The client is in the disconnected state - it is not connected\n to any server in the ensemble.]]>\n      </doc>\n    </field>\n    <field name=\"NoSyncConnected\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[Unused, this state is never generated by the server]]>\n      </doc>\n    </field>\n    <field name=\"SyncConnected\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The client is in the connected state - it is connected\n to a server in the ensemble (one of the servers specified\n in the host connection parameter during ZooKeeper client\n creation).]]>\n      </doc>\n    </field>\n    <field name=\"Expired\" type=\"org.apache.zookeeper.Watcher.Event.KeeperState\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The serving cluster has expired this session. The ZooKeeper\n client connection (the session) is no longer valid. You must\n create a new client connection (instantiate a new ZooKeeper\n instance) if you with to access the ensemble.]]>\n      </doc>\n    </field>\n    <doc>\n    <![CDATA[Enumeration of states the ZooKeeper may be at the event]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.Watcher.Event.KeeperState -->\n  <!-- start class org.apache.zookeeper.ZooDefs -->\n  <class name=\"ZooDefs\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"ZooDefs\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <field name=\"opNames\" type=\"java.lang.String[]\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n  </class>\n  <!-- end class org.apache.zookeeper.ZooDefs -->\n  <!-- start interface org.apache.zookeeper.ZooDefs.Ids -->\n  <interface name=\"ZooDefs.Ids\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <field name=\"ANYONE_ID_UNSAFE\" type=\"org.apache.zookeeper.data.Id\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This Id represents anyone.]]>\n      </doc>\n    </field>\n    <field name=\"AUTH_IDS\" type=\"org.apache.zookeeper.data.Id\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This Id is only usable to set ACLs. It will get substituted with the\n Id's the client authenticated with.]]>\n      </doc>\n    </field>\n    <field name=\"OPEN_ACL_UNSAFE\" type=\"java.util.ArrayList\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This is a completely open ACL with the exception of ADMIN permission.]]>\n      </doc>\n    </field>\n    <field name=\"CREATOR_ALL_ACL\" type=\"java.util.ArrayList\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This ACL gives the creators authentication id's all permissions.]]>\n      </doc>\n    </field>\n    <field name=\"READ_ACL_UNSAFE\" type=\"java.util.ArrayList\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[This ACL gives the world the ability to read.]]>\n      </doc>\n    </field>\n  </interface>\n  <!-- end interface org.apache.zookeeper.ZooDefs.Ids -->\n  <!-- start interface org.apache.zookeeper.ZooDefs.OpCode -->\n  <interface name=\"ZooDefs.OpCode\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <field name=\"notification\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"create\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"delete\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"exists\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"getData\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"setData\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"getACL\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"setACL\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"getChildren\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"sync\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"ping\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"auth\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"setWatches\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"createSession\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"closeSession\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"error\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n  </interface>\n  <!-- end interface org.apache.zookeeper.ZooDefs.OpCode -->\n  <!-- start interface org.apache.zookeeper.ZooDefs.Perms -->\n  <interface name=\"ZooDefs.Perms\"    abstract=\"true\"\n    static=\"true\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <field name=\"READ\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"WRITE\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"CREATE\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"DELETE\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"ADMIN\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"ALL\" type=\"int\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n  </interface>\n  <!-- end interface org.apache.zookeeper.ZooDefs.Perms -->\n  <!-- start class org.apache.zookeeper.ZooKeeper -->\n  <class name=\"ZooKeeper\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"ZooKeeper\" type=\"java.lang.String, int, org.apache.zookeeper.Watcher\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <doc>\n      <![CDATA[To create a client(ZooKeeper) object, the application needs to pass a\n string containing a comma separated list of host:port pairs, each \n corresponding to a ZooKeeper server.\n <p>\n The client object will pick an arbitrary server and try to connect to it.\n If failed, it will try the next one in the list, until a connection is\n established, or all the servers have been tried.\n\n @param host\n            comma separated host:port pairs, each corresponding to a zk\n            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"\n @param sessionTimeout\n            session timeout in milliseconds\n @param watcher\n            a watcher object which will be notified of state changes, may\n            also be notified for node events\n\n @throws IOException in cases of network failure]]>\n      </doc>\n    </constructor>\n    <constructor name=\"ZooKeeper\" type=\"java.lang.String, int, org.apache.zookeeper.Watcher, long, byte[]\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <doc>\n      <![CDATA[To create a client(ZooKeeper) object, the application needs to pass a\n string containing a comma separated list of host:port pairs, each\n corresponding to a ZooKeeper server.\n <p>\n The client object will pick an arbitrary server and try to connect to it.\n If failed, it will try the next one in the list, until a connection is\n established, or all the servers have been tried.\n <p>\n Use {@link #getSessionId} and {@link #getSessionPasswd} on an established\n client connection, these values must be passed as sessionId and\n sessionPasswd respectively if reconnecting. Otherwise, if not\n reconnecting, use the other constructor which does not require these\n parameters.\n\n @param host\n            comma separated host:port pairs, each corresponding to a zk\n            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"\n @param sessionTimeout\n            session timeout in milliseconds\n @param watcher\n            a watcher object which will be notified of state changes, may\n            also be notified for node events\n @param sessionId\n            specific session id to use if reconnecting\n @param sessionPasswd\n            password for this session\n\n @throws IOException in cases of network failure]]>\n      </doc>\n    </constructor>\n    <method name=\"getSessionId\" return=\"long\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The session id for this ZooKeeper client instance. The value returned is\n not valid until the client connects to a server and may change after a\n re-connect.\n\n @return current session id]]>\n      </doc>\n    </method>\n    <method name=\"getSessionPasswd\" return=\"byte[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <doc>\n      <![CDATA[The session password for this ZooKeeper client instance. The value\n returned is not valid until the client connects to a server and may\n change after a re-connect.\n\n @return current session password]]>\n      </doc>\n    </method>\n    <method name=\"addAuthInfo\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"scheme\" type=\"java.lang.String\"/>\n      <param name=\"auth\" type=\"byte[]\"/>\n    </method>\n    <method name=\"register\"\n      abstract=\"false\" native=\"false\" synchronized=\"true\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n    </method>\n    <method name=\"close\"\n      abstract=\"false\" native=\"false\" synchronized=\"true\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Close this client object. Once the client is closed, its session becomes\n invalid. All the ephemeral nodes in the ZooKeeper server associated with\n the session will be removed. The watches left on those nodes (and on\n their parents) will be triggered.\n\n @throws InterruptedException\n\n @throws IOException\n @throws InterruptedException]]>\n      </doc>\n    </method>\n    <method name=\"create\" return=\"java.lang.String\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"data\" type=\"byte[]\"/>\n      <param name=\"acl\" type=\"java.util.List\"/>\n      <param name=\"createMode\" type=\"org.apache.zookeeper.CreateMode\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Create a node with the given path. The node data will be the given data,\n and node acl will be the given acl.\n <p>\n The flags argument specifies whether the created node will be ephemeral\n or not.\n <p>\n An ephemeral node will be removed by the ZooKeeper automatically when the\n session associated with the creation of the node expires.\n <p>\n The flags argument can also specify to create a sequential node. The\n actual path name of a sequential node will be the given path plus a\n suffix \"_i\" where i is the current sequential number of the node. Once\n such a node is created, the sequential number will be incremented by one.\n <p>\n If a node with the same actual path already exists in the ZooKeeper, a\n KeeperException with error code KeeperException.NodeExists will be\n thrown. Note that since a different actual path is used for each\n invocation of creating sequential node with the same path argument, the\n call will never throw \"file exists\" KeeperException.\n <p>\n If the parent node does not exist in the ZooKeeper, a KeeperException\n with error code KeeperException.NoNode will be thrown.\n <p>\n An ephemeral node cannot have children. If the parent node of the given\n path is ephemeral, a KeeperException with error code\n KeeperException.NoChildrenForEphemerals will be thrown.\n <p>\n This operation, if successful, will trigger all the watches left on the\n node of the given path by exists and getData API calls, and the watches\n left on the parent node by getChildren API calls.\n <p>\n If a node is created successfully, the ZooKeeper server will trigger the\n watches on the path left by exists calls, and the watches on the parent\n of the node by getChildren calls.\n <p>\n The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n Arrays larger than this will cause a KeeperExecption to be thrown.\n\n @param path\n                the path for the node\n @param data\n                the initial data for the node\n @param acl\n                the acl for the node\n @param flags\n                specifying whether the node to be created is ephemeral\n                and/or sequential\n @return the actual path of the created node\n @throws KeeperException if the server returns a non-zero error code\n @throws org.apache.zookeeper.KeeperException.InvalidACLException if the ACL is invalid\n @throws InterruptedException if the transaction is interrupted\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"validatePath\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <exception name=\"IllegalArgumentException\" type=\"java.lang.IllegalArgumentException\"/>\n      <doc>\n      <![CDATA[Validate the provided znode path string\n @param path znode path string\n @throws IllegalArgumentException if the path is invalid]]>\n      </doc>\n    </method>\n    <method name=\"create\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"data\" type=\"byte[]\"/>\n      <param name=\"acl\" type=\"java.util.List\"/>\n      <param name=\"createMode\" type=\"org.apache.zookeeper.CreateMode\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.StringCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of create. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #create(String, byte[], List<ACL>, CreateMode)]]>\n      </doc>\n    </method>\n    <method name=\"delete\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"version\" type=\"int\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <doc>\n      <![CDATA[Delete the node with the given path. The call will succeed if such a node\n exists, and the given version matches the node's version (if the given\n version is -1, it matches any node's versions).\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if the nodes does not exist.\n <p>\n A KeeperException with error code KeeperException.BadVersion will be\n thrown if the given version does not match the node's version.\n <p>\n A KeeperException with error code KeeperException.NotEmpty will be thrown\n if the node has children.\n <p>\n This operation, if successful, will trigger all the watches on the node\n of the given path left by exists API calls, and the watches on the parent\n node left by getChildren API calls.\n\n @param path\n                the path of the node to be deleted.\n @param version\n                the expected node version.\n @throws InterruptedException IF the server transaction is interrupted\n @throws KeeperException If the server signals an error with a non-zero return code.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"delete\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"version\" type=\"int\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.VoidCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of delete. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #delete(String, int)]]>\n      </doc>\n    </method>\n    <method name=\"exists\" return=\"org.apache.zookeeper.data.Stat\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the stat of the node of the given path. Return null if no such a\n node exists.\n <p>\n If the watch is non-null and the call is successful (no exception is thrown),\n a watch will be left on the node with the given path. The watch will be\n triggered by a successful operation that creates/delete the node or sets\n the data on the node.\n\n @param path the node path\n @param watcher explicit watcher\n @return the stat of the node of the given path; return null if no such a\n         node exists.\n @throws KeeperException If the server signals an error\n @throws InterruptedException If the server transaction is interrupted.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"exists\" return=\"org.apache.zookeeper.data.Stat\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the stat of the node of the given path. Return null if no such a\n node exists.\n <p>\n If the watch is true and the call is successful (no exception is thrown),\n a watch will be left on the node with the given path. The watch will be\n triggered by a successful operation that creates/delete the node or sets\n the data on the node.\n\n @param path\n                the node path\n @param watch\n                whether need to watch this node\n @return the stat of the node of the given path; return null if no such a\n         node exists.\n @throws KeeperException If the server signals an error\n @throws InterruptedException If the server transaction is interrupted.]]>\n      </doc>\n    </method>\n    <method name=\"exists\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.StatCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of exists. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #exists(String, boolean)]]>\n      </doc>\n    </method>\n    <method name=\"exists\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.StatCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of exists. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #exists(String, boolean)]]>\n      </doc>\n    </method>\n    <method name=\"getData\" return=\"byte[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the data and the stat of the node of the given path.\n <p>\n If the watch is non-null and the call is successful (no exception is\n thrown), a watch will be left on the node with the given path. The watch\n will be triggered by a successful operation that sets data on the node, or\n deletes the node.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n\n @param path the given path\n @param watcher explicit watcher\n @param stat the stat of the node\n @return the data of the node\n @throws KeeperException If the server signals an error with a non-zero error code\n @throws InterruptedException If the server transaction is interrupted.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"getData\" return=\"byte[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the data and the stat of the node of the given path.\n <p>\n If the watch is true and the call is successful (no exception is\n thrown), a watch will be left on the node with the given path. The watch\n will be triggered by a successful operation that sets data on the node, or\n deletes the node.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n\n @param path the given path\n @param watch whether need to watch this node\n @param stat the stat of the node\n @return the data of the node\n @throws KeeperException If the server signals an error with a non-zero error code\n @throws InterruptedException If the server transaction is interrupted.]]>\n      </doc>\n    </method>\n    <method name=\"getData\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.DataCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of getData. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #getData(String, Watcher, Stat)]]>\n      </doc>\n    </method>\n    <method name=\"getData\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.DataCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of getData. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #getData(String, boolean, Stat)]]>\n      </doc>\n    </method>\n    <method name=\"setData\" return=\"org.apache.zookeeper.data.Stat\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"data\" type=\"byte[]\"/>\n      <param name=\"version\" type=\"int\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Set the data for the node of the given path if such a node exists and the\n given version matches the version of the node (if the given version is\n -1, it matches any node's versions). Return the stat of the node.\n <p>\n This operation, if successful, will trigger all the watches on the node\n of the given path left by getData calls.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n <p>\n A KeeperException with error code KeeperException.BadVersion will be\n thrown if the given version does not match the node's version.\n <p>\n The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n Arrays larger than this will cause a KeeperExecption to be thrown.\n\n @param path\n                the path of the node\n @param data\n                the data to set\n @param version\n                the expected matching version\n @return the state of the node\n @throws InterruptedException If the server transaction is interrupted.\n @throws KeeperException If the server signals an error with a non-zero error code.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"setData\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"data\" type=\"byte[]\"/>\n      <param name=\"version\" type=\"int\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.StatCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of setData. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #setData(String, byte[], int)]]>\n      </doc>\n    </method>\n    <method name=\"getACL\" return=\"java.util.List\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the ACL and stat of the node of the given path.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n\n @param path\n                the given path for the node\n @param stat\n                the stat of the node will be copied to this parameter.\n @return the ACL array of the given node.\n @throws InterruptedException If the server transaction is interrupted.\n @throws KeeperException If the server signals an error with a non-zero error code.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"getACL\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"stat\" type=\"org.apache.zookeeper.data.Stat\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.ACLCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of getACL. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #getACL(String, Stat)]]>\n      </doc>\n    </method>\n    <method name=\"setACL\" return=\"org.apache.zookeeper.data.Stat\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"acl\" type=\"java.util.List\"/>\n      <param name=\"version\" type=\"int\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Set the ACL for the node of the given path if such a node exists and the\n given version matches the version of the node. Return the stat of the\n node.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n <p>\n A KeeperException with error code KeeperException.BadVersion will be\n thrown if the given version does not match the node's version.\n\n @param path\n @param acl\n @param version\n @return the stat of the node.\n @throws InterruptedException If the server transaction is interrupted.\n @throws KeeperException If the server signals an error with a non-zero error code.\n @throws org.apache.zookeeper.KeeperException.InvalidACLException If the acl is invalide.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"setACL\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"acl\" type=\"java.util.List\"/>\n      <param name=\"version\" type=\"int\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.StatCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of setACL. The request doesn't actually until\n the asynchronous callback is called.\n\n @see #setACL(String, List, int)]]>\n      </doc>\n    </method>\n    <method name=\"getChildren\" return=\"java.util.List\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the list of the children of the node of the given path.\n <p>\n If the watch is non-null and the call is successful (no exception is thrown),\n a watch will be left on the node with the given path. The watch willbe\n triggered by a successful operation that deletes the node of the given\n path or creates/delete a child under the node.\n <p>\n The list of children returned is not sorted and no guarantee is provided\n as to its natural or lexical order.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n\n @param path\n @param watcher explicit watcher\n @return an unordered array of children of the node with the given path\n @throws InterruptedException If the server transaction is interrupted.\n @throws KeeperException If the server signals an error with a non-zero error code.\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"getChildren\" return=\"java.util.List\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[Return the list of the children of the node of the given path.\n <p>\n If the watch is true and the call is successful (no exception is thrown),\n a watch will be left on the node with the given path. The watch willbe\n triggered by a successful operation that deletes the node of the given\n path or creates/delete a child under the node.\n <p>\n The list of children returned is not sorted and no guarantee is provided\n as to its natural or lexical order.\n <p>\n A KeeperException with error code KeeperException.NoNode will be thrown\n if no node with the given path exists.\n\n @param path\n @param watch\n @return an unordered array of children of the node with the given path\n @throws InterruptedException If the server transaction is interrupted.\n @throws KeeperException If the server signals an error with a non-zero error code.]]>\n      </doc>\n    </method>\n    <method name=\"getChildren\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watcher\" type=\"org.apache.zookeeper.Watcher\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.ChildrenCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of getChildren. The request doesn't actually\n until the asynchronous callback is called.\n\n @see #getChildren(String, Watcher)]]>\n      </doc>\n    </method>\n    <method name=\"getChildren\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"watch\" type=\"boolean\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.ChildrenCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[The Asynchronous version of getChildren. The request doesn't actually\n until the asynchronous callback is called.\n\n @see #getChildren(String, boolean)]]>\n      </doc>\n    </method>\n    <method name=\"sync\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"cb\" type=\"org.apache.zookeeper.AsyncCallback.VoidCallback\"/>\n      <param name=\"ctx\" type=\"java.lang.Object\"/>\n      <doc>\n      <![CDATA[Asynchronous sync. Flushes channel between process and leader.\n @param path\n @param cb a handler for the callback\n @param ctx context to be provided to the callback\n @throws IllegalArgumentException if an invalid path is specified]]>\n      </doc>\n    </method>\n    <method name=\"getState\" return=\"org.apache.zookeeper.ZooKeeper.States\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <field name=\"cnxn\" type=\"org.apache.zookeeper.ClientCnxn\"\n      transient=\"false\" volatile=\"false\"\n      static=\"false\" final=\"true\" visibility=\"protected\"\n      deprecated=\"not deprecated\">\n    </field>\n    <doc>\n    <![CDATA[This is the main class of ZooKeeper client library. To use a ZooKeeper\n service, an application must first instantiate an object of ZooKeeper class.\n All the iterations will be done by calling the methods of ZooKeeper class.\n <p>\n Once a connection to a server is established, a session ID is assigned to the\n client. The client will send heart beats to the server periodically to keep\n the session valid.\n <p>\n The application can call ZooKeeper APIs through a client as long as the\n session ID of the client remains valid.\n <p>\n If for some reason, the client fails to send heart beats to the server for a\n prolonged period of time (exceeding the sessionTimeout value, for instance),\n the server will expire the session, and the session ID will become invalid.\n The client object will no longer be usable. To make ZooKeeper API calls, the\n application must create a new client object.\n <p>\n If the ZooKeeper server the client currently connects to fails or otherwise\n does not respond, the client will automatically try to connect to another\n server before its session ID expires. If successful, the application can\n continue to use the client.\n <p>\n Some successful ZooKeeper API calls can leave watches on the \"data nodes\" in\n the ZooKeeper server. Other successful ZooKeeper API calls can trigger those\n watches. Once a watch is triggered, an event will be delivered to the client\n which left the watch at the first place. Each watch can be triggered only\n once. Thus, up to one event will be delivered to a client for every watch it\n leaves.\n <p>\n A client needs an object of a class implementing Watcher interface for\n processing the events delivered to the client.\n\n When a client drops current connection and re-connects to a server, all the\n existing watches are considered as being triggered but the undelivered events\n are lost. To emulate this, the client will generate a special event to tell\n the event handler a connection has been dropped. This special event has type\n EventNone and state sKeeperStateDisconnected.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.ZooKeeper -->\n  <!-- start class org.apache.zookeeper.ZooKeeper.States -->\n  <class name=\"ZooKeeper.States\" extends=\"java.lang.Enum\"\n    abstract=\"false\"\n    static=\"true\" final=\"true\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <method name=\"values\" return=\"org.apache.zookeeper.ZooKeeper.States[]\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <method name=\"valueOf\" return=\"org.apache.zookeeper.ZooKeeper.States\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"name\" type=\"java.lang.String\"/>\n    </method>\n    <method name=\"isAlive\" return=\"boolean\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </method>\n    <field name=\"CONNECTING\" type=\"org.apache.zookeeper.ZooKeeper.States\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"ASSOCIATING\" type=\"org.apache.zookeeper.ZooKeeper.States\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"CONNECTED\" type=\"org.apache.zookeeper.ZooKeeper.States\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"CLOSED\" type=\"org.apache.zookeeper.ZooKeeper.States\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n    <field name=\"AUTH_FAILED\" type=\"org.apache.zookeeper.ZooKeeper.States\"\n      transient=\"false\" volatile=\"false\"\n      static=\"true\" final=\"true\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </field>\n  </class>\n  <!-- end class org.apache.zookeeper.ZooKeeper.States -->\n  <!-- start class org.apache.zookeeper.ZooKeeperMain -->\n  <class name=\"ZooKeeperMain\" extends=\"java.lang.Object\"\n    abstract=\"false\"\n    static=\"false\" final=\"false\" visibility=\"public\"\n    deprecated=\"not deprecated\">\n    <constructor name=\"ZooKeeperMain\"\n      static=\"false\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n    </constructor>\n    <method name=\"main\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"args\" type=\"java.lang.String[]\"/>\n      <exception name=\"NumberFormatException\" type=\"java.lang.NumberFormatException\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n    </method>\n    <method name=\"delQuota\" return=\"boolean\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"zk\" type=\"org.apache.zookeeper.ZooKeeper\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"bytes\" type=\"boolean\"/>\n      <param name=\"numNodes\" type=\"boolean\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[this method deletes quota for a node.\n @param zk the zookeeper client\n @param path the path to delete quota for\n @param bytes true if number of bytes needs to\n be unset\n @param numNodes true if number of nodes needs \n to be unset\n @return true if quota deletion is successful\n @throws KeeperException\n @throws IOException\n @throws InterruptedException]]>\n      </doc>\n    </method>\n    <method name=\"createQuota\" return=\"boolean\"\n      abstract=\"false\" native=\"false\" synchronized=\"false\"\n      static=\"true\" final=\"false\" visibility=\"public\"\n      deprecated=\"not deprecated\">\n      <param name=\"zk\" type=\"org.apache.zookeeper.ZooKeeper\"/>\n      <param name=\"path\" type=\"java.lang.String\"/>\n      <param name=\"bytes\" type=\"long\"/>\n      <param name=\"numNodes\" type=\"int\"/>\n      <exception name=\"KeeperException\" type=\"org.apache.zookeeper.KeeperException\"/>\n      <exception name=\"IOException\" type=\"java.io.IOException\"/>\n      <exception name=\"InterruptedException\" type=\"java.lang.InterruptedException\"/>\n      <doc>\n      <![CDATA[this method creates a quota node for the path\n @param zk the ZooKeeper client\n @param path the path for which quota needs to be created\n @param bytes the limit of bytes on this path\n @param numNodes the limit of number of nodes on this path\n @return true if its successful and false if not.]]>\n      </doc>\n    </method>\n    <doc>\n    <![CDATA[The command line client to ZooKeeper.]]>\n    </doc>\n  </class>\n  <!-- end class org.apache.zookeeper.ZooKeeperMain -->\n</package>\n\n</api>\n"
  },
  {
    "path": "src/java/lib/jline-0.9.94.LICENSE.txt",
    "content": "Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or\nwithout modification, are permitted provided that the following\nconditions are met:\n\nRedistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with\nthe distribution.\n\nNeither the name of JLine nor the names of its contributors\nmay be used to endorse or promote products derived from this\nsoftware without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\nBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\nEVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\nAND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\nOF THE POSSIBILITY OF SUCH DAMAGE.\n\n"
  },
  {
    "path": "src/java/lib/log4j-1.2.17.LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 1999-2005 The Apache Software Foundation\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/java/lib/slf4j-1.7.25.LICENSE.txt",
    "content": "Copyright (c) 2004-2017 QOS.ch\nAll rights reserved.\n\nPermission is hereby granted, free  of charge, to any person obtaining\na  copy  of this  software  and  associated  documentation files  (the\n\"Software\"), to  deal in  the Software without  restriction, including\nwithout limitation  the rights to  use, copy, modify,  merge, publish,\ndistribute,  sublicense, and/or sell  copies of  the Software,  and to\npermit persons to whom the Software  is furnished to do so, subject to\nthe following conditions:\n\nThe  above  copyright  notice  and  this permission  notice  shall  be\nincluded in all copies or substantial portions of the Software.\n\nTHE  SOFTWARE IS  PROVIDED  \"AS  IS\", WITHOUT  WARRANTY  OF ANY  KIND,\nEXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF\nMERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n"
  },
  {
    "path": "src/java/main/org/apache/jute/BinaryInputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.DataInput;\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n *\n */\npublic class BinaryInputArchive implements InputArchive {\n    static public final String UNREASONBLE_LENGTH= \"Unreasonable length = \";\n    private DataInput in;\n    \n    static public BinaryInputArchive getArchive(InputStream strm) {\n        return new BinaryInputArchive(new DataInputStream(strm));\n    }\n    \n    static private class BinaryIndex implements Index {\n        private int nelems;\n        BinaryIndex(int nelems) {\n            this.nelems = nelems;\n        }\n        public boolean done() {\n            return (nelems <= 0);\n        }\n        public void incr() {\n            nelems--;\n        }\n    }\n    /** Creates a new instance of BinaryInputArchive */\n    public BinaryInputArchive(DataInput in) {\n        this.in = in;\n    }\n    \n    public byte readByte(String tag) throws IOException {\n        return in.readByte();\n    }\n    \n    public boolean readBool(String tag) throws IOException {\n        return in.readBoolean();\n    }\n    \n    public int readInt(String tag) throws IOException {\n        return in.readInt();\n    }\n    \n    public long readLong(String tag) throws IOException {\n        return in.readLong();\n    }\n    \n    public float readFloat(String tag) throws IOException {\n        return in.readFloat();\n    }\n    \n    public double readDouble(String tag) throws IOException {\n        return in.readDouble();\n    }\n    \n    public String readString(String tag) throws IOException {\n    \tint len = in.readInt();\n    \tif (len == -1) return null;\n        checkLength(len);\n    \tbyte b[] = new byte[len];\n    \tin.readFully(b);\n    \treturn new String(b, \"UTF8\");\n    }\n    \n    static public final int maxBuffer = Integer.getInteger(\"jute.maxbuffer\", 0xfffff);\n\n    public byte[] readBuffer(String tag) throws IOException {\n        int len = readInt(tag);\n        if (len == -1) return null;\n        checkLength(len);\n        byte[] arr = new byte[len];\n        in.readFully(arr);\n        return arr;\n    }\n    \n    public void readRecord(Record r, String tag) throws IOException {\n        r.deserialize(this, tag);\n    }\n    \n    public void startRecord(String tag) throws IOException {}\n    \n    public void endRecord(String tag) throws IOException {}\n    \n    public Index startVector(String tag) throws IOException {\n        int len = readInt(tag);\n        if (len == -1) {\n        \treturn null;\n        }\n\t\treturn new BinaryIndex(len);\n    }\n    \n    public void endVector(String tag) throws IOException {}\n    \n    public Index startMap(String tag) throws IOException {\n        return new BinaryIndex(readInt(tag));\n    }\n    \n    public void endMap(String tag) throws IOException {}\n\n    // Since this is a rough sanity check, add some padding to maxBuffer to\n    // make up for extra fields, etc. (otherwise e.g. clients may be able to\n    // write buffers larger than we can read from disk!)\n    private void checkLength(int len) throws IOException {\n        if (len < 0 || len > maxBuffer + 1024) {\n            throw new IOException(UNREASONBLE_LENGTH + len);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/BinaryOutputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.DataOutput;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.util.List;\nimport java.util.TreeMap;\n\n/**\n *\n */\npublic class BinaryOutputArchive implements OutputArchive {\n    private ByteBuffer bb = ByteBuffer.allocate(1024);\n\n    private DataOutput out;\n    \n    public static BinaryOutputArchive getArchive(OutputStream strm) {\n        return new BinaryOutputArchive(new DataOutputStream(strm));\n    }\n    \n    /** Creates a new instance of BinaryOutputArchive */\n    public BinaryOutputArchive(DataOutput out) {\n        this.out = out;\n    }\n    \n    public void writeByte(byte b, String tag) throws IOException {\n        out.writeByte(b);\n    }\n    \n    public void writeBool(boolean b, String tag) throws IOException {\n        out.writeBoolean(b);\n    }\n    \n    public void writeInt(int i, String tag) throws IOException {\n        out.writeInt(i);\n    }\n    \n    public void writeLong(long l, String tag) throws IOException {\n        out.writeLong(l);\n    }\n    \n    public void writeFloat(float f, String tag) throws IOException {\n        out.writeFloat(f);\n    }\n    \n    public void writeDouble(double d, String tag) throws IOException {\n        out.writeDouble(d);\n    }\n    \n    /**\n     * create our own char encoder to utf8. This is faster \n     * then string.getbytes(UTF8).\n     * @param s the string to encode into utf8\n     * @return utf8 byte sequence.\n     */\n    final private ByteBuffer stringToByteBuffer(CharSequence s) {\n        bb.clear();\n        final int len = s.length();\n        for (int i = 0; i < len; i++) {\n            if (bb.remaining() < 3) {\n                ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1);\n                bb.flip();\n                n.put(bb);\n                bb = n;\n            }\n            char c = s.charAt(i);\n            if (c < 0x80) {\n                bb.put((byte) c);\n            } else if (c < 0x800) {\n                bb.put((byte) (0xc0 | (c >> 6)));\n                bb.put((byte) (0x80 | (c & 0x3f)));\n            } else {\n                bb.put((byte) (0xe0 | (c >> 12)));\n                bb.put((byte) (0x80 | ((c >> 6) & 0x3f)));\n                bb.put((byte) (0x80 | (c & 0x3f)));\n            }\n        }\n        bb.flip();\n        return bb;\n    }\n\n    public void writeString(String s, String tag) throws IOException {\n        if (s == null) {\n            writeInt(-1, \"len\");\n            return;\n        }\n        ByteBuffer bb = stringToByteBuffer(s);\n        writeInt(bb.remaining(), \"len\");\n        out.write(bb.array(), bb.position(), bb.limit());\n    }\n\n    public void writeBuffer(byte barr[], String tag)\n    throws IOException {\n    \tif (barr == null) {\n    \t\tout.writeInt(-1);\n    \t\treturn;\n    \t}\n    \tout.writeInt(barr.length);\n        out.write(barr);\n    }\n    \n    public void writeRecord(Record r, String tag) throws IOException {\n        r.serialize(this, tag);\n    }\n    \n    public void startRecord(Record r, String tag) throws IOException {}\n    \n    public void endRecord(Record r, String tag) throws IOException {}\n    \n    public void startVector(List v, String tag) throws IOException {\n    \tif (v == null) {\n    \t\twriteInt(-1, tag);\n    \t\treturn;\n    \t}\n        writeInt(v.size(), tag);\n    }\n    \n    public void endVector(List v, String tag) throws IOException {}\n    \n    public void startMap(TreeMap v, String tag) throws IOException {\n        writeInt(v.size(), tag);\n    }\n    \n    public void endMap(TreeMap v, String tag) throws IOException {}\n    \n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/CsvInputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.PushbackReader;\nimport java.io.UnsupportedEncodingException;\n\n/**\n *\n */\nclass CsvInputArchive implements InputArchive {\n    \n    private PushbackReader stream;\n    \n    private class CsvIndex implements Index {\n        public boolean done() {\n            char c = '\\0';\n            try {\n                c = (char) stream.read();\n                stream.unread(c);\n            } catch (IOException ex) {\n            }\n            return (c == '}') ? true : false;\n        }\n        public void incr() {}\n    }\n    \n    private void throwExceptionOnError(String tag) throws IOException {\n        throw new IOException(\"Error deserializing \"+tag);\n    }\n    \n    private String readField(String tag) throws IOException {\n        try {\n            StringBuilder buf = new StringBuilder();\n            while (true) {\n                char c = (char) stream.read();\n                switch (c) {\n                    case ',':\n                        return buf.toString();\n                    case '}':\n                    case '\\n':\n                    case '\\r':\n                        stream.unread(c);\n                        return buf.toString();\n                    default:\n                        buf.append(c);\n                }\n            }\n        } catch (IOException ex) {\n            throw new IOException(\"Error reading \"+tag);\n        }\n    }\n    \n    static CsvInputArchive getArchive(InputStream strm)\n    throws UnsupportedEncodingException {\n        return new CsvInputArchive(strm);\n    }\n    \n    /** Creates a new instance of CsvInputArchive */\n    public CsvInputArchive(InputStream in)\n    throws UnsupportedEncodingException {\n        stream = new PushbackReader(new InputStreamReader(in, \"UTF-8\"));\n    }\n    \n    public byte readByte(String tag) throws IOException {\n        return (byte) readLong(tag);\n    }\n    \n    public boolean readBool(String tag) throws IOException {\n        String sval = readField(tag);\n        return \"T\".equals(sval) ? true : false;\n    }\n    \n    public int readInt(String tag) throws IOException {\n        return (int) readLong(tag);\n    }\n    \n    public long readLong(String tag) throws IOException {\n        String sval = readField(tag);\n        try {\n            long lval = Long.parseLong(sval);\n            return lval;\n        } catch (NumberFormatException ex) {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n    }\n    \n    public float readFloat(String tag) throws IOException {\n        return (float) readDouble(tag);\n    }\n    \n    public double readDouble(String tag) throws IOException {\n        String sval = readField(tag);\n        try {\n            double dval = Double.parseDouble(sval);\n            return dval;\n        } catch (NumberFormatException ex) {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n    }\n    \n    public String readString(String tag) throws IOException {\n        String sval = readField(tag);\n        return Utils.fromCSVString(sval);\n        \n    }\n    \n    public byte[] readBuffer(String tag) throws IOException {\n        String sval = readField(tag);\n        return Utils.fromCSVBuffer(sval);\n    }\n    \n    public void readRecord(Record r, String tag) throws IOException {\n        r.deserialize(this, tag);\n    }\n    \n    public void startRecord(String tag) throws IOException {\n        if (tag != null && !\"\".equals(tag)) {\n            char c1 = (char) stream.read();\n            char c2 = (char) stream.read();\n            if (c1 != 's' || c2 != '{') {\n                throw new IOException(\"Error deserializing \"+tag);\n            }\n        }\n    }\n    \n    public void endRecord(String tag) throws IOException {\n        char c = (char) stream.read();\n        if (tag == null || \"\".equals(tag)) {\n            if (c != '\\n' && c != '\\r') {\n                throw new IOException(\"Error deserializing record.\");\n            } else {\n                return;\n            }\n        }\n        \n        if (c != '}') {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n        c = (char) stream.read();\n        if (c != ',') {\n            stream.unread(c);\n        }\n        \n        return;\n    }\n    \n    public Index startVector(String tag) throws IOException {\n        char c1 = (char) stream.read();\n        char c2 = (char) stream.read();\n        if (c1 != 'v' || c2 != '{') {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n        return new CsvIndex();\n    }\n    \n    public void endVector(String tag) throws IOException {\n        char c = (char) stream.read();\n        if (c != '}') {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n        c = (char) stream.read();\n        if (c != ',') {\n            stream.unread(c);\n        }\n        return;\n    }\n    \n    public Index startMap(String tag) throws IOException {\n        char c1 = (char) stream.read();\n        char c2 = (char) stream.read();\n        if (c1 != 'm' || c2 != '{') {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n        return new CsvIndex();\n    }\n    \n    public void endMap(String tag) throws IOException {\n        char c = (char) stream.read();\n        if (c != '}') {\n            throw new IOException(\"Error deserializing \"+tag);\n        }\n        c = (char) stream.read();\n        if (c != ',') {\n            stream.unread(c);\n        }\n        return;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/CsvOutputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.io.UnsupportedEncodingException;\nimport java.util.List;\nimport java.util.TreeMap;\n\n/**\n *\n */\npublic class CsvOutputArchive implements OutputArchive {\n\n    private PrintStream stream;\n    private boolean isFirst = true;\n    \n    static CsvOutputArchive getArchive(OutputStream strm)\n    throws UnsupportedEncodingException {\n        return new CsvOutputArchive(strm);\n    }\n    \n    private void throwExceptionOnError(String tag) throws IOException {\n        if (stream.checkError()) {\n            throw new IOException(\"Error serializing \"+tag);\n        }\n    }\n \n    private void printCommaUnlessFirst() {\n        if (!isFirst) {\n            stream.print(\",\");\n        }\n        isFirst = false;\n    }\n    \n    /** Creates a new instance of CsvOutputArchive */\n    public CsvOutputArchive(OutputStream out)\n    throws UnsupportedEncodingException {\n        stream = new PrintStream(out, true, \"UTF-8\");\n    }\n    \n    public void writeByte(byte b, String tag) throws IOException {\n        writeLong((long)b, tag);\n    }\n    \n    public void writeBool(boolean b, String tag) throws IOException {\n        printCommaUnlessFirst();\n        String val = b ? \"T\" : \"F\";\n        stream.print(val);\n        throwExceptionOnError(tag);\n    }\n    \n    public void writeInt(int i, String tag) throws IOException {\n        writeLong((long)i, tag);\n    }\n    \n    public void writeLong(long l, String tag) throws IOException {\n        printCommaUnlessFirst();\n        stream.print(l);\n        throwExceptionOnError(tag);\n    }\n    \n    public void writeFloat(float f, String tag) throws IOException {\n        writeDouble((double)f, tag);\n    }\n    \n    public void writeDouble(double d, String tag) throws IOException {\n        printCommaUnlessFirst();\n        stream.print(d);\n        throwExceptionOnError(tag);\n    }\n    \n    public void writeString(String s, String tag) throws IOException {\n        printCommaUnlessFirst();\n        stream.print(Utils.toCSVString(s));\n        throwExceptionOnError(tag);\n    }\n    \n    public void writeBuffer(byte buf[], String tag)\n    throws IOException {\n        printCommaUnlessFirst();\n        stream.print(Utils.toCSVBuffer(buf));\n        throwExceptionOnError(tag);\n    }\n    \n    public void writeRecord(Record r, String tag) throws IOException {\n        if (r == null) {\n            return;\n        }\n        r.serialize(this, tag);\n    }\n    \n    public void startRecord(Record r, String tag) throws IOException {\n        if (tag != null && !\"\".equals(tag)) {\n            printCommaUnlessFirst();\n            stream.print(\"s{\");\n            isFirst = true;\n        }\n    }\n    \n    public void endRecord(Record r, String tag) throws IOException {\n        if (tag == null || \"\".equals(tag)) {\n            stream.print(\"\\n\");\n            isFirst = true;\n        } else {\n            stream.print(\"}\");\n            isFirst = false;\n        }\n    }\n    \n    public void startVector(List v, String tag) throws IOException {\n        printCommaUnlessFirst();\n        stream.print(\"v{\");\n        isFirst = true;\n    }\n    \n    public void endVector(List v, String tag) throws IOException {\n        stream.print(\"}\");\n        isFirst = false;\n    }\n    \n    public void startMap(TreeMap v, String tag) throws IOException {\n        printCommaUnlessFirst();\n        stream.print(\"m{\");\n        isFirst = true;\n    }\n    \n    public void endMap(TreeMap v, String tag) throws IOException {\n        stream.print(\"}\");\n        isFirst = false;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/Index.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\n/**\n * Interface that acts as an iterator for deserializing maps.\n * The deserializer returns an instance that the record uses to\n * read vectors and maps. An example of usage is as follows:\n *\n * <code>\n * Index idx = startVector(...);\n * while (!idx.done()) {\n *   .... // read element of a vector\n *   idx.incr();\n * }\n * </code>\n *\n */\npublic interface Index {\n    public boolean done();\n    public void incr();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/InputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\n\n/**\n * Interface that all the Deserializers have to implement.\n *\n */\npublic interface InputArchive {\n    public byte readByte(String tag) throws IOException;\n    public boolean readBool(String tag) throws IOException;\n    public int readInt(String tag) throws IOException;\n    public long readLong(String tag) throws IOException;\n    public float readFloat(String tag) throws IOException;\n    public double readDouble(String tag) throws IOException;\n    public String readString(String tag) throws IOException;\n    public byte[] readBuffer(String tag) throws IOException;\n    public void readRecord(Record r, String tag) throws IOException;\n    public void startRecord(String tag) throws IOException;\n    public void endRecord(String tag) throws IOException;\n    public Index startVector(String tag) throws IOException;\n    public void endVector(String tag) throws IOException;\n    public Index startMap(String tag) throws IOException;\n    public void endMap(String tag) throws IOException;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/OutputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.TreeMap;\n\n/**\n * Interface that alll the serializers have to implement.\n *\n */\npublic interface OutputArchive {\n    public void writeByte(byte b, String tag) throws IOException;\n    public void writeBool(boolean b, String tag) throws IOException;\n    public void writeInt(int i, String tag) throws IOException;\n    public void writeLong(long l, String tag) throws IOException;\n    public void writeFloat(float f, String tag) throws IOException;\n    public void writeDouble(double d, String tag) throws IOException;\n    public void writeString(String s, String tag) throws IOException;\n    public void writeBuffer(byte buf[], String tag)\n        throws IOException;\n    public void writeRecord(Record r, String tag) throws IOException;\n    public void startRecord(Record r, String tag) throws IOException;\n    public void endRecord(Record r, String tag) throws IOException;\n    public void startVector(List v, String tag) throws IOException;\n    public void endVector(List v, String tag) throws IOException;\n    public void startMap(TreeMap v, String tag) throws IOException;\n    public void endMap(TreeMap v, String tag) throws IOException;\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/Record.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport org.apache.yetus.audience.InterfaceAudience;\n\nimport java.io.IOException;\n\n/**\n * Interface that is implemented by generated classes.\n * \n */\n@InterfaceAudience.Public\npublic interface Record {\n    public void serialize(OutputArchive archive, String tag)\n        throws IOException;\n    public void deserialize(InputArchive archive, String tag)\n        throws IOException;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/RecordReader.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\n\n/**\n * Front-end interface to deserializers. Also acts as a factory\n * for deserializers.\n *\n */\npublic class RecordReader {\n    \n    private InputArchive archive;\n\n    static private HashMap archiveFactory;\n    \n    static {\n        archiveFactory = new HashMap();\n        Class[] params = { InputStream.class };\n        try {\n            archiveFactory.put(\"binary\",\n                    BinaryInputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n            archiveFactory.put(\"csv\",\n                    CsvInputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n            archiveFactory.put(\"xml\",\n                    XmlInputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n        } catch (SecurityException ex) {\n            ex.printStackTrace();\n        } catch (NoSuchMethodException ex) {\n            ex.printStackTrace();\n        }\n    }\n    \n    static private InputArchive createArchive(InputStream in, String format)\n    throws IOException {\n        Method factory = (Method) archiveFactory.get(format);\n        if (factory != null) {\n            Object[] params = { in };\n            try {\n                return (InputArchive) factory.invoke(null, params);\n            } catch (IllegalArgumentException ex) {\n                ex.printStackTrace();\n            } catch (InvocationTargetException ex) {\n                ex.printStackTrace();\n            } catch (IllegalAccessException ex) {\n                ex.printStackTrace();\n            }\n        }\n        return null;\n    }\n    /**\n     * Creates a new instance of RecordReader.\n     * @param in Stream from which to deserialize a record\n     * @param format Deserialization format (\"binary\", \"xml\", or \"csv\")\n     */\n    public RecordReader(InputStream in, String format)\n    throws IOException {\n        archive = createArchive(in, format);\n    }\n    \n    /**\n     * Deserialize a record\n     * @param r Record to be deserialized\n     */\n    public void read(Record r) throws IOException {\n        r.deserialize(archive, \"\");\n    }\n    \n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/RecordWriter.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\n\n/**\n * Front-end for serializers. Also serves as a factory for serializers.\n *\n */\npublic class RecordWriter {\n    \n    private OutputArchive archive;\n    \n    static private OutputArchive getBinaryArchive(OutputStream out) {\n        return new BinaryOutputArchive(new DataOutputStream(out));\n    }\n    \n    static private OutputArchive getCsvArchive(OutputStream out)\n    throws IOException {\n        try {\n            return new CsvOutputArchive(out);\n        } catch (UnsupportedEncodingException ex) {\n            throw new IOException(\"Unsupported encoding UTF-8\");\n        }\n    }\n    \n    static private OutputArchive getXmlArchive(OutputStream out)\n    throws IOException {\n        return new XmlOutputArchive(out);\n    }\n\n    static HashMap constructFactory() {\n        HashMap factory = new HashMap();\n        Class[] params = { OutputStream.class };\n        try {\n            factory.put(\"binary\",\n                    BinaryOutputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n            factory.put(\"csv\",\n                    CsvOutputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n            factory.put(\"xml\",\n                    XmlOutputArchive.class.getDeclaredMethod(\n                        \"getArchive\", params));\n        } catch (SecurityException ex) {\n            ex.printStackTrace();\n        } catch (NoSuchMethodException ex) {\n            ex.printStackTrace();\n        }\n        return factory;\n    }\n    \n    static private HashMap archiveFactory = constructFactory();\n    \n    static private OutputArchive createArchive(OutputStream out,\n            String format)\n            throws IOException {\n        Method factory = (Method) archiveFactory.get(format);\n        if (factory != null) {\n            Object[] params = { out };\n            try {\n                return (OutputArchive) factory.invoke(null, params);\n            } catch (IllegalArgumentException ex) {\n                ex.printStackTrace();\n            } catch (InvocationTargetException ex) {\n                ex.printStackTrace();\n            } catch (IllegalAccessException ex) {\n                ex.printStackTrace();\n            }\n        }\n        return null;\n    }\n    /**\n     * Creates a new instance of RecordWriter\n     * @param out Output stream where the records will be serialized\n     * @param format Serialization format (\"binary\", \"xml\", or \"csv\")\n     */\n    public RecordWriter(OutputStream out, String format)\n    throws IOException {\n        archive = createArchive(out, format);\n    }\n    \n    /**\n     * Serialize a record\n     * @param r record to be serialized\n     */\n    public void write(Record r) throws IOException {\n        r.serialize(archive, \"\");\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/Utils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * Various utility functions for Hadoop record I/O runtime.\n */\npublic class Utils {\n    \n    /** Cannot create a new instance of Utils */\n    private Utils() {\n        super();\n    }\n   \n    /**\n     * equals function that actually compares two buffers.\n     *\n     * @param onearray First buffer\n     * @param twoarray Second buffer\n     * @return true if one and two contain exactly the same content, else false.\n     */\n    public static boolean bufEquals(byte onearray[], byte twoarray[] ) {\n    \tif (onearray == twoarray) return true;\n        boolean ret = (onearray.length == twoarray.length);\n        if (!ret) {\n            return ret;\n        }\n        for (int idx = 0; idx < onearray.length; idx++) {\n            if (onearray[idx] != twoarray[idx]) {\n                return false;\n            }\n        }\n        return true;\n    }\n    \n    private static final char[] hexchars = { '0', '1', '2', '3', '4', '5',\n                                            '6', '7', '8', '9', 'A', 'B',\n                                            'C', 'D', 'E', 'F' };\n    /**\n     * \n     * @param s \n     * @return \n     */\n    static String toXMLString(String s) {\n        if (s == null)\n            return \"\";\n\n        StringBuilder sb = new StringBuilder();\n        for (int idx = 0; idx < s.length(); idx++) {\n          char ch = s.charAt(idx);\n          if (ch == '<') {\n            sb.append(\"&lt;\");\n          } else if (ch == '&') {\n            sb.append(\"&amp;\");\n          } else if (ch == '%') {\n            sb.append(\"%25\");\n          } else if (ch < 0x20) {\n            sb.append(\"%\");\n            sb.append(hexchars[ch/16]);\n            sb.append(hexchars[ch%16]);\n          } else {\n            sb.append(ch);\n          }\n        }\n        return sb.toString();\n    }\n    \n    static private int h2c(char ch) {\n      if (ch >= '0' && ch <= '9') {\n        return ch - '0';\n      } else if (ch >= 'A' && ch <= 'F') {\n        return ch - 'A';\n      } else if (ch >= 'a' && ch <= 'f') {\n        return ch - 'a';\n      }\n      return 0;\n    }\n    \n    /**\n     * \n     * @param s \n     * @return \n     */\n    static String fromXMLString(String s) {\n        StringBuilder sb = new StringBuilder();\n        for (int idx = 0; idx < s.length();) {\n          char ch = s.charAt(idx++);\n          if (ch == '%') {\n            char ch1 = s.charAt(idx++);\n            char ch2 = s.charAt(idx++);\n            char res = (char)(h2c(ch1)*16 + h2c(ch2));\n            sb.append(res);\n          } else {\n            sb.append(ch);\n          }\n        }\n        \n        return sb.toString();\n    }\n    \n    /**\n     * \n     * @param s \n     * @return \n     */\n    static String toCSVString(String s) {\n        if (s == null)\n            return \"\";\n\n        StringBuilder sb = new StringBuilder(s.length()+1);\n        sb.append('\\'');\n        int len = s.length();\n        for (int i = 0; i < len; i++) {\n            char c = s.charAt(i);\n            switch(c) {\n                case '\\0':\n                    sb.append(\"%00\");\n                    break;\n                case '\\n':\n                    sb.append(\"%0A\");\n                    break;\n                case '\\r':\n                    sb.append(\"%0D\");\n                    break;\n                case ',':\n                    sb.append(\"%2C\");\n                    break;\n                case '}':\n                    sb.append(\"%7D\");\n                    break;\n                case '%':\n                    sb.append(\"%25\");\n                    break;\n                default:\n                    sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n    \n    /**\n     * \n     * @param s \n     * @throws java.io.IOException \n     * @return \n     */\n    static String fromCSVString(String s) throws IOException {\n        if (s.charAt(0) != '\\'') {\n            throw new IOException(\"Error deserializing string.\");\n        }\n        int len = s.length();\n        StringBuilder sb = new StringBuilder(len-1);\n        for (int i = 1; i < len; i++) {\n            char c = s.charAt(i);\n            if (c == '%') {\n                char ch1 = s.charAt(i+1);\n                char ch2 = s.charAt(i+2);\n                i += 2;\n                if (ch1 == '0' && ch2 == '0') { sb.append('\\0'); }\n                else if (ch1 == '0' && ch2 == 'A') { sb.append('\\n'); }\n                else if (ch1 == '0' && ch2 == 'D') { sb.append('\\r'); }\n                else if (ch1 == '2' && ch2 == 'C') { sb.append(','); }\n                else if (ch1 == '7' && ch2 == 'D') { sb.append('}'); }\n                else if (ch1 == '2' && ch2 == '5') { sb.append('%'); }\n                else {throw new IOException(\"Error deserializing string.\");}\n            } else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n    \n    /**\n     * \n     * @param s \n     * @return \n     */\n    static String toXMLBuffer(byte barr[]) {\n        if (barr == null || barr.length == 0) {\n            return \"\";\n        }\n        StringBuilder sb = new StringBuilder(2*barr.length);\n        for (int idx = 0; idx < barr.length; idx++) {\n            sb.append(Integer.toHexString(barr[idx]));\n        }\n        return sb.toString();\n    }\n    \n    /**\n     * \n     * @param s \n     * @throws java.io.IOException \n     * @return \n     */\n    static byte[] fromXMLBuffer(String s)\n    throws IOException {\n        ByteArrayOutputStream stream =  new ByteArrayOutputStream();\n        if (s.length() == 0) { return stream.toByteArray(); }\n        int blen = s.length()/2;\n        byte[] barr = new byte[blen];\n        for (int idx = 0; idx < blen; idx++) {\n            char c1 = s.charAt(2*idx);\n            char c2 = s.charAt(2*idx+1);\n            barr[idx] = Byte.parseByte(\"\"+c1+c2, 16);\n        }\n        stream.write(barr);\n        return stream.toByteArray();\n    }\n    \n    /**\n     * \n     * @param buf \n     * @return \n     */\n    static String toCSVBuffer(byte barr[]) {\n        if (barr == null || barr.length == 0) {\n            return \"\";\n        }\n        StringBuilder sb = new StringBuilder(barr.length + 1);\n        sb.append('#');\n        for(int idx = 0; idx < barr.length; idx++) {\n            sb.append(Integer.toHexString(barr[idx]));\n        }\n        return sb.toString();\n    }\n    \n    /**\n     * Converts a CSV-serialized representation of buffer to a new\n     * ByteArrayOutputStream.\n     * @param s CSV-serialized representation of buffer\n     * @throws java.io.IOException \n     * @return Deserialized ByteArrayOutputStream\n     */\n    static byte[] fromCSVBuffer(String s)\n    throws IOException {\n        if (s.charAt(0) != '#') {\n            throw new IOException(\"Error deserializing buffer.\");\n        }\n        ByteArrayOutputStream stream =  new ByteArrayOutputStream();\n        if (s.length() == 1) { return stream.toByteArray(); }\n        int blen = (s.length()-1)/2;\n        byte[] barr = new byte[blen];\n        for (int idx = 0; idx < blen; idx++) {\n            char c1 = s.charAt(2*idx+1);\n            char c2 = s.charAt(2*idx+2);\n            barr[idx] = Byte.parseByte(\"\"+c1+c2, 16);\n        }\n        stream.write(barr);\n        return stream.toByteArray();\n    }\n    public static int compareBytes(byte b1[], int off1, int len1, byte b2[], int off2, int len2) {\n        int i;\n        for(i=0; i < len1 && i < len2; i++) {\n            if (b1[off1+i] != b2[off2+i]) {\n                return b1[off1+i] < b2[off2+i] ? -1 : 1;\n            }\n        }\n        if (len1 != len2) {\n            return len1 < len2 ? -1 : 1;\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/XmlInputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n/**\n *\n */\nclass XmlInputArchive implements InputArchive {\n    \n    static private class Value {\n        private String type;\n        private StringBuffer sb;\n        \n        public Value(String t) {\n            type = t;\n            sb = new StringBuffer();\n        }\n        public void addChars(char[] buf, int offset, int len) {\n            sb.append(buf, offset, len);\n        }\n        public String getValue() { return sb.toString(); }\n        public String getType() { return type; }\n    }\n    \n    private static class XMLParser extends DefaultHandler {\n        private boolean charsValid = false;\n        \n        private ArrayList<Value> valList;\n        \n        private XMLParser(ArrayList<Value> vlist) {\n            valList = vlist;\n        }\n        \n        public void startDocument() throws SAXException {}\n        \n        public void endDocument() throws SAXException {}\n        \n        public void startElement(String ns,\n                String sname,\n                String qname,\n                Attributes attrs) throws SAXException {\n            charsValid = false;\n            if (\"boolean\".equals(qname) ||\n                    \"i4\".equals(qname) ||\n                    \"int\".equals(qname) ||\n                    \"string\".equals(qname) ||\n                    \"double\".equals(qname) ||\n                    \"ex:i1\".equals(qname) ||\n                    \"ex:i8\".equals(qname) ||\n                    \"ex:float\".equals(qname)) {\n                charsValid = true;\n                valList.add(new Value(qname));\n            } else if (\"struct\".equals(qname) ||\n                \"array\".equals(qname)) {\n                valList.add(new Value(qname));\n            }\n        }\n        \n        public void endElement(String ns,\n                String sname,\n                String qname) throws SAXException {\n            charsValid = false;\n            if (\"struct\".equals(qname) ||\n                    \"array\".equals(qname)) {\n                valList.add(new Value(\"/\"+qname));\n            }\n        }\n        \n        public void characters(char buf[], int offset, int len)\n        throws SAXException {\n            if (charsValid) {\n                Value v = valList.get(valList.size()-1);\n                v.addChars(buf, offset,len);\n            }\n        }\n        \n    }\n    \n    private class XmlIndex implements Index {\n        public boolean done() {\n            Value v = valList.get(vIdx);\n            if (\"/array\".equals(v.getType())) {\n                valList.set(vIdx, null);\n                vIdx++;\n                return true;\n            } else {\n                return false;\n            }\n        }\n        public void incr() {}\n    }\n    \n    private ArrayList<Value> valList;\n    private int vLen;\n    private int vIdx;\n    \n    private Value next() throws IOException {\n        if (vIdx < vLen) {\n            Value v = valList.get(vIdx);\n            valList.set(vIdx, null);\n            vIdx++;\n            return v;\n        } else {\n            throw new IOException(\"Error in deserialization.\");\n        }\n    }\n    \n    static XmlInputArchive getArchive(InputStream strm)\n    throws ParserConfigurationException, SAXException, IOException {\n        return new XmlInputArchive(strm);\n    }\n    \n    /** Creates a new instance of BinaryInputArchive */\n    public XmlInputArchive(InputStream in)\n    throws ParserConfigurationException, SAXException, IOException {\n        valList = new ArrayList<Value>();\n        DefaultHandler handler = new XMLParser(valList);\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        SAXParser parser = factory.newSAXParser();\n        parser.parse(in, handler);\n        vLen = valList.size();\n        vIdx = 0;\n    }\n    \n    public byte readByte(String tag) throws IOException {\n        Value v = next();\n        if (!\"ex:i1\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Byte.parseByte(v.getValue());\n    }\n    \n    public boolean readBool(String tag) throws IOException {\n        Value v = next();\n        if (!\"boolean\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return \"1\".equals(v.getValue());\n    }\n    \n    public int readInt(String tag) throws IOException {\n        Value v = next();\n        if (!\"i4\".equals(v.getType()) &&\n                !\"int\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Integer.parseInt(v.getValue());\n    }\n    \n    public long readLong(String tag) throws IOException {\n        Value v = next();\n        if (!\"ex:i8\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Long.parseLong(v.getValue());\n    }\n    \n    public float readFloat(String tag) throws IOException {\n        Value v = next();\n        if (!\"ex:float\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Float.parseFloat(v.getValue());\n    }\n    \n    public double readDouble(String tag) throws IOException {\n        Value v = next();\n        if (!\"double\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Double.parseDouble(v.getValue());\n    }\n    \n    public String readString(String tag) throws IOException {\n        Value v = next();\n        if (!\"string\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Utils.fromXMLString(v.getValue());\n    }\n    \n    public byte[] readBuffer(String tag) throws IOException {\n        Value v = next();\n        if (!\"string\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return Utils.fromXMLBuffer(v.getValue());\n    }\n    \n    public void readRecord(Record r, String tag) throws IOException {\n        r.deserialize(this, tag);\n    }\n    \n    public void startRecord(String tag) throws IOException {\n        Value v = next();\n        if (!\"struct\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n    }\n    \n    public void endRecord(String tag) throws IOException {\n        Value v = next();\n        if (!\"/struct\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n    }\n    \n    public Index startVector(String tag) throws IOException {\n        Value v = next();\n        if (!\"array\".equals(v.getType())) {\n            throw new IOException(\"Error deserializing \"+tag+\".\");\n        }\n        return new XmlIndex();\n    }\n    \n    public void endVector(String tag) throws IOException {}\n    \n    public Index startMap(String tag) throws IOException {\n        return startVector(tag);\n    }\n    \n    public void endMap(String tag) throws IOException { endVector(tag); }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/XmlOutputArchive.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.Stack;\nimport java.util.TreeMap;\n\n/**\n *\n */\nclass XmlOutputArchive implements OutputArchive {\n\n    private PrintStream stream;\n    \n    private int indent = 0;\n    \n    private Stack<String> compoundStack;\n    \n    private void putIndent() {\n        StringBuilder sb = new StringBuilder(\"\");\n        for (int idx = 0; idx < indent; idx++) {\n            sb.append(\"  \");\n        }\n        stream.print(sb.toString());\n    }\n    \n    private void addIndent() {\n        indent++;\n    }\n    \n    private void closeIndent() {\n        indent--;\n    }\n    \n    private void printBeginEnvelope(String tag) {\n        if (!compoundStack.empty()) {\n            String s = compoundStack.peek();\n            if (\"struct\".equals(s)) {\n                putIndent();\n                stream.print(\"<member>\\n\");\n                addIndent();\n                putIndent();\n                stream.print(\"<name>\"+tag+\"</name>\\n\");\n                putIndent();\n                stream.print(\"<value>\");\n            } else if (\"vector\".equals(s)) {\n                stream.print(\"<value>\");\n            } else if (\"map\".equals(s)) {\n                stream.print(\"<value>\");\n            }\n        } else {\n            stream.print(\"<value>\");\n        }\n    }\n    \n    private void printEndEnvelope(String tag) {\n        if (!compoundStack.empty()) {\n            String s = compoundStack.peek();\n            if (\"struct\".equals(s)) {\n                stream.print(\"</value>\\n\");\n                closeIndent();\n                putIndent();\n                stream.print(\"</member>\\n\");\n            } else if (\"vector\".equals(s)) {\n                stream.print(\"</value>\\n\");\n            } else if (\"map\".equals(s)) {\n                stream.print(\"</value>\\n\");\n            }\n        } else {\n            stream.print(\"</value>\\n\");\n        }\n    }\n    \n    private void insideVector(String tag) {\n        printBeginEnvelope(tag);\n        compoundStack.push(\"vector\");\n    }\n    \n    private void outsideVector(String tag) throws IOException {\n        String s = compoundStack.pop();\n        if (!\"vector\".equals(s)) {\n            throw new IOException(\"Error serializing vector.\");\n        }\n        printEndEnvelope(tag);\n    }\n    \n    private void insideMap(String tag) {\n        printBeginEnvelope(tag);\n        compoundStack.push(\"map\");\n    }\n    \n    private void outsideMap(String tag) throws IOException {\n        String s = compoundStack.pop();\n        if (!\"map\".equals(s)) {\n            throw new IOException(\"Error serializing map.\");\n        }\n        printEndEnvelope(tag);\n    }\n    \n    private void insideRecord(String tag) {\n        printBeginEnvelope(tag);\n        compoundStack.push(\"struct\");\n    }\n    \n    private void outsideRecord(String tag) throws IOException {\n        String s = compoundStack.pop();\n        if (!\"struct\".equals(s)) {\n            throw new IOException(\"Error serializing record.\");\n        }\n        printEndEnvelope(tag);\n    }\n    \n    static XmlOutputArchive getArchive(OutputStream strm) {\n        return new XmlOutputArchive(strm);\n    }\n    \n    /** Creates a new instance of XmlOutputArchive */\n    public XmlOutputArchive(OutputStream out) {\n        stream = new PrintStream(out);\n        compoundStack = new Stack<String>();\n    }\n    \n    public void writeByte(byte b, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<ex:i1>\");\n        stream.print(Byte.toString(b));\n        stream.print(\"</ex:i1>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeBool(boolean b, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<boolean>\");\n        stream.print(b ? \"1\" : \"0\");\n        stream.print(\"</boolean>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeInt(int i, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<i4>\");\n        stream.print(Integer.toString(i));\n        stream.print(\"</i4>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeLong(long l, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<ex:i8>\");\n        stream.print(Long.toString(l));\n        stream.print(\"</ex:i8>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeFloat(float f, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<ex:float>\");\n        stream.print(Float.toString(f));\n        stream.print(\"</ex:float>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeDouble(double d, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<double>\");\n        stream.print(Double.toString(d));\n        stream.print(\"</double>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeString(String s, String tag) throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<string>\");\n        stream.print(Utils.toXMLString(s));\n        stream.print(\"</string>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeBuffer(byte buf[], String tag)\n    throws IOException {\n        printBeginEnvelope(tag);\n        stream.print(\"<string>\");\n        stream.print(Utils.toXMLBuffer(buf));\n        stream.print(\"</string>\");\n        printEndEnvelope(tag);\n    }\n    \n    public void writeRecord(Record r, String tag) throws IOException {\n        r.serialize(this, tag);\n    }\n    \n    public void startRecord(Record r, String tag) throws IOException {\n        insideRecord(tag);\n        stream.print(\"<struct>\\n\");\n        addIndent();\n    }\n    \n    public void endRecord(Record r, String tag) throws IOException {\n        closeIndent();\n        putIndent();\n        stream.print(\"</struct>\");\n        outsideRecord(tag);\n    }\n    \n    public void startVector(List v, String tag) throws IOException {\n        insideVector(tag);\n        stream.print(\"<array>\\n\");\n        addIndent();\n    }\n    \n    public void endVector(List v, String tag) throws IOException {\n        closeIndent();\n        putIndent();\n        stream.print(\"</array>\");\n        outsideVector(tag);\n    }\n    \n    public void startMap(TreeMap v, String tag) throws IOException {\n        insideMap(tag);\n        stream.print(\"<array>\\n\");\n        addIndent();\n    }\n    \n    public void endMap(TreeMap v, String tag) throws IOException {\n        closeIndent();\n        putIndent();\n        stream.print(\"</array>\");\n        outsideMap(tag);\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/CGenerator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.util.ArrayList;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.Iterator;\n\n/**\n * C++ Code generator front-end for Hadoop record I/O.\n */\nclass CGenerator {\n    private String mName;\n    private ArrayList<JFile> mInclFiles;\n    private ArrayList<JRecord> mRecList;\n    private final File outputDirectory;\n\n    /** Creates a new instance of CppGenerator\n     *\n     * @param name possibly full pathname to the file\n     * @param ilist included files (as JFile)\n     * @param rlist List of records defined within this file\n     * @param outputDirectory\n     */\n    CGenerator(String name, ArrayList<JFile> ilist, ArrayList<JRecord> rlist,\n            File outputDirectory)\n    {\n        this.outputDirectory = outputDirectory;\n        mName = (new File(name)).getName();\n        mInclFiles = ilist;\n        mRecList = rlist;\n    }\n\n    /**\n     * Generate C++ code. This method only creates the requested file(s)\n     * and spits-out file-level elements (such as include statements etc.)\n     * record-level code is generated by JRecord.\n     */\n    void genCode() throws IOException {\n        if (!outputDirectory.exists()) {\n            if (!outputDirectory.mkdirs()) {\n                throw new IOException(\"unable to create output directory \"\n                        + outputDirectory);\n            }\n        }\n\n        FileWriter c = null;\n        FileWriter h = null;\n        try {\n            c = new FileWriter(new File(outputDirectory, mName+\".c\"));\n            h = new FileWriter(new File(outputDirectory, mName+\".h\"));\n\n            h.write(\"/**\\n\");\n            h.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n            h.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n            h.write(\"* distributed with this work for additional information\\n\");\n            h.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n            h.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n            h.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n            h.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n            h.write(\"*\\n\");\n            h.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n            h.write(\"*\\n\");\n            h.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n            h.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n            h.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n            h.write(\"* See the License for the specific language governing permissions and\\n\");\n            h.write(\"* limitations under the License.\\n\");\n            h.write(\"*/\\n\");\n            h.write(\"\\n\");\n\n            c.write(\"/**\\n\");\n            c.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n            c.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n            c.write(\"* distributed with this work for additional information\\n\");\n            c.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n            c.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n            c.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n            c.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n            c.write(\"*\\n\");\n            c.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n            c.write(\"*\\n\");\n            c.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n            c.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n            c.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n            c.write(\"* See the License for the specific language governing permissions and\\n\");\n            c.write(\"* limitations under the License.\\n\");\n            c.write(\"*/\\n\");\n            c.write(\"\\n\");\n\n            h.write(\"#ifndef __\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n            h.write(\"#define __\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n\n            h.write(\"#include \\\"recordio.h\\\"\\n\");\n            for (Iterator<JFile> i = mInclFiles.iterator(); i.hasNext();) {\n                JFile f = i.next();\n                h.write(\"#include \\\"\"+f.getName()+\".h\\\"\\n\");\n            }\n            // required for compilation from C++\n            h.write(\"\\n#ifdef __cplusplus\\nextern \\\"C\\\" {\\n#endif\\n\\n\");\n\n            c.write(\"#include <stdlib.h>\\n\"); // need it for calloc() & free()\n            c.write(\"#include \\\"\"+mName+\".h\\\"\\n\\n\");\n\n            for (Iterator<JRecord> i = mRecList.iterator(); i.hasNext();) {\n                JRecord jr = i.next();\n                jr.genCCode(h, c);\n            }\n\n            h.write(\"\\n#ifdef __cplusplus\\n}\\n#endif\\n\\n\");\n            h.write(\"#endif //\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n        } finally {\n            try {\n                if (h != null) {\n                    h.close();\n                }\n            } finally {\n                if (c != null) {\n                    c.close();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/CSharpGenerator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\npublic class CSharpGenerator {\n    private ArrayList<JRecord> mRecList;\n    private final File outputDirectory;\n\n    /** Creates a new instance of CSharpGenerator\n     *\n     * @param name possibly full pathname to the file\n     * @param ilist included files (as JFile)\n     * @param rlist List of records defined within this file\n     * @param outputDirectory\n     */\n    CSharpGenerator(String name, ArrayList<JFile> ilist, ArrayList<JRecord> rlist,\n            File outputDirectory)\n     {\n        this.outputDirectory = outputDirectory;\n        mRecList = rlist;\n    }\n\n    /**\n     * Generate C# code. This method only creates the requested file(s)\n     * and spits-out file-level elements (such as include statements etc.)\n     * record-level code is generated by JRecord.\n     */\n    void genCode() throws IOException {\n        for (JRecord rec : mRecList) {\n            rec.genCsharpCode(outputDirectory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/CppGenerator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.util.ArrayList;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.Iterator;\n\n/**\n * C++ Code generator front-end for Hadoop record I/O.\n */\nclass CppGenerator {\n    private String mName;\n    private ArrayList<JFile> mInclFiles;\n    private ArrayList<JRecord> mRecList;\n    private final File outputDirectory;\n\n    /** Creates a new instance of CppGenerator\n     *\n     * @param name possibly full pathname to the file\n     * @param ilist included files (as JFile)\n     * @param rlist List of records defined within this file\n     * @param outputDirectory\n     */\n    CppGenerator(String name, ArrayList<JFile> ilist, ArrayList<JRecord> rlist,\n            File outputDirectory)\n     {\n        this.outputDirectory = outputDirectory;\n        mName = (new File(name)).getName();\n        mInclFiles = ilist;\n        mRecList = rlist;\n    }\n\n    /**\n     * Generate C++ code. This method only creates the requested file(s)\n     * and spits-out file-level elements (such as include statements etc.)\n     * record-level code is generated by JRecord.\n     */\n    void genCode() throws IOException {\n        if (!outputDirectory.exists()) {\n            if (!outputDirectory.mkdirs()) {\n                throw new IOException(\"unable to create output directory \"\n                        + outputDirectory);\n            }\n        }\n        FileWriter cc = null;\n        FileWriter hh = null;\n\n        try {\n            cc = new FileWriter(new File(outputDirectory, mName+\".cc\"));\n            hh = new FileWriter(new File(outputDirectory, mName+\".hh\"));\n            hh.write(\"/**\\n\");\n            hh.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n            hh.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n            hh.write(\"* distributed with this work for additional information\\n\");\n            hh.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n            hh.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n            hh.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n            hh.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n            hh.write(\"*\\n\");\n            hh.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n            hh.write(\"*\\n\");\n            hh.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n            hh.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n            hh.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n            hh.write(\"* See the License for the specific language governing permissions and\\n\");\n            hh.write(\"* limitations under the License.\\n\");\n            hh.write(\"*/\\n\");\n            hh.write(\"\\n\");\n\n            cc.write(\"/**\\n\");\n            cc.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n            cc.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n            cc.write(\"* distributed with this work for additional information\\n\");\n            cc.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n            cc.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n            cc.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n            cc.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n            cc.write(\"*\\n\");\n            cc.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n            cc.write(\"*\\n\");\n            cc.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n            cc.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n            cc.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n            cc.write(\"* See the License for the specific language governing permissions and\\n\");\n            cc.write(\"* limitations under the License.\\n\");\n            cc.write(\"*/\\n\");\n            cc.write(\"\\n\");\n\n            hh.write(\"#ifndef __\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n            hh.write(\"#define __\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n\n            hh.write(\"#include \\\"recordio.hh\\\"\\n\");\n            for (Iterator<JFile> i = mInclFiles.iterator(); i.hasNext();) {\n                JFile f = i.next();\n                hh.write(\"#include \\\"\"+f.getName()+\".hh\\\"\\n\");\n            }\n            cc.write(\"#include \\\"\"+mName+\".hh\\\"\\n\");\n\n            for (Iterator<JRecord> i = mRecList.iterator(); i.hasNext();) {\n                JRecord jr = i.next();\n                jr.genCppCode(hh, cc);\n            }\n\n            hh.write(\"#endif //\"+mName.toUpperCase().replace('.','_')+\"__\\n\");\n        } finally {\n            try {\n                if (hh != null) {\n                    hh.close();\n                }\n            } finally {\n                if (cc != null) {\n                    cc.close();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JBoolean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JBoolean extends JType {\n    \n    /** Creates a new instance of JBoolean */\n    public JBoolean() {\n        super(\"int32_t\", \"bool\", \"bool\", \"boolean\", \"Bool\", \"Boolean\", \"bool\", \"toBoolean\");\n    }\n    \n    public String getSignature() {\n        return \"z\";\n    }\n    \n    public String genJavaCompareTo(String fname) {\n        return \"    ret = (\"+fname+\" == peer.\"+fname+\")? 0 : (\"+fname+\"?1:-1);\\n\";\n    }\n    \n    public String genJavaHashCode(String fname) {\n        return \"     ret = (\"+fname+\")?0:1;\\n\";\n    }\n\n    String genCsharpHashCode(String fname) {\n        return \"     ret = (\"+fname+\")?0:1;\\n\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JBuffer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JBuffer extends JCompType {\n    \n    /** Creates a new instance of JBuffer */\n    public JBuffer() {\n        super(\"struct buffer\", \" ::std::string\", \"byte[]\", \"byte[]\", \"Buffer\", \"byte[]\", \"byte[]\");\n    }\n    \n    public String genCppGetSet(String fname, int fIdx) {\n        String cgetFunc = \"  virtual const \"+getCppType()+\"& get\"+fname+\"() const {\\n\";\n        cgetFunc += \"    return m\"+fname+\";\\n\";\n        cgetFunc += \"  }\\n\";\n        String getFunc = \"  virtual \"+getCppType()+\"& get\"+fname+\"() {\\n\";\n        getFunc += \"    bs_.set(\"+fIdx+\");return m\"+fname+\";\\n\";\n        getFunc += \"  }\\n\";\n        return cgetFunc + getFunc;\n    }\n    \n    public String getSignature() {\n        return \"B\";\n    }\n    \n    public String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        String ret = \"\";\n        if (decl) {\n            ret = \"    byte[] \"+fname+\";\\n\";\n        }\n        return ret + \"        \"+fname+\"=a_.readBuffer(\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    public String genJavaWriteWrapper(String fname, String tag) {\n        return \"        a_.writeBuffer(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    public String genJavaCompareTo(String fname, String other) {\n      StringBuilder sb = new StringBuilder();\n      sb.append(\"    {\\n\");\n      sb.append(\"      byte[] my = \"+fname+\";\\n\");\n      sb.append(\"      byte[] ur = \"+other+\";\\n\");\n      sb.append(\"      ret = org.apache.jute.Utils.compareBytes(my,0,my.length,ur,0,ur.length);\\n\");\n      sb.append(\"    }\\n\");\n      return sb.toString();\n    }\n    \n    public String genJavaCompareTo(String fname) {\n        return genJavaCompareTo(fname, \"peer.\"+fname);\n    }\n\t   public String genJavaCompareToWrapper(String fname, String other) {\n      return \"    \"+genJavaCompareTo(fname, other);\n    }\n\t   \n\tpublic String genCsharpHashCode(String fname) {\n\t    return \"    ret = SequenceUtils.GetHashCodeEx(\"+fname+\");\\n\";\n\t}\n\n    public String genJavaEquals(String fname, String peer) {\n        return \"    ret = org.apache.jute.Utils.bufEquals(\"+fname+\",\"+peer+\");\\n\";\n    }\n    \n    public String genCsharpEquals(String fname, String peer) {\n        return \"    ret = SequenceUtils.EqualsEx(\"+fname+\",\"+peer+\");\\n\";\n    }\n    \n    public String genJavaHashCode(String fname) {\n        return \"    ret = java.util.Arrays.toString(\"+fname+\").hashCode();\\n\";\n    }\n    \n    public String genJavaSlurpBytes(String b, String s, String l) {\n      StringBuilder sb = new StringBuilder();\n      sb.append(\"        {\\n\");\n      sb.append(\"           int i = org.apache.jute.Utils.readVInt(\"+b+\", \"+s+\");\\n\");\n      sb.append(\"           int z = WritableUtils.getVIntSize(i);\\n\");\n      sb.append(\"           \"+s+\" += z+i; \"+l+\" -= (z+i);\\n\");\n      sb.append(\"        }\\n\");\n      return sb.toString();\n    }\n    \n    public String genJavaCompareBytes() {\n      StringBuilder sb = new StringBuilder();\n      sb.append(\"        {\\n\");\n      sb.append(\"           int i1 = org.apache.jute.Utils.readVInt(b1, s1);\\n\");\n      sb.append(\"           int i2 = org.apache.jute.Utils.readVInt(b2, s2);\\n\");\n      sb.append(\"           int z1 = WritableUtils.getVIntSize(i1);\\n\");\n      sb.append(\"           int z2 = WritableUtils.getVIntSize(i2);\\n\");\n      sb.append(\"           s1+=z1; s2+=z2; l1-=z1; l2-=z2;\\n\");\n      sb.append(\"           int r1 = org.apache.jute.Utils.compareBytes(b1,s1,l1,b2,s2,l2);\\n\");\n      sb.append(\"           if (r1 != 0) { return (r1<0)?-1:0; }\\n\");\n      sb.append(\"           s1+=i1; s2+=i2; l1-=i1; l1-=i2;\\n\");\n      sb.append(\"        }\\n\");\n      return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JByte.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JByte extends JType {\n    \n    /** Creates a new instance of JByte */\n    public JByte() {\n        super(\"char\", \"int8_t\", \"byte\", \"byte\", \"Byte\", \"Byte\", \"byte\", \"toByte\");\n    }\n    \n    public String getSignature() {\n        return \"b\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JCompType.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n * Abstract base class for all the \"compound\" types such as ustring,\n * buffer, vector, map, and record.\n */\nabstract class JCompType extends JType {\n    \n    /** Creates a new instance of JCompType */\n    JCompType(String cType, String cppType, String csharpType, String javaType, String suffix, String wrapper, String csharpWrapper) {\n        super(cType, cppType, csharpType, javaType, suffix, wrapper, csharpWrapper, null);\n    }\n    \n    String genCppGetSet(String fname, int fIdx) {\n        String cgetFunc = \"  virtual const \"+getCppType()+\"& get\"+fname+\"() const {\\n\";\n        cgetFunc += \"    return m\"+fname+\";\\n\";\n        cgetFunc += \"  }\\n\";\n        String getFunc = \"  virtual \"+getCppType()+\"& get\"+fname+\"() {\\n\";\n        getFunc += \"    bs_.set(\"+fIdx+\");return m\"+fname+\";\\n\";\n        getFunc += \"  }\\n\";\n        return cgetFunc + getFunc;\n    }\n    \n    String genJavaCompareTo(String fname) {\n        return \"    ret = \"+fname+\".compareTo(peer.\"+fname+\");\\n\";\n    }\n    \n    String genJavaEquals(String fname, String peer) {\n        return \"    ret = \"+fname+\".equals(\"+peer+\");\\n\";\n    }\n    \n    String genJavaHashCode(String fname) {\n        return \"    ret = \"+fname+\".hashCode();\\n\";\n    }\n\n    String genCsharpHashCode(String fname) {\n        return \"    ret = \"+fname+\".GetHashCode();\\n\";\n    }\n\n    String genCsharpEquals(String name, String peer) {\n        return \"    ret = \"+name+\".Equals(\"+peer+\");\\n\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JDouble.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JDouble extends JType {\n    \n    /** Creates a new instance of JDouble */\n    public JDouble() {\n        super(\"double\", \"double\", \"double\", \"double\", \"Double\", \"Double\", \"double\", \"toDouble\");\n    }\n    \n    public String getSignature() {\n        return \"d\";\n    }\n    \n    public String genJavaHashCode(String fname) {\n        String tmp = \"Double.doubleToLongBits(\"+fname+\")\";\n        return \"    ret = (int)(\"+tmp+\"^(\"+tmp+\">>>32));\\n\";\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JField.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JField {\n    private JType mType;\n    private String mName;\n    /**\n     * Creates a new instance of JField\n     */\n    public JField(JType type, String name) {\n        mType = type;\n        mName = name;\n    }\n    \n    public String getSignature() {\n        return mType.getSignature();\n    }\n    \n    public String genCppDecl() {\n        return mType.genCppDecl(mName);\n    }\n    \n\tpublic String genCDecl() {\n\t\treturn mType.genCDecl(mName);\n\t}\n\n    public String genCsharpDecl() {\n        return mType.genCsharpDecl(mName);\n    }\n\n    public String genCsharpConstructorParam(String fname) {\n        return mType.genCsharpConstructorParam(fname);\n    }\n\t\n    public String genJavaDecl() {\n        return mType.genJavaDecl(mName);\n    }\n    \n    public String genJavaConstructorParam(String fname) {\n        return mType.genJavaConstructorParam(fname);\n    }\n    \n    public String getName() {\n        return mName;\n    }\n\n    public String getCsharpName() {\n        return mName;\n    }\n    \n    public String getTag() {\n        return mName;\n    }\n    \n    public JType getType() {\n        return mType;\n    }\n    \n    public String genCppGetSet(int fIdx) {\n        return mType.genCppGetSet(mName, fIdx);\n    }\n\n    public String genCsharpConstructorSet(String fname) {\n        return mType.genCsharpConstructorSet(mName, fname);\n    }\n\n public String genCsharpGetSet(int fIdx) {\n        return mType.genCsharpGetSet(getCsharpName(), fIdx);\n    }\n\n    public String genCsharpWriteMethodName() {\n        return mType.genCsharpWriteMethod(getCsharpName(), getTag());\n    }\n\n    public String genCsharpReadMethodName() {\n        return mType.genCsharpReadMethod(getCsharpName(), getTag());\n    }\n\n    public String genJavaGetSet(int fIdx) {\n        return mType.genJavaGetSet(mName, fIdx);\n    }\n    \n    public String genJavaWriteMethodName() {\n        return mType.genJavaWriteMethod(getName(), getTag());\n    }\n    \n    public String genJavaReadMethodName() {\n        return mType.genJavaReadMethod(getName(), getTag());\n    }\n    \n    public String genJavaCompareTo() {\n        return mType.genJavaCompareTo(getName());\n    }\n    \n    public String genJavaEquals() {\n        return mType.genJavaEquals(getName(), \"peer.\"+getName());\n    }\n    \n    public String genJavaHashCode() {\n        return mType.genJavaHashCode(getName());\n    }\n\n    public String genJavaConstructorSet(String fname) {\n        return mType.genJavaConstructorSet(mName, fname);\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JFile.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\n/**\n * Container for the Hadoop Record DDL.\n * The main components of the file are filename, list of included files,\n * and records defined in that file.\n *\n */\npublic class JFile {\n    \n    private String mName;\n    private ArrayList<JFile> mInclFiles;\n    private ArrayList<JRecord> mRecords;\n    \n    /** Creates a new instance of JFile\n     *\n     * @param name possibly full pathname to the file\n     * @param inclFiles included files (as JFile)\n     * @param recList List of records defined within this file\n     */\n    public JFile(String name, ArrayList<JFile> inclFiles,\n            ArrayList<JRecord> recList)\n    {\n        mName = name;\n        mInclFiles = inclFiles;\n        mRecords = recList;\n    }\n    \n    /** Strip the other pathname components and return the basename */\n    String getName() {\n        int idx = mName.lastIndexOf('/');\n        return (idx > 0) ? mName.substring(idx) : mName; \n    }\n    \n    /** Generate record code in given language. Language should be all\n     *  lowercase.\n     * @param outputDirectory \n     */\n    public void genCode(String language, File outputDirectory)\n        throws IOException\n    {\n        if (\"c++\".equals(language)) {\n            CppGenerator gen = new CppGenerator(mName, mInclFiles, mRecords,\n                    outputDirectory);\n            gen.genCode();\n        } else if (\"java\".equals(language)) {\n            JavaGenerator gen = new JavaGenerator(mName, mInclFiles, mRecords,\n                    outputDirectory);\n            gen.genCode();\n        } else if (\"c\".equals(language)) {\n        \tCGenerator gen = new CGenerator(mName, mInclFiles, mRecords,\n        \t        outputDirectory);\n        \tgen.genCode();\n        } else if (\"csharp\".equals(language)) {\n        \tCSharpGenerator gen = new CSharpGenerator(mName, mInclFiles, mRecords,\n        \t        outputDirectory);\n        \tgen.genCode();\n        } else {\n            throw new IOException(\"Cannnot recognize language:\" + language);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JFloat.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JFloat extends JType {\n    \n    /** Creates a new instance of JFloat */\n    public JFloat() {\n        super(\"float\", \"float\", \"float\", \"float\", \"Float\", \"Float\", \"float\", \"toFloat\");\n    }\n    \n    public String getSignature() {\n        return \"f\";\n    }\n    \n    public String genJavaHashCode(String fname) {\n        return \"    ret = Float.floatToIntBits(\"+fname+\");\\n\";\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JInt.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JInt extends JType {\n    \n    /** Creates a new instance of JInt */\n    public JInt() {\n        super(\"int32_t\", \"int32_t\", \"int\", \"int\", \"Int\", \"Integer\", \"int\", \"toInt\");\n    }\n    \n    public String getSignature() {\n        return \"i\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JLong.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JLong extends JType {\n    \n    /** Creates a new instance of JLong */\n    public JLong() {\n        super(\"int64_t\", \"int64_t\", \"long\", \"long\", \"Long\", \"Long\", \"long\", \"toLong\");\n    }\n    \n    public String getSignature() {\n        return \"l\";\n    }\n    \n    public String genJavaHashCode(String fname) {\n        return \"    ret = (int) (\"+fname+\"^(\"+fname+\">>>32));\\n\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JMap.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JMap extends JCompType {\n   \n    static private int level = 0;\n    \n    static private String getLevel() { return Integer.toString(level); }\n    \n    static private void incrLevel() { level++; }\n    \n    static private void decrLevel() { level--; }\n    \n    static private String getId(String id) { return id+getLevel(); }\n    \n    private JType mKey;\n    private JType mValue;\n    \n    /** Creates a new instance of JMap */\n    public JMap(JType t1, JType t2) {\n        super(\"#error\", \" ::std::map<\"+t1.getCppType()+\",\"+t2.getCppType()+\">\",\n                \"System.Collections.Generic.SortedDictionary<string, string>\", \"java.util.TreeMap\", \"Map\", \"System.Collections.Generic.SortedDictionary<string, string>\", \"java.util.TreeMap\");\n        mKey = t1;\n        mValue = t2;\n    }\n    \n    public String getSignature() {\n        return \"{\" + mKey.getSignature() + mValue.getSignature() +\"}\";\n    }\n    \n    public String genJavaCompareTo(String fname) {\n        return \"    throw new UnsupportedOperationException(\\\"comparing \"\n            + fname + \" is unimplemented\\\");\\n\";\n    }\n    \n    public String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        StringBuilder ret = new StringBuilder(\"\");\n        if (decl) {\n            ret.append(\"    java.util.TreeMap \"+fname+\";\\n\");\n        }\n        ret.append(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      org.apache.jute.Index \"+getId(\"midx\")+\" = a_.startMap(\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      \"+fname+\"=new java.util.TreeMap();\\n\");\n        ret.append(\"      for (; !\"+getId(\"midx\")+\".done(); \"+getId(\"midx\")+\".incr()) {\\n\");\n        ret.append(mKey.genJavaReadWrapper(getId(\"k\"),getId(\"k\"),true));\n        ret.append(mValue.genJavaReadWrapper(getId(\"v\"),getId(\"v\"),true));\n        ret.append(\"        \"+fname+\".put(\"+getId(\"k\")+\",\"+getId(\"v\")+\");\\n\");\n        ret.append(\"      }\\n\");\n        ret.append(\"    a_.endMap(\\\"\"+tag+\"\\\");\\n\");\n        decrLevel();\n        ret.append(\"    }\\n\");\n        return ret.toString();\n    }\n    \n    public String genJavaReadMethod(String fname, String tag) {\n        return genJavaReadWrapper(fname, tag, false);\n    }\n    \n    public String genJavaWriteWrapper(String fname, String tag) {\n        StringBuilder ret = new StringBuilder(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      a_.startMap(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      java.util.Set \"+getId(\"es\")+\" = \"+fname+\".entrySet();\\n\");\n        ret.append(\"      for(java.util.Iterator \"+getId(\"midx\")+\" = \"+getId(\"es\")+\".iterator(); \"+getId(\"midx\")+\".hasNext(); ) {\\n\");\n        ret.append(\"        java.util.Map.Entry \"+getId(\"me\")+\" = (java.util.Map.Entry) \"+getId(\"midx\")+\".next();\\n\");\n        ret.append(\"        \"+mKey.getJavaWrapperType()+\" \"+getId(\"k\")+\" = (\"+mKey.getJavaWrapperType()+\") \"+getId(\"me\")+\".getKey();\\n\");\n        ret.append(\"        \"+mValue.getJavaWrapperType()+\" \"+getId(\"v\")+\" = (\"+mValue.getJavaWrapperType()+\") \"+getId(\"me\")+\".getValue();\\n\");\n        ret.append(mKey.genJavaWriteWrapper(getId(\"k\"),getId(\"k\")));\n        ret.append(mValue.genJavaWriteWrapper(getId(\"v\"),getId(\"v\")));\n        ret.append(\"      }\\n\");\n        ret.append(\"      a_.endMap(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"    }\\n\");\n        decrLevel();\n        return ret.toString();\n    }\n    \n    public String genJavaWriteMethod(String fname, String tag) {\n        return genJavaWriteWrapper(fname, tag);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JRecord.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\n\n/**\n *\n */\npublic class JRecord extends JCompType {\n\n    private String mFQName;\n    private String mName;\n    private String mModule;\n    private ArrayList<JField> mFields;\n\n    /**\n     * Creates a new instance of JRecord\n     */\n    public JRecord(String name, ArrayList<JField> flist) {\n        super(\"struct \" + name.substring(name.lastIndexOf('.')+1),\n                name.replaceAll(\"\\\\.\",\"::\"), name, name, \"Record\", name, name+\"IRecord\");\n        mFQName = name;\n        int idx = name.lastIndexOf('.');\n        mName = name.substring(idx+1);\n        mModule = name.substring(0, idx);\n        mFields = flist;\n    }\n\n    public String getName() {\n        return mName;\n    }\n\n    public String getCsharpName() {\n        return mName;\n    }\n\n    public String getJavaFQName() {\n        return mFQName;\n    }\n\n    public String getCppFQName() {\n        return mFQName.replaceAll(\"\\\\.\", \"::\");\n    }\n\n    public String getJavaPackage() {\n        return mModule;\n    }\n\n    public String getCppNameSpace() {\n        return mModule.replaceAll(\"\\\\.\", \"::\");\n    }\n\n    public ArrayList<JField> getFields() {\n        return mFields;\n    }\n\n    public String getSignature() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"L\").append(mName).append(\"(\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            String s = i.next().getSignature();\n            sb.append(s);\n        }\n        sb.append(\")\");\n        return sb.toString();\n    }\n\n    public String genCppDecl(String fname) {\n        return \"  \"+ getCppNameSpace() + \"::\" + mName+\" m\"+fname+\";\\n\";\n    }\n\n    public String genJavaReadMethod(String fname, String tag) {\n        return genJavaReadWrapper(fname, tag, false);\n    }\n\n    public String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        StringBuilder ret = new StringBuilder(\"\");\n        if (decl) {\n            ret.append(\"    \"+getJavaFQName()+\" \"+fname+\";\\n\");\n        }\n        ret.append(\"    \"+fname+\"= new \"+getJavaFQName()+\"();\\n\");\n        ret.append(\"    a_.readRecord(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        return ret.toString();\n    }\n\n    public String genJavaWriteWrapper(String fname, String tag) {\n        return \"    a_.writeRecord(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n\n     String genCsharpReadMethod(String fname, String tag) {\n        //return \"    \"+capitalize(fname)+\"=a_.Read\"+mMethodSuffix+\"(\" + capitalize(fname) + \",\\\"\"+tag+\"\\\");\\n\";\n        return genCsharpReadWrapper(fname, tag, false);\n    }\n\n    public String genCsharpReadWrapper(String fname, String tag, boolean decl) {\n        StringBuilder ret = new StringBuilder(\"\");\n        if (decl) {\n            ret.append(\"    \"+mFQName+\" \"+fname+\";\\n\");\n        }\n        ret.append(\"    \"+fname+\"= new \"+mFQName+\"();\\n\");\n        ret.append(\"    a_.readRecord(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        return ret.toString();\n    }\n\n    public String genCsharpWriteWrapper(String fname, String tag) {\n        return \"    a_.writeRecord(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n\n    static HashMap<String, String> vectorStructs = new HashMap<String, String>();\n    public void genCCode(FileWriter h, FileWriter c) throws IOException {\n        for (JField f : mFields) {\n            if (f.getType() instanceof JVector) {\n                JVector jv = (JVector)f.getType();\n                JType jvType = jv.getElementType();\n                String struct_name = JVector.extractVectorName(jvType);\n                if (vectorStructs.get(struct_name) == null) {\n                    vectorStructs.put(struct_name, struct_name);\n                    h.write(\"struct \" + struct_name + \" {\\n    int32_t count;\\n\" + jv.getElementType().genCDecl(\"*data\") + \"\\n};\\n\");\n                    h.write(\"int serialize_\" + struct_name + \"(struct oarchive *out, const char *tag, struct \" + struct_name + \" *v);\\n\");\n                    h.write(\"int deserialize_\" + struct_name + \"(struct iarchive *in, const char *tag, struct \" + struct_name + \" *v);\\n\");\n                    h.write(\"int allocate_\" + struct_name + \"(struct \" + struct_name + \" *v, int32_t len);\\n\");\n                    h.write(\"int deallocate_\" + struct_name + \"(struct \" + struct_name + \" *v);\\n\");\n                    c.write(\"int allocate_\" + struct_name + \"(struct \" + struct_name + \" *v, int32_t len) {\\n\");\n                    c.write(\"    if (!len) {\\n\");\n                    c.write(\"        v->count = 0;\\n\");\n                    c.write(\"        v->data = 0;\\n\");\n                    c.write(\"    } else {\\n\");\n                    c.write(\"        v->count = len;\\n\");\n                    c.write(\"        v->data = calloc(sizeof(*v->data), len);\\n\");\n                    c.write(\"    }\\n\");\n                    c.write(\"    return 0;\\n\");\n                    c.write(\"}\\n\");\n                    c.write(\"int deallocate_\" + struct_name + \"(struct \" + struct_name + \" *v) {\\n\");\n                    c.write(\"    if (v->data) {\\n\");\n                    c.write(\"        int32_t i;\\n\");\n                    c.write(\"        for(i=0;i<v->count; i++) {\\n\");\n                    c.write(\"            deallocate_\"+JRecord.extractMethodSuffix(jvType)+\"(&v->data[i]);\\n\");\n                    c.write(\"        }\\n\");\n                    c.write(\"        free(v->data);\\n\");\n                    c.write(\"        v->data = 0;\\n\");\n                    c.write(\"    }\\n\");\n                    c.write(\"    return 0;\\n\");\n                    c.write(\"}\\n\");\n                    c.write(\"int serialize_\" + struct_name + \"(struct oarchive *out, const char *tag, struct \" + struct_name + \" *v)\\n\");\n                    c.write(\"{\\n\");\n                    c.write(\"    int32_t count = v->count;\\n\");\n                    c.write(\"    int rc = 0;\\n\");\n                    c.write(\"    int32_t i;\\n\");\n                    c.write(\"    rc = out->start_vector(out, tag, &count);\\n\");\n                    c.write(\"    for(i=0;i<v->count;i++) {\\n\");\n                    genSerialize(c, jvType, \"data\", \"data[i]\");\n                    c.write(\"    }\\n\");\n                    c.write(\"    rc = rc ? rc : out->end_vector(out, tag);\\n\");\n                    c.write(\"    return rc;\\n\");\n                    c.write(\"}\\n\");\n                    c.write(\"int deserialize_\" + struct_name + \"(struct iarchive *in, const char *tag, struct \" + struct_name + \" *v)\\n\");\n                    c.write(\"{\\n\");\n                    c.write(\"    int rc = 0;\\n\");\n                    c.write(\"    int32_t i;\\n\");\n                    c.write(\"    rc = in->start_vector(in, tag, &v->count);\\n\");\n                    c.write(\"    v->data = calloc(v->count, sizeof(*v->data));\\n\");\n                    c.write(\"    for(i=0;i<v->count;i++) {\\n\");\n                    genDeserialize(c, jvType, \"value\", \"data[i]\");\n                    c.write(\"    }\\n\");\n                    c.write(\"    rc = in->end_vector(in, tag);\\n\");\n                    c.write(\"    return rc;\\n\");\n                    c.write(\"}\\n\");\n\n                }\n            }\n        }\n        String rec_name = getName();\n        h.write(\"struct \" + rec_name + \" {\\n\");\n        for (JField f : mFields) {\n            h.write(f.genCDecl());\n        }\n        h.write(\"};\\n\");\n        h.write(\"int serialize_\" + rec_name + \"(struct oarchive *out, const char *tag, struct \" + rec_name + \" *v);\\n\");\n        h.write(\"int deserialize_\" + rec_name + \"(struct iarchive *in, const char *tag, struct \" + rec_name + \"*v);\\n\");\n        h.write(\"void deallocate_\" + rec_name + \"(struct \" + rec_name + \"*);\\n\");\n        c.write(\"int serialize_\" + rec_name + \"(struct oarchive *out, const char *tag, struct \" + rec_name + \" *v)\");\n        c.write(\"{\\n\");\n        c.write(\"    int rc;\\n\");\n        c.write(\"    rc = out->start_record(out, tag);\\n\");\n        for(JField f : mFields) {\n            genSerialize(c, f.getType(), f.getTag(), f.getName());\n        }\n        c.write(\"    rc = rc ? rc : out->end_record(out, tag);\\n\");\n        c.write(\"    return rc;\\n\");\n        c.write(\"}\\n\");\n        c.write(\"int deserialize_\" + rec_name + \"(struct iarchive *in, const char *tag, struct \" + rec_name + \"*v)\");\n        c.write(\"{\\n\");\n        c.write(\"    int rc;\\n\");\n        c.write(\"    rc = in->start_record(in, tag);\\n\");\n        for(JField f : mFields) {\n            genDeserialize(c, f.getType(), f.getTag(), f.getName());\n        }\n        c.write(\"    rc = rc ? rc : in->end_record(in, tag);\\n\");\n        c.write(\"    return rc;\\n\");\n        c.write(\"}\\n\");\n        c.write(\"void deallocate_\" + rec_name + \"(struct \" + rec_name + \"*v)\");\n        c.write(\"{\\n\");\n        for(JField f : mFields) {\n            if (f.getType() instanceof JRecord) {\n                c.write(\"    deallocate_\" + extractStructName(f.getType()) + \"(&v->\" + f.getName() + \");\\n\");\n            } else if (f.getType() instanceof JVector) {\n                JVector vt = (JVector)f.getType();\n                c.write(\"    deallocate_\" + JVector.extractVectorName(vt.getElementType())+ \"(&v->\"+f.getName()+\");\\n\");\n            } else if (f.getType() instanceof JCompType) {\n                c.write(\"    deallocate_\" + extractMethodSuffix(f.getType()) + \"(&v->\"+f.getName()+\");\\n\");\n            }\n        }\n        c.write(\"}\\n\");\n    }\n\n    private void genSerialize(FileWriter c, JType type, String tag, String name) throws IOException {\n        if (type instanceof JRecord) {\n            c.write(\"    rc = rc ? rc : serialize_\" + extractStructName(type) + \"(out, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        } else if (type instanceof JVector) {\n            c.write(\"    rc = rc ? rc : serialize_\" + JVector.extractVectorName(((JVector)type).getElementType()) + \"(out, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        } else {\n            c.write(\"    rc = rc ? rc : out->serialize_\" + extractMethodSuffix(type) + \"(out, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        }\n    }\n\n    private void genDeserialize(FileWriter c, JType type, String tag, String name) throws IOException {\n        if (type instanceof JRecord) {\n            c.write(\"    rc = rc ? rc : deserialize_\" + extractStructName(type) + \"(in, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        } else if (type instanceof JVector) {\n            c.write(\"    rc = rc ? rc : deserialize_\" + JVector.extractVectorName(((JVector)type).getElementType()) + \"(in, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        } else {\n            c.write(\"    rc = rc ? rc : in->deserialize_\" + extractMethodSuffix(type) + \"(in, \\\"\" + tag + \"\\\", &v->\" + name + \");\\n\");\n        }\n    }\n\n    static String extractMethodSuffix(JType t) {\n        if (t instanceof JRecord) {\n            return extractStructName(t);\n        }\n        return t.getMethodSuffix();\n    }\n\n    static private String extractStructName(JType t) {\n        String type = t.getCType();\n        if (!type.startsWith(\"struct \")) return type;\n        return type.substring(\"struct \".length());\n    }\n\n    public void genCppCode(FileWriter hh, FileWriter cc)\n        throws IOException {\n        String[] ns = getCppNameSpace().split(\"::\");\n        for (int i = 0; i < ns.length; i++) {\n            hh.write(\"namespace \"+ns[i]+\" {\\n\");\n        }\n\n        hh.write(\"class \"+getName()+\" : public ::hadoop::Record {\\n\");\n        hh.write(\"private:\\n\");\n\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            JField jf = i.next();\n            hh.write(jf.genCppDecl());\n        }\n        hh.write(\"  mutable std::bitset<\"+mFields.size()+\"> bs_;\\n\");\n        hh.write(\"public:\\n\");\n        hh.write(\"  virtual void serialize(::hadoop::OArchive& a_, const char* tag) const;\\n\");\n        hh.write(\"  virtual void deserialize(::hadoop::IArchive& a_, const char* tag);\\n\");\n        hh.write(\"  virtual const ::std::string& type() const;\\n\");\n        hh.write(\"  virtual const ::std::string& signature() const;\\n\");\n        hh.write(\"  virtual bool validate() const;\\n\");\n        hh.write(\"  virtual bool operator<(const \"+getName()+\"& peer_) const;\\n\");\n        hh.write(\"  virtual bool operator==(const \"+getName()+\"& peer_) const;\\n\");\n        hh.write(\"  virtual ~\"+getName()+\"() {};\\n\");\n        int fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            hh.write(jf.genCppGetSet(fIdx));\n        }\n        hh.write(\"}; // end record \"+getName()+\"\\n\");\n        for (int i=ns.length-1; i>=0; i--) {\n            hh.write(\"} // end namespace \"+ns[i]+\"\\n\");\n        }\n        cc.write(\"void \"+getCppFQName()+\"::serialize(::hadoop::OArchive& a_, const char* tag) const {\\n\");\n        cc.write(\"  if (!validate()) throw new ::hadoop::IOException(\\\"All fields not set.\\\");\\n\");\n        cc.write(\"  a_.startRecord(*this,tag);\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            String name = jf.getName();\n            if (jf.getType() instanceof JBuffer) {\n                cc.write(\"  a_.serialize(m\"+name+\",m\"+name+\".length(),\\\"\"+jf.getTag()+\"\\\");\\n\");\n            } else {\n                cc.write(\"  a_.serialize(m\"+name+\",\\\"\"+jf.getTag()+\"\\\");\\n\");\n            }\n            cc.write(\"  bs_.reset(\"+fIdx+\");\\n\");\n        }\n        cc.write(\"  a_.endRecord(*this,tag);\\n\");\n        cc.write(\"  return;\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"void \"+getCppFQName()+\"::deserialize(::hadoop::IArchive& a_, const char* tag) {\\n\");\n        cc.write(\"  a_.startRecord(*this,tag);\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            String name = jf.getName();\n            if (jf.getType() instanceof JBuffer) {\n                cc.write(\"  { size_t len=0; a_.deserialize(m\"+name+\",len,\\\"\"+jf.getTag()+\"\\\");}\\n\");\n            } else {\n                cc.write(\"  a_.deserialize(m\"+name+\",\\\"\"+jf.getTag()+\"\\\");\\n\");\n            }\n            cc.write(\"  bs_.set(\"+fIdx+\");\\n\");\n        }\n        cc.write(\"  a_.endRecord(*this,tag);\\n\");\n        cc.write(\"  return;\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"bool \"+getCppFQName()+\"::validate() const {\\n\");\n        cc.write(\"  if (bs_.size() != bs_.count()) return false;\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = (JField) i.next();\n            JType type = jf.getType();\n            if (type instanceof JRecord) {\n                cc.write(\"  if (!m\"+jf.getName()+\".validate()) return false;\\n\");\n            }\n        }\n        cc.write(\"  return true;\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"bool \"+getCppFQName()+\"::operator< (const \"+getCppFQName()+\"& peer_) const {\\n\");\n        cc.write(\"  return (1\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            JField jf = i.next();\n            String name = jf.getName();\n            cc.write(\"    && (m\"+name+\" < peer_.m\"+name+\")\\n\");\n        }\n        cc.write(\"  );\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"bool \"+getCppFQName()+\"::operator== (const \"+getCppFQName()+\"& peer_) const {\\n\");\n        cc.write(\"  return (1\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            JField jf = i.next();\n            String name = jf.getName();\n            cc.write(\"    && (m\"+name+\" == peer_.m\"+name+\")\\n\");\n        }\n        cc.write(\"  );\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"const ::std::string&\"+getCppFQName()+\"::type() const {\\n\");\n        cc.write(\"  static const ::std::string type_(\\\"\"+mName+\"\\\");\\n\");\n        cc.write(\"  return type_;\\n\");\n        cc.write(\"}\\n\");\n\n        cc.write(\"const ::std::string&\"+getCppFQName()+\"::signature() const {\\n\");\n        cc.write(\"  static const ::std::string sig_(\\\"\"+getSignature()+\"\\\");\\n\");\n        cc.write(\"  return sig_;\\n\");\n        cc.write(\"}\\n\");\n\n    }\n\n    public void genJavaCode(File outputDirectory) throws IOException {\n        String pkg = getJavaPackage();\n        String pkgpath = pkg.replaceAll(\"\\\\.\", \"/\");\n        File pkgdir = new File(outputDirectory, pkgpath);\n        if (!pkgdir.exists()) {\n            // create the pkg directory\n            if (!pkgdir.mkdirs()) {\n                throw new IOException(\"Cannnot create directory: \" + pkgpath);\n            }\n        } else if (!pkgdir.isDirectory()) {\n            throw new IOException(pkgpath + \" is not a directory.\");\n        }\n        File jfile = new File(pkgdir, getName()+\".java\");\n        FileWriter jj = null;\n        try{\n            jj = new FileWriter(jfile);\n        jj.write(\"// File generated by hadoop record compiler. Do not edit.\\n\");\n        jj.write(\"/**\\n\");\n        jj.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n        jj.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n        jj.write(\"* distributed with this work for additional information\\n\");\n        jj.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n        jj.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n        jj.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n        jj.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n        jj.write(\"*\\n\");\n        jj.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n        jj.write(\"*\\n\");\n        jj.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n        jj.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n        jj.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n        jj.write(\"* See the License for the specific language governing permissions and\\n\");\n        jj.write(\"* limitations under the License.\\n\");\n        jj.write(\"*/\\n\");\n        jj.write(\"\\n\");\n        jj.write(\"package \"+getJavaPackage()+\";\\n\\n\");\n        jj.write(\"import org.apache.jute.*;\\n\");\n            jj.write(\"import org.apache.yetus.audience.InterfaceAudience;\\n\");\n            jj.write(\"@InterfaceAudience.Public\\n\");\n        jj.write(\"public class \"+getName()+\" implements Record {\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            JField jf = i.next();\n            jj.write(jf.genJavaDecl());\n        }\n        jj.write(\"  public \"+getName()+\"() {\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public \"+getName()+\"(\\n\");\n        int fIdx = 0;\n        int fLen = mFields.size();\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaConstructorParam(jf.getName()));\n            jj.write((fLen-1 == fIdx)?\"\":\",\\n\");\n        }\n        jj.write(\") {\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaConstructorSet(jf.getName()));\n        }\n        jj.write(\"  }\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaGetSet(fIdx));\n        }\n        jj.write(\"  public void serialize(OutputArchive a_, String tag) throws java.io.IOException {\\n\");\n        jj.write(\"    a_.startRecord(this,tag);\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaWriteMethodName());\n        }\n        jj.write(\"    a_.endRecord(this,tag);\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public void deserialize(InputArchive a_, String tag) throws java.io.IOException {\\n\");\n        jj.write(\"    a_.startRecord(tag);\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaReadMethodName());\n        }\n        jj.write(\"    a_.endRecord(tag);\\n\");\n        jj.write(\"}\\n\");\n\n        jj.write(\"  public String toString() {\\n\");\n        jj.write(\"    try {\\n\");\n        jj.write(\"      java.io.ByteArrayOutputStream s =\\n\");\n        jj.write(\"        new java.io.ByteArrayOutputStream();\\n\");\n        jj.write(\"      CsvOutputArchive a_ = \\n\");\n        jj.write(\"        new CsvOutputArchive(s);\\n\");\n        jj.write(\"      a_.startRecord(this,\\\"\\\");\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaWriteMethodName());\n        }\n        jj.write(\"      a_.endRecord(this,\\\"\\\");\\n\");\n        jj.write(\"      return new String(s.toByteArray(), \\\"UTF-8\\\");\\n\");\n        jj.write(\"    } catch (Throwable ex) {\\n\");\n        jj.write(\"      ex.printStackTrace();\\n\");\n        jj.write(\"    }\\n\");\n        jj.write(\"    return \\\"ERROR\\\";\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public void write(java.io.DataOutput out) throws java.io.IOException {\\n\");\n        jj.write(\"    BinaryOutputArchive archive = new BinaryOutputArchive(out);\\n\");\n        jj.write(\"    serialize(archive, \\\"\\\");\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public void readFields(java.io.DataInput in) throws java.io.IOException {\\n\");\n        jj.write(\"    BinaryInputArchive archive = new BinaryInputArchive(in);\\n\");\n        jj.write(\"    deserialize(archive, \\\"\\\");\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public int compareTo (Object peer_) throws ClassCastException {\\n\");\n        boolean unimplemented = false;\n        for (JField f : mFields) {\n            if ((f.getType() instanceof JMap)\n                    || (f.getType() instanceof JVector))\n            {\n                unimplemented = true;\n            }\n        }\n        if (unimplemented) {\n            jj.write(\"    throw new UnsupportedOperationException(\\\"comparing \"\n                    + getName() + \" is unimplemented\\\");\\n\");\n        } else {\n            jj.write(\"    if (!(peer_ instanceof \"+getName()+\")) {\\n\");\n            jj.write(\"      throw new ClassCastException(\\\"Comparing different types of records.\\\");\\n\");\n            jj.write(\"    }\\n\");\n            jj.write(\"    \"+getName()+\" peer = (\"+getName()+\") peer_;\\n\");\n            jj.write(\"    int ret = 0;\\n\");\n            for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n                JField jf = i.next();\n                jj.write(jf.genJavaCompareTo());\n                jj.write(\"    if (ret != 0) return ret;\\n\");\n            }\n            jj.write(\"     return ret;\\n\");\n        }\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public boolean equals(Object peer_) {\\n\");\n        jj.write(\"    if (!(peer_ instanceof \"+getName()+\")) {\\n\");\n        jj.write(\"      return false;\\n\");\n        jj.write(\"    }\\n\");\n        jj.write(\"    if (peer_ == this) {\\n\");\n        jj.write(\"      return true;\\n\");\n        jj.write(\"    }\\n\");\n        jj.write(\"    \"+getName()+\" peer = (\"+getName()+\") peer_;\\n\");\n        jj.write(\"    boolean ret = false;\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaEquals());\n            jj.write(\"    if (!ret) return ret;\\n\");\n        }\n        jj.write(\"     return ret;\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"  public int hashCode() {\\n\");\n        jj.write(\"    int result = 17;\\n\");\n        jj.write(\"    int ret;\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            jj.write(jf.genJavaHashCode());\n            jj.write(\"    result = 37*result + ret;\\n\");\n        }\n        jj.write(\"    return result;\\n\");\n        jj.write(\"  }\\n\");\n        jj.write(\"  public static String signature() {\\n\");\n        jj.write(\"    return \\\"\"+getSignature()+\"\\\";\\n\");\n        jj.write(\"  }\\n\");\n\n        jj.write(\"}\\n\");\n\n        } finally {\n            if (jj != null) {\n        jj.close();\n            }\n        }\n\n    }\n\n   public void genCsharpCode(File outputDirectory) throws IOException {\n  String pkg = getJavaPackage();\n        String pkgpath = pkg.replace(\"org.apache.zookeeper\", \"\");\n        pkgpath = pkgpath.replace(\".\", \"/\");\n        File pkgdir = new File(outputDirectory, pkgpath);\n        if (!pkgdir.exists()) {\n            // create the pkg directory\n            if (!pkgdir.mkdirs()) {\n                throw new IOException(\"Cannnot create directory: \" + outputDirectory);\n            }\n        } else if (!pkgdir.isDirectory()) {\n            throw new IOException(pkgdir + \" is not a directory.\");\n        }\n        File csharpFile = new File(pkgdir, getName()+\".cs\");\n        FileWriter cs = null;\n\n        try {\n            cs = new FileWriter(csharpFile);\n        cs.write(\"// File generated by hadoop record compiler. Do not edit.\\n\");\n        cs.write(\"\\n\");\n        cs.write(\"#pragma warning disable\\n\");\n        cs.write(\"\\n\");\n        cs.write(\"using System.Collections.Generic;\\n\");\n        cs.write(\"using org.apache.jute;\\n\");\n        cs.write(\"\\n\");        \n\t\tcs.write(\"namespace \"+getJavaPackage()+\"\\n\");\n        cs.write(\"{\\n\");\n\t\tif(getJavaPackage().equals(\"org.apache.zookeeper.data\"))\n\t\t{\n\t\t\tcs.write(\"public class \"+getName()+\" : Record\\n\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcs.write(\"internal class \"+getName()+\" : Record\\n\");\n\t\t}\n        cs.write(\"{\\n\");\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext();) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpDecl());\n        }\n\t\tcs.write(\"  public \"+ getName()+\"() {}\\n\");\n\t\tcs.write(\"  public \"+getName()+\"(\");\n        int fIdx = 0;\n        int fLen = mFields.size();\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpConstructorParam(jf.getCsharpName()));\n            cs.write((fLen-1 == fIdx)?\"\":\",\");\n        }\n        cs.write(\")\\n{\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpConstructorSet(jf.getCsharpName()));\n        }\n        cs.write(\"  }\\n\");\n\t\t fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpGetSet(fIdx));\n            cs.write(\"\\n\");\n        }\n        cs.write(\"  void Record.serialize(OutputArchive a_, string tag)\\n {\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpWriteMethodName());\n        }\n        cs.write(\"  }\\n\");\n\n        cs.write(\"  void Record.deserialize(InputArchive a_, string tag)\\n{\\n\");\n        fIdx = 0;\n        for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {\n            JField jf = i.next();\n            cs.write(jf.genCsharpReadMethodName());\n        }\n        cs.write(\"}\\n\");\n        cs.write(\"}\\n\");\n        cs.write(\"}\\n\");\n\n        } finally {\n            if (cs != null) {\n        cs.close();\n    }  \n\t}\n\t}\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JString.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JString extends JCompType {\n    \n    /** Creates a new instance of JString */\n    public JString() {\n        super(\"char *\", \" ::std::string\", \"string\", \"String\", \"String\", \"String\", \"string\");\n    }\n    \n    public String getSignature() {\n        return \"s\";\n    }\n    \n    public String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        String ret = \"\";\n        if (decl) {\n            ret = \"    String \"+fname+\";\\n\";\n        }\n        return ret + \"        \"+fname+\"=a_.readString(\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    public String genJavaWriteWrapper(String fname, String tag) {\n        return \"        a_.writeString(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JType.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n * Abstract Base class for all types supported by Hadoop Record I/O.\n * \n */\nabstract public class JType {\n    \n\tprivate String mCName;\n    private String mCppName;\n    private String mCsharpName;\n    private String mJavaName;\n    protected String mMethodSuffix;\n    private String mWrapper;\n    private String mSharpWrapper;\n    private String mUnwrapMethod;\n\n    /**\n     * Creates a new instance of JType\n     */\n    JType(String cname, String cppname, String csharpName, String javaname, String suffix, String wrapper, String csharpWrapper, String unwrap) {\n    \tmCName = cname;\n        mCppName = cppname;\n        mCsharpName = csharpName;\n        mJavaName = javaname;\n        mMethodSuffix = suffix;\n        mWrapper = wrapper;\n        mSharpWrapper = csharpWrapper;\n        mUnwrapMethod = unwrap;\n    }\n    \n    abstract String getSignature();\n    \n    String genCppDecl(String fname) {\n        return \"  \"+mCppName+\" m\"+fname+\";\\n\"; \n    }\n    \n\tString genCDecl(String name) {\n\t\treturn \"    \" + mCName + \" \"+name+\";\\n\"; \n\t}\n\n    public String genCsharpDecl(String name) {\n        return \"  private \"+mCsharpName+\" \" +name+\";\\n\";\n    }\n\n    String genJavaDecl (String fname) {\n        return \"  private \"+mJavaName+\" \" +fname+\";\\n\";\n    }\n    \n    String genJavaConstructorParam (String fname) {\n        return \"        \"+mJavaName+\" \"+fname;\n    }\n    \n    String genCppGetSet(String fname, int fIdx) {\n        String getFunc = \"  virtual \"+mCppName+\" get\"+fname+\"() const {\\n\";\n        getFunc += \"    return m\"+fname+\";\\n\";\n        getFunc += \"  }\\n\";\n        String setFunc = \"  virtual void set\"+fname+\"(\"+mCppName+\" m_) {\\n\";\n        setFunc += \"    m\"+fname+\"=m_; bs_.set(\"+fIdx+\");\\n\";\n        setFunc += \"  }\\n\";\n        return getFunc+setFunc;\n    }\n    \n\t String genCsharpGetSet(String fname, int fIdx) {\n\t\t String funName=fname.equals(\"type\")?\"_Type\":fname;\n\t\t String getFunc = \"  public \"+getCsharpType()+\" get\"+capitalize(funName)+\"() {\";\n\t        getFunc += \"return \"+fname+\";\";\n\t        getFunc += \"  }\\n\";\n\t        String setFunc = \"  internal void set\"+capitalize(funName)+\"(\"+getCsharpType()+\" m_) {\";\n\t        setFunc += fname+\"=m_;\";\n\t        setFunc += \"  }\\n\";\n\t        return getFunc+setFunc;\n    }\n\n    static String capitalize(String s) {\n        return s.substring(0,1).toUpperCase()+s.substring(1);\n    }\n    String genJavaGetSet(String fname, int fIdx) {\n        String getFunc = \"  public \"+mJavaName+\" get\"+capitalize(fname)+\"() {\\n\";\n        getFunc += \"    return \"+fname+\";\\n\";\n        getFunc += \"  }\\n\";\n        String setFunc = \"  public void set\"+capitalize(fname)+\"(\"+mJavaName+\" m_) {\\n\";\n        setFunc += \"    \" + fname+\"=m_;\\n\";\n        setFunc += \"  }\\n\";\n        return getFunc+setFunc;\n    }\n    \n    String getCType() {\n    \treturn mCName;\n    }\n    String getCppType() {\n        return mCppName;\n    }\n    \n    String getCsharpType() {\n        return mCsharpName;\n    }\n\n    String getJavaType() {\n        return mJavaName;\n    }\n   \n    String getJavaWrapperType() {\n        return mWrapper;\n    }\n\n    String getCsharpWrapperType() {\n        return mSharpWrapper;\n    }\n    \n    String getMethodSuffix() {\n        return mMethodSuffix;\n    }\n    \n    String genJavaWriteMethod(String fname, String tag) {\n        return \"    a_.write\"+mMethodSuffix+\"(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    String genJavaReadMethod(String fname, String tag) {\n        return \"    \"+fname+\"=a_.read\"+mMethodSuffix+\"(\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        String ret = \"\";\n        if (decl) {\n            ret = \"    \"+mWrapper+\" \"+fname+\";\\n\";\n        }\n        return ret + \"    \"+fname+\"=new \"+mWrapper+\"(a_.read\"+mMethodSuffix+\"(\\\"\"+tag+\"\\\"));\\n\";\n    }\n    \n    String genJavaWriteWrapper(String fname, String tag) {\n        return \"        a_.write\"+mMethodSuffix+\"(\"+fname+\".\"+mUnwrapMethod+\"(),\\\"\"+tag+\"\\\");\\n\";\n    }\n    \n    String genJavaCompareTo(String fname) {\n        return \"    ret = (\"+fname+\" == peer.\"+fname+\")? 0 :((\"+fname+\"<peer.\"+fname+\")?-1:1);\\n\";\n    }\n    \n    String genJavaEquals(String fname, String peer) {\n        return \"    ret = (\"+fname+\"==\"+peer+\");\\n\";\n    }\n    \n    String genJavaHashCode(String fname) {\n        return \"    ret = (int)\"+fname+\";\\n\";\n    }\n\n    String genJavaConstructorSet(String fname, String name) {\n        return \"    this.\"+fname+\"=\"+name+\";\\n\";\n    }\n\n    String genCsharpWriteMethod(String fname, String tag) {\n        return \"    a_.write\"+mMethodSuffix+\"(\"+fname+\",\\\"\"+tag+\"\\\");\\n\";\n    }\n\n    String genCsharpReadMethod(String fname, String tag) {\n        return \"    \"+fname+\"=a_.read\"+mMethodSuffix+\"(\\\"\"+tag+\"\\\");\\n\";\n    }\n\n    String genCsharpReadWrapper(String fname, String tag, boolean decl) {\n        String ret = \"\";\n        if (decl) {\n            ret = \"    \"+mSharpWrapper+\" \"+fname+\";\\n\";\n        }\n        return ret + \"    \"+fname+\"=a_.read\"+mMethodSuffix+\"(\\\"\"+tag+\"\\\");\\n\";\n    }\n\n    String genCsharpWriteWrapper(String fname, String tag) {\n        if (mUnwrapMethod == null) return \"a_.write\"+mMethodSuffix+\"(\"+fname+\",\"+tag+\");\\n\";\n        return \"        a_.write\"+mMethodSuffix+\"(\"+fname+\".\"+mUnwrapMethod+\"(),\\\"\"+tag+\"\\\");\\n\";\n    }\n\n    String genCsharpEquals(String fname, String peer) {\n    \treturn \"    ret = (\"+fname+\"==\"+peer+\");\\n\";\n    }\n\n    String genCsharpHashCode(String fname) {\n        return \"    ret = (int)\"+fname+\";\\n\";\n    }\n\n    String genCsharpConstructorSet(String mName, String fname) {\n        return \"this.\"+fname+\"=\"+mName+\";\\n\";\n    }\n\n    public String genCsharpConstructorParam(String fname) {\n        return \"  \"+mCsharpName+\" \" +fname;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JVector.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\n/**\n *\n */\npublic class JVector extends JCompType {\n    \n    static private int level = 0;\n    \n    static private String getId(String id) { return id+getLevel(); }\n    \n    static private String getLevel() { return Integer.toString(level); }\n    \n    static private void incrLevel() { level++; }\n    \n    static private void decrLevel() { level--; }\n    \n    private JType mElement;\n    \n    /** Creates a new instance of JVector */\n    public JVector(JType t) {\n        super(\"struct \" + extractVectorName(t), \" ::std::vector<\"+t.getCppType()+\">\", \"List<\"+ t.getCsharpType() + \">\", \"java.util.List<\" + t.getJavaType() + \">\", \"Vector\",\n                 \"List<\" + t.getCsharpType() + \">\", \"java.util.ArrayList<\" + t.getJavaType() + \">\");\n        mElement = t;\n    }\n    \n    public String getSignature() {\n        return \"[\" + mElement.getSignature() + \"]\";\n    }\n    \n    public String genJavaCompareTo(String fname) {\n        return \"    throw new UnsupportedOperationException(\\\"comparing \"\n            + fname + \" is unimplemented\\\");\\n\";\n    }\n    \n    public String genJavaReadWrapper(String fname, String tag, boolean decl) {\n        StringBuilder ret = new StringBuilder(\"\");\n        if (decl) {\n            ret.append(\"      java.util.List \"+fname+\";\\n\");\n        }\n        ret.append(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      Index \"+getId(\"vidx\")+\" = a_.startVector(\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      if (\"+getId(\"vidx\")+\"!= null) {\");\n        ret.append(\"          \"+fname+\"=new java.util.ArrayList<\"+ mElement.getJavaType() + \">();\\n\");\n        ret.append(\"          for (; !\"+getId(\"vidx\")+\".done(); \"+getId(\"vidx\")+\".incr()) {\\n\");\n        ret.append(mElement.genJavaReadWrapper(getId(\"e\"), getId(\"e\"), true));\n        ret.append(\"            \"+fname+\".add(\"+getId(\"e\")+\");\\n\");\n        ret.append(\"          }\\n\");\n        ret.append(\"      }\\n\");\n        ret.append(\"    a_.endVector(\\\"\"+tag+\"\\\");\\n\");\n        decrLevel();\n        ret.append(\"    }\\n\");\n        return ret.toString();\n    }\n    \n    public String genJavaReadMethod(String fname, String tag) {\n        return genJavaReadWrapper(fname, tag, false);\n    }\n    \n    public String genJavaWriteWrapper(String fname, String tag) {\n        StringBuilder ret = new StringBuilder(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      a_.startVector(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      if (\"+fname+\"!= null) {\");\n        ret.append(\"          int \"+getId(\"len\")+\" = \"+fname+\".size();\\n\");\n        ret.append(\"          for(int \"+getId(\"vidx\")+\" = 0; \"+getId(\"vidx\")+\"<\"+getId(\"len\")+\"; \"+getId(\"vidx\")+\"++) {\\n\");\n        ret.append(\"            \"+mElement.getJavaWrapperType()+\" \"+getId(\"e\")+\" = (\"+mElement.getJavaWrapperType()+\") \"+fname+\".get(\"+getId(\"vidx\")+\");\\n\");\n        ret.append(mElement.genJavaWriteWrapper(getId(\"e\"), getId(\"e\")));\n        ret.append(\"          }\\n\");\n        ret.append(\"      }\\n\");\n        ret.append(\"      a_.endVector(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"    }\\n\");\n        decrLevel();\n        return ret.toString();\n    }\n    \n    public String genJavaWriteMethod(String fname, String tag) {\n        return genJavaWriteWrapper(fname, tag);\n    }\n    \n    public JType getElementType() {\n    \treturn mElement;\n    }\n\n    public String genCsharpWriteWrapper(String fname, String tag) {\n        StringBuilder ret = new StringBuilder(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      a_.startVector(\"+fname+\",\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      if (\"+fname+\"!= null) {\");\n\t    ret.append(\"\\n      foreach(var \"+getId(\"e\")+\" in \" + fname + \")\"+mElement.genCsharpWriteWrapper(getId(\"e\"), getId(\"e\")));\n        ret.append(\"      }\\n\");\n        ret.append(\"    }\\n\");\n        decrLevel();\n        return ret.toString();\n    }\n\n    String genCsharpWriteMethod(String fname, String tag) {\n        return genCsharpWriteWrapper(fname, tag);\n    }\n    \n    String genCsharpHashCode(String fname) {\n        return \"    ret = SequenceUtils.GetHashCodeEx(\"+fname+\");\\n\";\n    }\n\n    public String genCsharpReadWrapper(String fname, String tag, boolean decl) {\n        StringBuilder ret = new StringBuilder(\"\");\n        if (decl) {\n            ret.append(\"      List<\" + mElement.getCsharpType()+ \"> \"+fname+\";\\n\");\n        }\n        ret.append(\"    {\\n\");\n        incrLevel();\n        ret.append(\"      Index \"+getId(\"vidx\")+\" = a_.startVector(\\\"\"+tag+\"\\\");\\n\");\n        ret.append(\"      if (\"+getId(\"vidx\")+\"!= null) {\");\n        ret.append(\"          var tmpLst=new List<\"+ mElement.getCsharpType() + \">();\\n\");\n        ret.append(\"          for (; !\"+getId(\"vidx\")+\".done(); \"+getId(\"vidx\")+\".incr()) {\\n\");\n        ret.append(mElement.genCsharpReadWrapper(getId(\"e\"), getId(\"e\"), true));\n        ret.append(\"            tmpLst.Add(\"+getId(\"e\")+\");\\n\");\n        ret.append(\"          }\\n\");\n        ret.append(\"            \"+fname + \"=tmpLst;\\n\");\n        ret.append(\"      }\\n\");\n        decrLevel();\n        ret.append(\"    }\\n\");\n        return ret.toString();\n    }\n    \n    String genCsharpReadMethod(String fname, String tag) {\n        return genCsharpReadWrapper(fname, tag, false);\n    }\n\n    static public String extractVectorName(JType jvType) {\n\t\treturn JRecord.extractMethodSuffix(jvType)+\"_vector\";\n\t}\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/JavaGenerator.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.jute.compiler;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\n\n/**\n * Java Code generator front-end for Hadoop record I/O.\n */\nclass JavaGenerator {\n    private ArrayList<JRecord> mRecList;\n    private final File outputDirectory;\n    \n    /** Creates a new instance of JavaGenerator\n     *\n     * @param name possibly full pathname to the file\n     * @param incl included files (as JFile)\n     * @param records List of records defined within this file\n     * @param outputDirectory \n     */\n    JavaGenerator(String name, ArrayList<JFile> incl,\n            ArrayList<JRecord> records, File outputDirectory)\n    {\n        mRecList = records;\n        this.outputDirectory = outputDirectory;\n    }\n    \n    /**\n     * Generate Java code for records. This method is only a front-end to\n     * JRecord, since one file is generated for each record.\n     */\n    void genCode() throws IOException {\n        for (Iterator<JRecord> i = mRecList.iterator(); i.hasNext(); ) {\n            JRecord rec = i.next();\n            rec.genJavaCode(outputDirectory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/jute/compiler/package.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<html>\n  <head>\n    <title>Hadoop Record Compiler</title>\n  </head>\n  <body>\n  This package contains classes needed for code generation\n  from the hadoop record compiler. CppGenerator and JavaGenerator\n  are the main entry points from the parser. There are classes\n  corrsponding to every primitive type and compound type\n  included in Hadoop record I/O syntax.\n  </body>\n</html>\n"
  },
  {
    "path": "src/java/main/org/apache/jute/package.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<html>\n  <head>\n    <title>Hadoop Record I/O</title>\n  </head>\n  <body>\n  Hadoop record I/O contains classes and a record description language\n  translator for simplifying serialization and deserialization of records in a\n  language-neutral manner.\n  \n  <h2>Introduction</h2>\n  \n  Software systems of any significant complexity require mechanisms for data \ninterchange with the outside world. These interchanges typically involve the\nmarshaling and unmarshaling of logical units of data to and from data streams\n(files, network connections, memory buffers etc.). Applications usually have\nsome code for serializing and deserializing the data types that they manipulate\nembedded in them. The work of serialization has several features that make\nautomatic code generation for it worthwhile. Given a particular output encoding\n(binary, XML, etc.), serialization of primitive types and simple compositions\nof primitives (structs, vectors etc.) is a very mechanical task. Manually\nwritten serialization code can be susceptible to bugs especially when records\nhave a large number of fields or a record definition changes between software\nversions. Lastly, it can be very useful for applications written in different\nprogramming languages to be able to share and interchange data. This can be \nmade a lot easier by describing the data records manipulated by these\napplications in a language agnostic manner and using the descriptions to derive\nimplementations of serialization in multiple target languages. \n\nThis document describes Hadoop Record I/O, a mechanism that is aimed \nat\n<ul> \n<li> enabling the specification of simple serializable data types (records) \n<li> enabling the generation of code in multiple target languages for\nmarshaling and unmarshaling such types\n<li> providing target language specific support that will enable application \nprogrammers to incorporate generated code into their applications\n</ul>\n\nThe goals of Hadoop Record I/O are similar to those of mechanisms such as XDR,\nASN.1, PADS and ICE. While these systems all include a DDL that enables\nthe specification of most record types, they differ widely in what else they\nfocus on. The focus in Hadoop Record I/O is on data marshaling and\nmulti-lingual support.  We take a translator-based approach to serialization.\nHadoop users have to describe their data in a simple data description\nlanguage. The Hadoop DDL translator rcc generates code that users\ncan invoke in order to read/write their data from/to simple stream \nabstractions. Next we list explicitly some of the goals and non-goals of\nHadoop Record I/O.\n\n\n<h3>Goals</h3>\n\n<ul>\n<li> Support for commonly used primitive types. Hadoop should include as\nprimitives commonly used builtin types from programming languages we intend to\nsupport.\n\n<li> Support for common data compositions (including recursive compositions).\nHadoop should support widely used composite types such as structs and\nvectors.\n\n<li> Code generation in multiple target languages. Hadoop should be capable of\ngenerating serialization code in multiple target languages and should be\neasily extensible to new target languages. The initial target languages are\nC++ and Java.\n\n<li> Support for generated target languages. Hadooop should include support\nin the form of headers, libraries, packages for supported target languages \nthat enable easy inclusion and use of generated code in applications.\n\n<li> Support for multiple output encodings. Candidates include\npacked binary, comma-separated text, XML etc.\n\n<li> Support for specifying record types in a backwards/forwards compatible\nmanner. This will probably be in the form of support for optional fields in\nrecords. This version of the document does not include a description of the\nplanned mechanism, we intend to include it in the next iteration.\n\n</ul>\n\n<h3>Non-Goals</h3>\n\n<ul>\n  <li> Serializing existing arbitrary C++ classes.\n  <li> Serializing complex data structures such as trees, linked lists etc.\n  <li> Built-in indexing schemes, compression, or check-sums.\n  <li> Dynamic construction of objects from an XML schema.\n</ul>\n\nThe remainder of this document describes the features of Hadoop record I/O\nin more detail. Section 2 describes the data types supported by the system.\nSection 3 lays out the DDL syntax with some examples of simple records. \nSection 4 describes the process of code generation with rcc. Section 5\ndescribes target language mappings and support for Hadoop types. We include a\nfairly complete description of C++ mappings with intent to include Java and\nothers in upcoming iterations of this document. The last section talks about\nsupported output encodings.\n\n\n<h2>Data Types and Streams</h2>\n\nThis section describes the primitive and composite types supported by Hadoop.\nWe aim to support a set of types that can be used to simply and efficiently\nexpress a wide range of record types in different programming languages.\n\n<h3>Primitive Types</h3>\n\nFor the most part, the primitive types of Hadoop map directly to primitive\ntypes in high level programming languages. Special cases are the\nustring (a Unicode string) and buffer types, which we believe\nfind wide use and which are usually implemented in library code and not\navailable as language built-ins. Hadoop also supplies these via library code\nwhen a target language built-in is not present and there is no widely\nadopted \"standard\" implementation. The complete list of primitive types is:\n\n<ul>\n  <li> byte: An 8-bit unsigned integer.\n  <li> boolean: A boolean value.\n  <li> int: A 32-bit signed integer.\n  <li> long: A 64-bit signed integer.\n  <li> float: A single precision floating point number as described by\n    IEEE-754.\n  <li> double: A double precision floating point number as described by\n    IEEE-754.\n  <li> ustring: A string consisting of Unicode characters.\n  <li> buffer: An arbitrary sequence of bytes. \n</ul>\n\n\n<h3>Composite Types</h3>\nHadoop supports a small set of composite types that enable the description\nof simple aggregate types and containers. A composite type is serialized\nby sequentially serializing it constituent elements. The supported\ncomposite types are:\n\n<ul>\n\n  <li> record: An aggregate type like a C-struct. This is a list of\ntyped fields that are together considered a single unit of data. A record\nis serialized by sequentially serializing its constituent fields. In addition\nto serialization a record has comparison operations (equality and less-than)\nimplemented for it, these are defined as memberwise comparisons.\n\n  <li>vector: A sequence of entries of the same data type, primitive\nor composite.\n\n  <li> map: An associative container mapping instances of a key type to\ninstances of a value type. The key and value types may themselves be primitive\nor composite types. \n\n</ul>\n\n<h3>Streams</h3>\n\nHadoop generates code for serializing and deserializing record types to\nabstract streams. For each target language Hadoop defines very simple input\nand output stream interfaces. Application writers can usually develop\nconcrete implementations of these by putting a one method wrapper around\nan existing stream implementation.\n\n\n<h2>DDL Syntax and Examples</h2>\n\nWe now describe the syntax of the Hadoop data description language. This is\nfollowed by a few examples of DDL usage.\n \n<h3>Hadoop DDL Syntax</h3>\n\n<pre><code>\nrecfile = *include module *record\ninclude = \"include\" path\npath = (relative-path / absolute-path)\nmodule = \"module\" module-name\nmodule-name = name *(\".\" name)\nrecord := \"class\" name \"{\" 1*(field) \"}\"\nfield := type name \";\"\nname :=  ALPHA (ALPHA / DIGIT / \"_\" )*\ntype := (ptype / ctype)\nptype := (\"byte\" / \"boolean\" / \"int\" |\n          \"long\" / \"float\" / \"double\"\n          \"ustring\" / \"buffer\")\nctype := ((\"vector\" \"<\" type \">\") /\n          (\"map\" \"<\" type \",\" type \">\" ) ) / name)\n</code></pre>\n\nA DDL file describes one or more record types. It begins with zero or\nmore include declarations, a single mandatory module declaration\nfollowed by zero or more class declarations. The semantics of each of\nthese declarations are described below:\n\n<ul>\n\n<li>include: An include declaration specifies a DDL file to be\nreferenced when generating code for types in the current DDL file. Record types\nin the current compilation unit may refer to types in all included files.\nFile inclusion is recursive. An include does not trigger code\ngeneration for the referenced file.\n\n<li> module: Every Hadoop DDL file must have a single module\ndeclaration that follows the list of includes and precedes all record\ndeclarations. A module declaration identifies a scope within which\nthe names of all types in the current file are visible. Module names are\nmapped to C++ namespaces, Java packages etc. in generated code.\n\n<li> class: Records types are specified through class\ndeclarations. A class declaration is like a Java class declaration.\nIt specifies a named record type and a list of fields that constitute records\nof the type. Usage is illustrated in the following examples.\n\n</ul>\n\n<h3>Examples</h3>\n\n<ul>\n<li>A simple DDL file links.jr with just one record declaration. \n<pre><code>\nmodule links {\n    class Link {\n        ustring URL;\n        boolean isRelative;\n        ustring anchorText;\n    };\n}\n</code></pre>\n\n<li> A DDL file outlinks.jr which includes another\n<pre><code>\ninclude \"links.jr\"\n\nmodule outlinks {\n    class OutLinks {\n        ustring baseURL;\n        vector<links.Link> outLinks;\n    };\n}\n</code></pre>\n</ul>\n\n<h2>Code Generation</h2>\n\nThe Hadoop translator is written in Java. Invocation is done by executing a \nwrapper shell script named named rcc. It takes a list of\nrecord description files as a mandatory argument and an\noptional language argument (the default is Java) --language or\n-l. Thus a typical invocation would look like:\n<pre><code>\n$ rcc -l C++ <filename> ...\n</code></pre>\n\n\n<h2>Target Language Mappings and Support</h2>\n\nFor all target languages, the unit of code generation is a record type. \nFor each record type, Hadoop generates code for serialization and\ndeserialization, record comparison and access to record members.\n\n<h3>C++</h3>\n\nSupport for including Hadoop generated C++ code in applications comes in the\nform of a header file recordio.hh which needs to be included in source\nthat uses Hadoop types and a library librecordio.a which applications need\nto be linked with. The header declares the Hadoop C++ namespace which defines\nappropriate types for the various primitives, the basic interfaces for\nrecords and streams and enumerates the supported serialization encodings.\nDeclarations of these interfaces and a description of their semantics follow:\n\n<pre><code>\nnamespace hadoop {\n\n  enum RecFormat { kBinary, kXML, kCSV };\n\n  class InStream {\n  public:\n    virtual ssize_t read(void *buf, size_t n) = 0;\n  };\n\n  class OutStream {\n  public:\n    virtual ssize_t write(const void *buf, size_t n) = 0;\n  };\n\n  class IOError : public runtime_error {\n  public:\n    explicit IOError(const std::string& msg);\n  };\n\n  class IArchive;\n  class OArchive;\n\n  class RecordReader {\n  public:\n    RecordReader(InStream& in, RecFormat fmt);\n    virtual ~RecordReader(void);\n\n    virtual void read(Record& rec);\n  };\n\n  class RecordWriter {\n  public:\n    RecordWriter(OutStream& out, RecFormat fmt);\n    virtual ~RecordWriter(void);\n\n    virtual void write(Record& rec);\n  };\n\n\n  class Record {\n  public:\n    virtual std::string type(void) const = 0;\n    virtual std::string signature(void) const = 0;\n  protected:\n    virtual bool validate(void) const = 0;\n\n    virtual void\n    serialize(OArchive& oa, const std::string& tag) const = 0;\n\n    virtual void\n    deserialize(IArchive& ia, const std::string& tag) = 0;\n  };\n}\n</code></pre>\n\n<ul>\n\n<li> RecFormat: An enumeration of the serialization encodings supported\nby this implementation of Hadoop.\n\n<li> InStream: A simple abstraction for an input stream. This has a \nsingle public read method that reads n bytes from the stream into\nthe buffer buf. Has the same semantics as a blocking read system\ncall. Returns the number of bytes read or -1 if an error occurs.\n\n<li> OutStream: A simple abstraction for an output stream. This has a \nsingle write method that writes n bytes to the stream from the\nbuffer buf. Has the same semantics as a blocking write system\ncall. Returns the number of bytes written or -1 if an error occurs.\n\n<li> RecordReader: A RecordReader reads records one at a time from\nan underlying stream in a specified record format. The reader is instantiated\nwith a stream and a serialization format. It has a read method that\ntakes an instance of a record and deserializes the record from the stream.\n\n<li> RecordWriter: A RecordWriter writes records one at a\ntime to an underlying stream in a specified record format. The writer is\ninstantiated with a stream and a serialization format. It has a\nwrite method that takes an instance of a record and serializes the\nrecord to the stream.\n\n<li> Record: The base class for all generated record types. This has two\npublic methods type and signature that return the typename and the\ntype signature of the record.\n\n</ul>\n\nTwo files are generated for each record file (note: not for each record). If a\nrecord file is named \"name.jr\", the generated files are \n\"name.jr.cc\" and \"name.jr.hh\" containing serialization \nimplementations and record type declarations respectively.\n\nFor each record in the DDL file, the generated header file will contain a\nclass definition corresponding to the record type, method definitions for the\ngenerated type will be present in the '.cc' file.  The generated class will\ninherit from the abstract class hadoop::Record. The DDL files\nmodule declaration determines the namespace the record belongs to.\nEach '.' delimited token in the module declaration results in the\ncreation of a namespace. For instance, the declaration module docs.links\nresults in the creation of a docs namespace and a nested \ndocs::links namespace. In the preceding examples, the Link class\nis placed in the links namespace. The header file corresponding to\nthe links.jr file will contain:\n\n<pre><code>\nnamespace links {\n  class Link : public hadoop::Record {\n    // ....\n  };\n};\n</code></pre>\n\nEach field within the record will cause the generation of a private member\ndeclaration of the appropriate type in the class declaration, and one or more\nacccessor methods. The generated class will implement the serialize and\ndeserialize methods defined in hadoop::Record+. It will also \nimplement the inspection methods type and signature from\nhadoop::Record. A default constructor and virtual destructor will also\nbe generated. Serialization code will read/write records into streams that\nimplement the hadoop::InStream and the hadoop::OutStream interfaces.\n\nFor each member of a record an accessor method is generated that returns \neither the member or a reference to the member. For members that are returned \nby value, a setter method is also generated. This is true for primitive \ndata members of the types byte, int, long, boolean, float and \ndouble. For example, for a int field called MyField the folowing\ncode is generated.\n\n<pre><code>\n...\nprivate:\n  int32_t mMyField;\n  ...\npublic:\n  int32_t getMyField(void) const {\n    return mMyField;\n  };\n\n  void setMyField(int32_t m) {\n    mMyField = m;\n  };\n  ...\n</code></pre>\n\nFor a ustring or buffer or composite field. The generated code\nonly contains accessors that return a reference to the field. A const\nand a non-const accessor are generated. For example:\n\n<pre><code>\n...\nprivate:\n  std::string mMyBuf;\n  ...\npublic:\n\n  std::string& getMyBuf() {\n    return mMyBuf;\n  };\n\n  const std::string& getMyBuf() const {\n    return mMyBuf;\n  };\n  ...\n</code></pre>\n\n<h4>Examples</h4>\n\nSuppose the inclrec.jr file contains:\n<pre><code>\nmodule inclrec {\n    class RI {\n        int      I32;\n        double   D;\n        ustring  S;\n    };\n}\n</code></pre>\n\nand the testrec.jr file contains:\n\n<pre><code>\ninclude \"inclrec.jr\"\nmodule testrec {\n    class R {\n        vector<float> VF;\n        RI            Rec;\n        buffer        Buf;\n    };\n}\n</code></pre>\n\nThen the invocation of rcc such as:\n<pre><code>\n$ rcc -l c++ inclrec.jr testrec.jr\n</code></pre>\nwill result in generation of four files:\ninclrec.jr.{cc,hh} and testrec.jr.{cc,hh}.\n\nThe inclrec.jr.hh will contain:\n\n<pre><code>\n#ifndef _INCLREC_JR_HH_\n#define _INCLREC_JR_HH_\n\n#include \"recordio.hh\"\n\nnamespace inclrec {\n  \n  class RI : public hadoop::Record {\n\n  private:\n\n    int32_t      mI32;\n    double       mD;\n    std::string  mS;\n\n  public:\n\n    RI(void);\n    virtual ~RI(void);\n\n    virtual bool operator==(const RI& peer) const;\n    virtual bool operator<(const RI& peer) const;\n\n    virtual int32_t getI32(void) const { return mI32; }\n    virtual void setI32(int32_t v) { mI32 = v; }\n\n    virtual double getD(void) const { return mD; }\n    virtual void setD(double v) { mD = v; }\n\n    virtual std::string& getS(void) const { return mS; }\n    virtual const std::string& getS(void) const { return mS; }\n\n    virtual std::string type(void) const;\n    virtual std::string signature(void) const;\n\n  protected:\n\n    virtual void serialize(hadoop::OArchive& a) const;\n    virtual void deserialize(hadoop::IArchive& a);\n\n    virtual bool validate(void);\n  };\n} // end namespace inclrec\n\n#endif /* _INCLREC_JR_HH_ */\n\n</code></pre>\n\nThe testrec.jr.hh file will contain:\n\n\n<pre><code>\n\n#ifndef _TESTREC_JR_HH_\n#define _TESTREC_JR_HH_\n\n#include \"inclrec.jr.hh\"\n\nnamespace testrec {\n  class R : public hadoop::Record {\n\n  private:\n\n    std::vector<float> mVF;\n    inclrec::RI        mRec;\n    std::string        mBuf;\n\n  public:\n\n    R(void);\n    virtual ~R(void);\n\n    virtual bool operator==(const R& peer) const;\n    virtual bool operator<(const R& peer) const;\n\n    virtual std::vector<float>& getVF(void) const;\n    virtual const std::vector<float>& getVF(void) const;\n\n    virtual std::string& getBuf(void) const ;\n    virtual const std::string& getBuf(void) const;\n\n    virtual inclrec::RI& getRec(void) const;\n    virtual const inclrec::RI& getRec(void) const;\n    \n    virtual bool serialize(hadoop::OutArchive& a) const;\n    virtual bool deserialize(hadoop::InArchive& a);\n    \n    virtual std::string type(void) const;\n    virtual std::string signature(void) const;\n  };\n}; // end namespace testrec\n#endif /* _TESTREC_JR_HH_ */\n\n</code></pre>\n\n<h3>Java</h3>\n\nCode generation for Java is similar to that for C++. A Java class is generated\nfor each record type with private members corresponding to the fields. Getters\nand setters for fields are also generated. Some differences arise in the\nway comparison is expressed and in the mapping of modules to packages and\nclasses to files. For equality testing, an equals method is generated\nfor each record type. As per Java requirements a hashCode method is also\ngenerated. For comparison a compareTo method is generated for each\nrecord type. This has the semantics as defined by the Java Comparable\ninterface, that is, the method returns a negative integer, zero, or a positive\ninteger as the invoked object is less than, equal to, or greater than the\ncomparison parameter.\n\nA .java file is generated per record type as opposed to per DDL\nfile as in C++. The module declaration translates to a Java\npackage declaration. The module name maps to an identical Java package\nname. In addition to this mapping, the DDL compiler creates the appropriate\ndirectory hierarchy for the package and places the generated .java\nfiles in the correct directories.\n\n<h2>Mapping Summary</h2>\n\n<pre><code>\nDDL Type        C++ Type            Java Type \n\nboolean         bool                boolean\nbyte            int8_t              byte\nint             int32_t             int\nlong            int64_t             long\nfloat           float               float\ndouble          double              double\nustring         std::string         Text\nbuffer          std::string         java.io.ByteArrayOutputStream\nclass type      class type          class type\nvector<type>    std::vector<type>   java.util.ArrayList\nmap<type,type>  std::map<type,type> java.util.TreeMap\n</code></pre>\n\n<h2>Data encodings</h2>\n\nThis section describes the format of the data encodings supported by Hadoop.\nCurrently, three data encodings are supported, namely binary, CSV and XML.\n\n<h3>Binary Serialization Format</h3>\n\nThe binary data encoding format is fairly dense. Serialization of composite\ntypes is simply defined as a concatenation of serializations of the constituent\nelements (lengths are included in vectors and maps).\n\nComposite types are serialized as follows:\n<ul>\n<li> class: Sequence of serialized members.\n<li> vector: The number of elements serialized as an int. Followed by a\nsequence of serialized elements.\n<li> map: The number of key value pairs serialized as an int. Followed\nby a sequence of serialized (key,value) pairs.\n</ul>\n\nSerialization of primitives is more interesting, with a zero compression\noptimization for integral types and normalization to UTF-8 for strings. \nPrimitive types are serialized as follows:\n\n<ul>\n<li> byte: Represented by 1 byte, as is.\n<li> boolean: Represented by 1-byte (0 or 1)\n<li> int/long: Integers and longs are serialized zero compressed.\nRepresented as 1-byte if -120 <= value < 128. Otherwise, serialized as a\nsequence of 2-5 bytes for ints, 2-9 bytes for longs. The first byte represents\nthe number of trailing bytes, N, as the negative number (-120-N). For example,\nthe number 1024 (0x400) is represented by the byte sequence 'x86 x04 x00'.\nThis doesn't help much for 4-byte integers but does a reasonably good job with\nlongs without bit twiddling.\n<li> float/double: Serialized in IEEE 754 single and double precision\nformat in network byte order. This is the format used by Java.\n<li> ustring: Serialized as 4-byte zero compressed length followed by\ndata encoded as UTF-8. Strings are normalized to UTF-8 regardless of native\nlanguage representation.\n<li> buffer: Serialized as a 4-byte zero compressed length followed by the\nraw bytes in the buffer.\n</ul>\n\n\n<h3>CSV Serialization Format</h3>\n\nThe CSV serialization format has a lot more structure than the \"standard\"\nExcel CSV format, but we believe the additional structure is useful because\n\n<ul>\n<li> it makes parsing a lot easier without detracting too much from legibility\n<li> the delimiters around composites make it obvious when one is reading a\nsequence of Hadoop records\n</ul>\n\nSerialization formats for the various types are detailed in the grammar that\nfollows. The notable feature of the formats is the use of delimiters for \nindicating the certain field types.\n\n<ul>\n<li> A string field begins with a single quote (').\n<li> A buffer field begins with a sharp (#).\n<li> A class, vector or map begins with 's{', 'v{' or 'm{' respectively and\nends with '}'.\n</ul>\n\nThe CSV format can be described by the following grammar:\n\n<pre><code>\nrecord = primitive / struct / vector / map\nprimitive = boolean / int / long / float / double / ustring / buffer\n\nboolean = \"T\" / \"F\"\nint = [\"-\"] 1*DIGIT\nlong = \";\" [\"-\"] 1*DIGIT\nfloat = [\"-\"] 1*DIGIT \".\" 1*DIGIT [\"E\" / \"e\" [\"-\"] 1*DIGIT]\ndouble = \";\" [\"-\"] 1*DIGIT \".\" 1*DIGIT [\"E\" / \"e\" [\"-\"] 1*DIGIT]\n\nustring = \"'\" *(UTF8 char except NULL, LF, % and , / \"%00\" / \"%0a\" / \"%25\" / \"%2c\" )\n\nbuffer = \"#\" *(BYTE except NULL, LF, % and , / \"%00\" / \"%0a\" / \"%25\" / \"%2c\" )\n\nstruct = \"s{\" record *(\",\" record) \"}\"\nvector = \"v{\" [record *(\",\" record)] \"}\"\nmap = \"m{\" [*(record \",\" record)] \"}\"\n</code></pre>\n\n<h3>XML Serialization Format</h3>\n\nThe XML serialization format is the same used by Apache XML-RPC\n(http://ws.apache.org/xmlrpc/types.html). This is an extension of the original\nXML-RPC format and adds some additional data types. All record I/O types are\nnot directly expressible in this format, and access to a DDL is required in\norder to convert these to valid types. All types primitive or composite are\nrepresented by &lt;value&gt; elements. The particular XML-RPC type is\nindicated by a nested element in the &lt;value&gt; element. The encoding for\nrecords is always UTF-8. Primitive types are serialized as follows:\n\n<ul>\n<li> byte: XML tag &lt;ex:i1&gt;. Values: 1-byte unsigned \nintegers represented in US-ASCII\n<li> boolean: XML tag &lt;boolean&gt;. Values: \"0\" or \"1\"\n<li> int: XML tags &lt;i4&gt; or &lt;int&gt;. Values: 4-byte\nsigned integers represented in US-ASCII.\n<li> long: XML tag &lt;ex:i8&gt;. Values: 8-byte signed integers\nrepresented in US-ASCII.\n<li> float: XML tag &lt;ex:float&gt;. Values: Single precision\nfloating point numbers represented in US-ASCII.\n<li> double: XML tag &lt;double&gt;. Values: Double precision\nfloating point numbers represented in US-ASCII.\n<li> ustring: XML tag &lt;;string&gt;. Values: String values\nrepresented as UTF-8. XML does not permit all Unicode characters in literal\ndata. In particular, NULLs and control chars are not allowed. Additionally,\nXML processors are required to replace carriage returns with line feeds and to\nreplace CRLF sequences with line feeds. Programming languages that we work\nwith do not impose these restrictions on string types. To work around these\nrestrictions, disallowed characters and CRs are percent escaped in strings.\nThe '%' character is also percent escaped.\n<li> buffer: XML tag &lt;string&&gt;. Values: Arbitrary binary\ndata. Represented as hexBinary, each byte is replaced by its 2-byte\nhexadecimal representation.\n</ul>\n\nComposite types are serialized as follows:\n\n<ul>\n<li> class: XML tag &lt;struct&gt;. A struct is a sequence of\n&lt;member&gt; elements. Each &lt;member&gt; element has a &lt;name&gt;\nelement and a &lt;value&gt; element. The &lt;name&gt; is a string that must\nmatch /[a-zA-Z][a-zA-Z0-9_]*/. The value of the member is represented\nby a &lt;value&gt; element.\n\n<li> vector: XML tag &lt;array&lt;. An &lt;array&gt; contains a\nsingle &lt;data&gt; element. The &lt;data&gt; element is a sequence of\n&lt;value&gt; elements each of which represents an element of the vector.\n\n<li> map: XML tag &lt;array&gt;. Same as vector.\n\n</ul>\n\nFor example:\n\n<pre><code>\nclass {\n  int           MY_INT;            // value 5\n  vector<float> MY_VEC;            // values 0.1, -0.89, 2.45e4\n  buffer        MY_BUF;            // value '\\00\\n\\tabc%'\n}\n</code></pre>\n\nis serialized as\n\n<pre><code class=\"XML\">\n&lt;value&gt;\n  &lt;struct&gt;\n    &lt;member&gt;\n      &lt;name&gt;MY_INT&lt;/name&gt;\n      &lt;value&gt;&lt;i4&gt;5&lt;/i4&gt;&lt;/value&gt;\n    &lt;/member&gt;\n    &lt;member&gt;\n      &lt;name&gt;MY_VEC&lt;/name&gt;\n      &lt;value&gt;\n        &lt;array&gt;\n          &lt;data&gt;\n            &lt;value&gt;&lt;ex:float&gt;0.1&lt;/ex:float&gt;&lt;/value&gt;\n            &lt;value&gt;&lt;ex:float&gt;-0.89&lt;/ex:float&gt;&lt;/value&gt;\n            &lt;value&gt;&lt;ex:float&gt;2.45e4&lt;/ex:float&gt;&lt;/value&gt;\n          &lt;/data&gt;\n        &lt;/array&gt;\n      &lt;/value&gt;\n    &lt;/member&gt;\n    &lt;member&gt;\n      &lt;name&gt;MY_BUF&lt;/name&gt;\n      &lt;value&gt;&lt;string&gt;%00\\n\\tabc%25&lt;/string&gt;&lt;/value&gt;\n    &lt;/member&gt;\n  &lt;/struct&gt;\n&lt;/value&gt; \n</code></pre>\n\n  </body>\n</html>\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/AsyncCallback.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport java.util.List;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * Interface definitions of asynchronous callbacks.\n * An asynchronous callback is deferred to invoke after a function returns.\n * Asynchronous calls usually improve system efficiency on IO-related APIs.\n * <p/>\n * ZooKeeper provides asynchronous version as equivalent to synchronous APIs.\n */\n@InterfaceAudience.Public\npublic interface AsyncCallback {\n\n    /**\n     * This callback is used to retrieve the stat of the node.\n     */\n    @InterfaceAudience.Public\n    interface StatCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#BADVERSION}\n         * - The given version doesn't match the node's version\n         * for some API calls.\n         * </li>\n         * </ul>\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         * @param stat {@link org.apache.zookeeper.data.Stat} object of\n         *             the node on given path.\n         */\n        public void processResult(int rc, String path, Object ctx, Stat stat);\n    }\n\n    /**\n     * This callback is used to retrieve the data and stat of the node.\n     */\n    @InterfaceAudience.Public\n    interface DataCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * </ul>\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         * @param data The {@link org.apache.zookeeper.server.DataNode#data}\n         *             of the node.\n         * @param stat {@link org.apache.zookeeper.data.Stat} object of\n         *             the node on given path.\n         */\n        public void processResult(int rc, String path, Object ctx, byte data[],\n                Stat stat);\n    }\n\n    /**\n     * This callback is used to retrieve the ACL and stat of the node.\n     */\n    @InterfaceAudience.Public\n    interface ACLCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * </ul>\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         * @param acl  ACL Id in\n         *             {@link org.apache.zookeeper.ZooDefs.Ids}.\n         * @param stat {@link org.apache.zookeeper.data.Stat} object of\n         *             the node on given path.\n         */\n        public void processResult(int rc, String path, Object ctx,\n                List<ACL> acl, Stat stat);\n    }\n\n    /**\n     * This callback is used to retrieve the children of the node.\n     */\n    @InterfaceAudience.Public\n    interface ChildrenCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * </ul>\n         *\n         * @param rc       The return code or the result of the call.\n         * @param path     The path that we passed to asynchronous calls.\n         * @param ctx      Whatever context object that we passed to\n         *                 asynchronous calls.\n         * @param children An unordered array of children of the node on\n         *                 given path.\n         */\n        public void processResult(int rc, String path, Object ctx,\n                List<String> children);\n    }\n\n    /**\n     * This callback is used to retrieve the children and stat of the node.\n     */\n    @InterfaceAudience.Public\n    interface Children2Callback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * See {@link org.apache.zookeeper.AsyncCallback.ChildrenCallback}.\n         *\n         * @param rc       The return code or the result of the call.\n         * @param path     The path that we passed to asynchronous calls.\n         * @param ctx      Whatever context object that we passed to\n         *                 asynchronous calls.\n         * @param children An unordered array of children of the node on\n         *                 given path.\n         * @param stat     {@link org.apache.zookeeper.data.Stat} object of\n         *                 the node on given path.\n         */\n        public void processResult(int rc, String path, Object ctx,\n                List<String> children, Stat stat);\n    }\n\n    /**\n     * This callback is used to retrieve the name of the node.\n     */\n    @InterfaceAudience.Public\n    interface StringCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NODEEXISTS}\n         * - The node on give path already exists for some API calls.\n         * </li>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * <li>\n         * {@link\n         * org.apache.zookeeper.KeeperException.Code#NOCHILDRENFOREPHEMERALS}\n         * - an ephemeral node cannot have children. There is discussion in\n         * community. It might be changed in the future.\n         * </li>\n         * </ul>\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         * @param name The name of the Znode that was created.\n         *             On success, <i>name</i> and <i>path</i> are usually\n         *             equal, unless a sequential node has been created.\n         */\n        public void processResult(int rc, String path, Object ctx, String name);\n    }\n\n    /**\n     * This callback doesn't retrieve anything from the node. It is useful\n     * for some APIs that doesn't want anything sent back, e.g. {@link\n     * org.apache.zookeeper.ZooKeeper#sync(String,\n     * org.apache.zookeeper.AsyncCallback.VoidCallback, Object)}.\n     */\n    @InterfaceAudience.Public\n    interface VoidCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * <p/>\n         * On failure, rc is set to the corresponding failure code in\n         * {@link org.apache.zookeeper.KeeperException}.\n         * <ul>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}\n         * - The node on given path doesn't exist for some API calls.\n         * </li>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#BADVERSION}\n         * - The given version doesn't match the node's version\n         * for some API calls.\n         * </li>\n         * <li>\n         * {@link org.apache.zookeeper.KeeperException.Code#NOTEMPTY}\n         * - the node has children and some API calls cannnot succeed,\n         * e.g. {@link\n         * org.apache.zookeeper.ZooKeeper#delete(String, int,\n         * org.apache.zookeeper.AsyncCallback.VoidCallback, Object)}.\n         * </li>\n         * </ul>\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         */\n        public void processResult(int rc, String path, Object ctx);\n    }\n\n    /**\n     * This callback is used to process the multiple results from\n     * a single multi call.\n     * See {@link org.apache.zookeeper.ZooKeeper#multi} for more information.\n     * @since 3.4.7\n     */\n    @InterfaceAudience.Public\n    interface MultiCallback extends AsyncCallback {\n        /**\n         * Process the result of the asynchronous call.\n         * <p/>\n         * On success, rc is\n         * {@link org.apache.zookeeper.KeeperException.Code#OK}.\n         * All opResults are\n         * non-{@link org.apache.zookeeper.OpResult.ErrorResult},\n         *\n         * <p/>\n         * On failure, rc is a failure code in\n         * {@link org.apache.zookeeper.KeeperException.Code}.\n         * All opResults are\n         * {@link org.apache.zookeeper.OpResult.ErrorResult}.\n         * All operations will be rollback-ed even if operations\n         * before the failing one were successful.\n         *\n         * @param rc   The return code or the result of the call.\n         * @param path The path that we passed to asynchronous calls.\n         * @param ctx  Whatever context object that we passed to\n         *             asynchronous calls.\n         * @param opResults The list of results.\n         *                  One result for each operation,\n         *                  and the order matches that of input.\n         */\n        public void processResult(int rc, String path, Object ctx,\n                List<OpResult> opResults);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ClientCnxn.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.net.ConnectException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.net.SocketException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport javax.security.auth.login.LoginException;\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.AsyncCallback.ACLCallback;\nimport org.apache.zookeeper.AsyncCallback.Children2Callback;\nimport org.apache.zookeeper.AsyncCallback.ChildrenCallback;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.MultiCallback;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.OpResult.ErrorResult;\nimport org.apache.zookeeper.Watcher.Event;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.ZooKeeper.WatchRegistration;\nimport org.apache.zookeeper.client.HostProvider;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.proto.AuthPacket;\nimport org.apache.zookeeper.proto.ConnectRequest;\nimport org.apache.zookeeper.proto.CreateResponse;\nimport org.apache.zookeeper.proto.ExistsResponse;\nimport org.apache.zookeeper.proto.GetACLResponse;\nimport org.apache.zookeeper.proto.GetChildren2Response;\nimport org.apache.zookeeper.proto.GetChildrenResponse;\nimport org.apache.zookeeper.proto.GetDataResponse;\nimport org.apache.zookeeper.proto.GetSASLRequest;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.proto.SetACLResponse;\nimport org.apache.zookeeper.proto.SetDataResponse;\nimport org.apache.zookeeper.proto.SetWatches;\nimport org.apache.zookeeper.proto.WatcherEvent;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class manages the socket i/o for the client. ClientCnxn maintains a list\n * of available servers to connect to and \"transparently\" switches servers it is\n * connected to as needed.\n *\n */\npublic class ClientCnxn {\n    private static final Logger LOG = LoggerFactory.getLogger(ClientCnxn.class);\n\n    private static final String ZK_SASL_CLIENT_USERNAME =\n        \"zookeeper.sasl.client.username\";\n\n    /* ZOOKEEPER-706: If a session has a large number of watches set then\n     * attempting to re-establish those watches after a connection loss may\n     * fail due to the SetWatches request exceeding the server's configured\n     * jute.maxBuffer value. To avoid this we instead split the watch\n     * re-establishement across multiple SetWatches calls. This constant\n     * controls the size of each call. It is set to 128kB to be conservative\n     * with respect to the server's 1MB default for jute.maxBuffer.\n     */\n    private static final int SET_WATCHES_MAX_LENGTH = 128 * 1024;\n\n    /** This controls whether automatic watch resetting is enabled.\n     * Clients automatically reset watches during session reconnect, this\n     * option allows the client to turn off this behavior by setting\n     * the environment variable \"zookeeper.disableAutoWatchReset\" to \"true\" */\n    private static boolean disableAutoWatchReset;\n    static {\n        // this var should not be public, but otw there is no easy way\n        // to test\n        disableAutoWatchReset =\n            Boolean.getBoolean(\"zookeeper.disableAutoWatchReset\");\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"zookeeper.disableAutoWatchReset is \"\n                    + disableAutoWatchReset);\n        }\n    }\n\n    static class AuthData {\n        AuthData(String scheme, byte data[]) {\n            this.scheme = scheme;\n            this.data = data;\n        }\n\n        String scheme;\n\n        byte data[];\n    }\n\n    private final CopyOnWriteArraySet<AuthData> authInfo = new CopyOnWriteArraySet<AuthData>();\n\n    /**\n     * These are the packets that have been sent and are waiting for a response.\n     */\n    private final LinkedList<Packet> pendingQueue = new LinkedList<Packet>();\n\n    /**\n     * These are the packets that need to be sent.\n     */\n    private final LinkedList<Packet> outgoingQueue = new LinkedList<Packet>();\n\n    private int connectTimeout;\n\n    /**\n     * The timeout in ms the client negotiated with the server. This is the\n     * \"real\" timeout, not the timeout request by the client (which may have\n     * been increased/decreased by the server which applies bounds to this\n     * value.\n     */\n    private volatile int negotiatedSessionTimeout;\n\n    private int readTimeout;\n\n    private final int sessionTimeout;\n\n    private final ZooKeeper zooKeeper;\n\n    private final ClientWatchManager watcher;\n\n    private long sessionId;\n\n    private byte sessionPasswd[] = new byte[16];\n\n    /**\n     * If true, the connection is allowed to go to r-o mode. This field's value\n     * is sent, besides other data, during session creation handshake. If the\n     * server on the other side of the wire is partitioned it'll accept\n     * read-only clients only.\n     */\n    private boolean readOnly;\n\n    final String chrootPath;\n\n    final SendThread sendThread;\n\n    final EventThread eventThread;\n\n    /**\n     * Set to true when close is called. Latches the connection such that we\n     * don't attempt to re-connect to the server if in the middle of closing the\n     * connection (client sends session disconnect to server as part of close\n     * operation)\n     */\n    private volatile boolean closing = false;\n    \n    /**\n     * A set of ZooKeeper hosts this client could connect to.\n     */\n    private final HostProvider hostProvider;\n\n    /**\n     * Is set to true when a connection to a r/w server is established for the\n     * first time; never changed afterwards.\n     * <p>\n     * Is used to handle situations when client without sessionId connects to a\n     * read-only server. Such client receives \"fake\" sessionId from read-only\n     * server, but this sessionId is invalid for other servers. So when such\n     * client finds a r/w server, it sends 0 instead of fake sessionId during\n     * connection handshake and establishes new, valid session.\n     * <p>\n     * If this field is false (which implies we haven't seen r/w server before)\n     * then non-zero sessionId is fake, otherwise it is valid.\n     */\n    volatile boolean seenRwServerBefore = false;\n\n\n    public ZooKeeperSaslClient zooKeeperSaslClient;\n\n    public long getSessionId() {\n        return sessionId;\n    }\n\n    public byte[] getSessionPasswd() {\n        return sessionPasswd;\n    }\n\n    public int getSessionTimeout() {\n        return negotiatedSessionTimeout;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        SocketAddress local = sendThread.getClientCnxnSocket().getLocalSocketAddress();\n        SocketAddress remote = sendThread.getClientCnxnSocket().getRemoteSocketAddress();\n        sb\n            .append(\"sessionid:0x\").append(Long.toHexString(getSessionId()))\n            .append(\" local:\").append(local)\n            .append(\" remoteserver:\").append(remote)\n            .append(\" lastZxid:\").append(lastZxid)\n            .append(\" xid:\").append(xid)\n            .append(\" sent:\").append(sendThread.getClientCnxnSocket().getSentCount())\n            .append(\" recv:\").append(sendThread.getClientCnxnSocket().getRecvCount())\n            .append(\" queuedpkts:\").append(outgoingQueue.size())\n            .append(\" pendingresp:\").append(pendingQueue.size())\n            .append(\" queuedevents:\").append(eventThread.waitingEvents.size());\n\n        return sb.toString();\n    }\n\n    /**\n     * This class allows us to pass the headers and the relevant records around.\n     */\n    static class Packet {\n        RequestHeader requestHeader;\n\n        ReplyHeader replyHeader;\n\n        Record request;\n\n        Record response;\n\n        ByteBuffer bb;\n\n        /** Client's view of the path (may differ due to chroot) **/\n        String clientPath;\n        /** Servers's view of the path (may differ due to chroot) **/\n        String serverPath;\n\n        boolean finished;\n\n        AsyncCallback cb;\n\n        Object ctx;\n\n        WatchRegistration watchRegistration;\n\n        public boolean readOnly;\n\n        /** Convenience ctor */\n        Packet(RequestHeader requestHeader, ReplyHeader replyHeader,\n               Record request, Record response,\n               WatchRegistration watchRegistration) {\n            this(requestHeader, replyHeader, request, response,\n                 watchRegistration, false);\n        }\n\n        Packet(RequestHeader requestHeader, ReplyHeader replyHeader,\n               Record request, Record response,\n               WatchRegistration watchRegistration, boolean readOnly) {\n\n            this.requestHeader = requestHeader;\n            this.replyHeader = replyHeader;\n            this.request = request;\n            this.response = response;\n            this.readOnly = readOnly;\n            this.watchRegistration = watchRegistration;\n        }\n\n        public void createBB() {\n            try {\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeInt(-1, \"len\"); // We'll fill this in later\n                if (requestHeader != null) {\n                    requestHeader.serialize(boa, \"header\");\n                }\n                if (request instanceof ConnectRequest) {\n                    request.serialize(boa, \"connect\");\n                    // append \"am-I-allowed-to-be-readonly\" flag\n                    boa.writeBool(readOnly, \"readOnly\");\n                } else if (request != null) {\n                    request.serialize(boa, \"request\");\n                }\n                baos.close();\n                this.bb = ByteBuffer.wrap(baos.toByteArray());\n                this.bb.putInt(this.bb.capacity() - 4);\n                this.bb.rewind();\n            } catch (IOException e) {\n                LOG.warn(\"Ignoring unexpected exception\", e);\n            }\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder sb = new StringBuilder();\n\n            sb.append(\"clientPath:\" + clientPath);\n            sb.append(\" serverPath:\" + serverPath);\n            sb.append(\" finished:\" + finished);\n\n            sb.append(\" header:: \" + requestHeader);\n            sb.append(\" replyHeader:: \" + replyHeader);\n            sb.append(\" request:: \" + request);\n            sb.append(\" response:: \" + response);\n\n            // jute toString is horrible, remove unnecessary newlines\n            return sb.toString().replaceAll(\"\\r*\\n+\", \" \");\n        }\n    }\n\n    /**\n     * Creates a connection object. The actual network connect doesn't get\n     * established until needed. The start() instance method must be called\n     * subsequent to construction.\n     *\n     * @param chrootPath - the chroot of this client. Should be removed from this Class in ZOOKEEPER-838\n     * @param hostProvider\n     *                the list of ZooKeeper servers to connect to\n     * @param sessionTimeout\n     *                the timeout for connections.\n     * @param zooKeeper\n     *                the zookeeper object that this connection is related to.\n     * @param watcher watcher for this connection\n     * @param clientCnxnSocket\n     *                the socket implementation used (e.g. NIO/Netty)\n     * @param canBeReadOnly\n     *                whether the connection is allowed to go to read-only\n     *                mode in case of partitioning\n     * @throws IOException\n     */\n    public ClientCnxn(String chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper,\n            ClientWatchManager watcher, ClientCnxnSocket clientCnxnSocket, boolean canBeReadOnly)\n            throws IOException {\n        this(chrootPath, hostProvider, sessionTimeout, zooKeeper, watcher,\n             clientCnxnSocket, 0, new byte[16], canBeReadOnly);\n    }\n\n    /**\n     * Creates a connection object. The actual network connect doesn't get\n     * established until needed. The start() instance method must be called\n     * subsequent to construction.\n     *\n     * @param chrootPath - the chroot of this client. Should be removed from this Class in ZOOKEEPER-838\n     * @param hostProvider\n     *                the list of ZooKeeper servers to connect to\n     * @param sessionTimeout\n     *                the timeout for connections.\n     * @param zooKeeper\n     *                the zookeeper object that this connection is related to.\n     * @param watcher watcher for this connection\n     * @param clientCnxnSocket\n     *                the socket implementation used (e.g. NIO/Netty)\n     * @param sessionId session id if re-establishing session\n     * @param sessionPasswd session passwd if re-establishing session\n     * @param canBeReadOnly\n     *                whether the connection is allowed to go to read-only\n     *                mode in case of partitioning\n     * @throws IOException\n     */\n    public ClientCnxn(String chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper,\n            ClientWatchManager watcher, ClientCnxnSocket clientCnxnSocket,\n            long sessionId, byte[] sessionPasswd, boolean canBeReadOnly) {\n        this.zooKeeper = zooKeeper;\n        this.watcher = watcher;\n        this.sessionId = sessionId;\n        this.sessionPasswd = sessionPasswd;\n        this.sessionTimeout = sessionTimeout;\n        this.hostProvider = hostProvider;\n        this.chrootPath = chrootPath;\n\n        connectTimeout = sessionTimeout / hostProvider.size();\n        readTimeout = sessionTimeout * 2 / 3;\n        readOnly = canBeReadOnly;\n\n        sendThread = new SendThread(clientCnxnSocket);\n        eventThread = new EventThread();\n\n    }\n\n    /**\n     * tests use this to check on reset of watches\n     * @return if the auto reset of watches are disabled\n     */\n    public static boolean getDisableAutoResetWatch() {\n        return disableAutoWatchReset;\n    }\n    /**\n     * tests use this to set the auto reset\n     * @param b the value to set disable watches to\n     */\n    public static void setDisableAutoResetWatch(boolean b) {\n        disableAutoWatchReset = b;\n    }\n    public void start() {\n        sendThread.start();\n        eventThread.start();\n    }\n\n    private Object eventOfDeath = new Object();\n\n    private static class WatcherSetEventPair {\n        private final Set<Watcher> watchers;\n        private final WatchedEvent event;\n\n        public WatcherSetEventPair(Set<Watcher> watchers, WatchedEvent event) {\n            this.watchers = watchers;\n            this.event = event;\n        }\n    }\n\n    /**\n     * Guard against creating \"-EventThread-EventThread-EventThread-...\" thread\n     * names when ZooKeeper object is being created from within a watcher.\n     * See ZOOKEEPER-795 for details.\n     */\n    private static String makeThreadName(String suffix) {\n        String name = Thread.currentThread().getName().\n            replaceAll(\"-EventThread\", \"\");\n        return name + suffix;\n    }\n\n    class EventThread extends ZooKeeperThread {\n        private final LinkedBlockingQueue<Object> waitingEvents =\n            new LinkedBlockingQueue<Object>();\n\n        /** This is really the queued session state until the event\n         * thread actually processes the event and hands it to the watcher.\n         * But for all intents and purposes this is the state.\n         */\n        private volatile KeeperState sessionState = KeeperState.Disconnected;\n\n       private volatile boolean wasKilled = false;\n       private volatile boolean isRunning = false;\n\n        EventThread() {\n            super(makeThreadName(\"-EventThread\"));\n            setDaemon(true);\n        }\n\n        public void queueEvent(WatchedEvent event) {\n            if (event.getType() == EventType.None\n                    && sessionState == event.getState()) {\n                return;\n            }\n            sessionState = event.getState();\n\n            // materialize the watchers based on the event\n            WatcherSetEventPair pair = new WatcherSetEventPair(\n                    watcher.materialize(event.getState(), event.getType(),\n                            event.getPath()),\n                            event);\n            // queue the pair (watch set & event) for later processing\n            waitingEvents.add(pair);\n        }\n\n       public void queuePacket(Packet packet) {\n          if (wasKilled) {\n             synchronized (waitingEvents) {\n                if (isRunning) waitingEvents.add(packet);\n                else processEvent(packet);\n             }\n          } else {\n             waitingEvents.add(packet);\n          }\n       }\n\n        public void queueEventOfDeath() {\n            waitingEvents.add(eventOfDeath);\n        }\n\n        @Override\n        public void run() {\n           try {\n              isRunning = true;\n              while (true) {\n                 Object event = waitingEvents.take();\n                 if (event == eventOfDeath) {\n                    wasKilled = true;\n                 } else {\n                    processEvent(event);\n                 }\n                 if (wasKilled)\n                    synchronized (waitingEvents) {\n                       if (waitingEvents.isEmpty()) {\n                          isRunning = false;\n                          break;\n                       }\n                    }\n              }\n           } catch (InterruptedException e) {\n              LOG.error(\"Event thread exiting due to interruption\", e);\n           }\n\n            LOG.info(\"EventThread shut down for session: 0x{}\",\n                     Long.toHexString(getSessionId()));\n        }\n\n       private void processEvent(Object event) {\n          try {\n              if (event instanceof WatcherSetEventPair) {\n                  // each watcher will process the event\n                  WatcherSetEventPair pair = (WatcherSetEventPair) event;\n                  for (Watcher watcher : pair.watchers) {\n                      try {\n                          watcher.process(pair.event);\n                      } catch (Throwable t) {\n                          LOG.error(\"Error while calling watcher \", t);\n                      }\n                  }\n              } else {\n                  Packet p = (Packet) event;\n                  int rc = 0;\n                  String clientPath = p.clientPath;\n                  if (p.replyHeader.getErr() != 0) {\n                      rc = p.replyHeader.getErr();\n                  }\n                  if (p.cb == null) {\n                      LOG.warn(\"Somehow a null cb got to EventThread!\");\n                  } else if (p.response instanceof ExistsResponse\n                          || p.response instanceof SetDataResponse\n                          || p.response instanceof SetACLResponse) {\n                      StatCallback cb = (StatCallback) p.cb;\n                      if (rc == 0) {\n                          if (p.response instanceof ExistsResponse) {\n                              cb.processResult(rc, clientPath, p.ctx,\n                                      ((ExistsResponse) p.response)\n                                              .getStat());\n                          } else if (p.response instanceof SetDataResponse) {\n                              cb.processResult(rc, clientPath, p.ctx,\n                                      ((SetDataResponse) p.response)\n                                              .getStat());\n                          } else if (p.response instanceof SetACLResponse) {\n                              cb.processResult(rc, clientPath, p.ctx,\n                                      ((SetACLResponse) p.response)\n                                              .getStat());\n                          }\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null);\n                      }\n                  } else if (p.response instanceof GetDataResponse) {\n                      DataCallback cb = (DataCallback) p.cb;\n                      GetDataResponse rsp = (GetDataResponse) p.response;\n                      if (rc == 0) {\n                          cb.processResult(rc, clientPath, p.ctx, rsp\n                                  .getData(), rsp.getStat());\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null,\n                                  null);\n                      }\n                  } else if (p.response instanceof GetACLResponse) {\n                      ACLCallback cb = (ACLCallback) p.cb;\n                      GetACLResponse rsp = (GetACLResponse) p.response;\n                      if (rc == 0) {\n                          cb.processResult(rc, clientPath, p.ctx, rsp\n                                  .getAcl(), rsp.getStat());\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null,\n                                  null);\n                      }\n                  } else if (p.response instanceof GetChildrenResponse) {\n                      ChildrenCallback cb = (ChildrenCallback) p.cb;\n                      GetChildrenResponse rsp = (GetChildrenResponse) p.response;\n                      if (rc == 0) {\n                          cb.processResult(rc, clientPath, p.ctx, rsp\n                                  .getChildren());\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null);\n                      }\n                  } else if (p.response instanceof GetChildren2Response) {\n                      Children2Callback cb = (Children2Callback) p.cb;\n                      GetChildren2Response rsp = (GetChildren2Response) p.response;\n                      if (rc == 0) {\n                          cb.processResult(rc, clientPath, p.ctx, rsp\n                                  .getChildren(), rsp.getStat());\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null, null);\n                      }\n                  } else if (p.response instanceof CreateResponse) {\n                      StringCallback cb = (StringCallback) p.cb;\n                      CreateResponse rsp = (CreateResponse) p.response;\n                      if (rc == 0) {\n                          cb.processResult(rc, clientPath, p.ctx,\n                                  (chrootPath == null\n                                          ? rsp.getPath()\n                                          : rsp.getPath()\n                                    .substring(chrootPath.length())));\n                      } else {\n                          cb.processResult(rc, clientPath, p.ctx, null);\n                      }\n                  } else if (p.response instanceof MultiResponse) {\n                          MultiCallback cb = (MultiCallback) p.cb;\n                          MultiResponse rsp = (MultiResponse) p.response;\n                          if (rc == 0) {\n                                  List<OpResult> results = rsp.getResultList();\n                                  int newRc = rc;\n                                  for (OpResult result : results) {\n                                          if (result instanceof ErrorResult\n                                              && KeeperException.Code.OK.intValue()\n                                                  != (newRc = ((ErrorResult) result).getErr())) {\n                                                  break;\n                                          }\n                                  }\n                                  cb.processResult(newRc, clientPath, p.ctx, results);\n                          } else {\n                                  cb.processResult(rc, clientPath, p.ctx, null);\n                          }\n                  }  else if (p.cb instanceof VoidCallback) {\n                      VoidCallback cb = (VoidCallback) p.cb;\n                      cb.processResult(rc, clientPath, p.ctx);\n                  }\n              }\n          } catch (Throwable t) {\n              LOG.error(\"Caught unexpected throwable\", t);\n          }\n       }\n    }\n\n    private void finishPacket(Packet p) {\n        if (p.watchRegistration != null) {\n            p.watchRegistration.register(p.replyHeader.getErr());\n        }\n\n        if (p.cb == null) {\n            synchronized (p) {\n                p.finished = true;\n                p.notifyAll();\n            }\n        } else {\n            p.finished = true;\n            eventThread.queuePacket(p);\n        }\n    }\n\n    private void conLossPacket(Packet p) {\n        if (p.replyHeader == null) {\n            return;\n        }\n        switch (state) {\n        case AUTH_FAILED:\n            p.replyHeader.setErr(KeeperException.Code.AUTHFAILED.intValue());\n            break;\n        case CLOSED:\n            p.replyHeader.setErr(KeeperException.Code.SESSIONEXPIRED.intValue());\n            break;\n        default:\n            p.replyHeader.setErr(KeeperException.Code.CONNECTIONLOSS.intValue());\n        }\n        finishPacket(p);\n    }\n\n    private volatile long lastZxid;\n\n    public long getLastZxid() {\n        return lastZxid;\n    }\n\n    static class EndOfStreamException extends IOException {\n        private static final long serialVersionUID = -5438877188796231422L;\n\n        public EndOfStreamException(String msg) {\n            super(msg);\n        }\n        \n        @Override\n        public String toString() {\n            return \"EndOfStreamException: \" + getMessage();\n        }\n    }\n\n    private static class SessionTimeoutException extends IOException {\n        private static final long serialVersionUID = 824482094072071178L;\n\n        public SessionTimeoutException(String msg) {\n            super(msg);\n        }\n    }\n    \n    private static class SessionExpiredException extends IOException {\n        private static final long serialVersionUID = -1388816932076193249L;\n\n        public SessionExpiredException(String msg) {\n            super(msg);\n        }\n    }\n\n    private static class RWServerFoundException extends IOException {\n        private static final long serialVersionUID = 90431199887158758L;\n\n        public RWServerFoundException(String msg) {\n            super(msg);\n        }\n    }\n    \n    public static final int packetLen = Integer.getInteger(\"jute.maxbuffer\",\n            4096 * 1024);\n\n    /**\n     * This class services the outgoing request queue and generates the heart\n     * beats. It also spawns the ReadThread.\n     */\n    class SendThread extends ZooKeeperThread {\n        private long lastPingSentNs;\n        private final ClientCnxnSocket clientCnxnSocket;\n        private Random r = new Random(System.nanoTime());        \n        private boolean isFirstConnect = true;\n\n        void readResponse(ByteBuffer incomingBuffer) throws IOException {\n            ByteBufferInputStream bbis = new ByteBufferInputStream(\n                    incomingBuffer);\n            BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);\n            ReplyHeader replyHdr = new ReplyHeader();\n\n            replyHdr.deserialize(bbia, \"header\");\n            if (replyHdr.getXid() == -2) {\n                // -2 is the xid for pings\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Got ping response for sessionid: 0x\"\n                            + Long.toHexString(sessionId)\n                            + \" after \"\n                            + ((System.nanoTime() - lastPingSentNs) / 1000000)\n                            + \"ms\");\n                }\n                return;\n            }\n            if (replyHdr.getXid() == -4) {\n                // -4 is the xid for AuthPacket               \n                if(replyHdr.getErr() == KeeperException.Code.AUTHFAILED.intValue()) {\n                    state = States.AUTH_FAILED;                    \n                    eventThread.queueEvent( new WatchedEvent(Watcher.Event.EventType.None, \n                            Watcher.Event.KeeperState.AuthFailed, null) );            \t\t            \t\t\n                }\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Got auth sessionid:0x\"\n                            + Long.toHexString(sessionId));\n                }\n                return;\n            }\n            if (replyHdr.getXid() == -1) {\n                // -1 means notification\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Got notification sessionid:0x\"\n                        + Long.toHexString(sessionId));\n                }\n                WatcherEvent event = new WatcherEvent();\n                event.deserialize(bbia, \"response\");\n\n                // convert from a server path to a client path\n                if (chrootPath != null) {\n                    String serverPath = event.getPath();\n                    if(serverPath.compareTo(chrootPath)==0)\n                        event.setPath(\"/\");\n                    else if (serverPath.length() > chrootPath.length())\n                        event.setPath(serverPath.substring(chrootPath.length()));\n                    else {\n                    \tLOG.warn(\"Got server path \" + event.getPath()\n                    \t\t\t+ \" which is too short for chroot path \"\n                    \t\t\t+ chrootPath);\n                    }\n                }\n\n                WatchedEvent we = new WatchedEvent(event);\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Got \" + we + \" for sessionid 0x\"\n                            + Long.toHexString(sessionId));\n                }\n\n                eventThread.queueEvent( we );\n                return;\n            }\n\n            // If SASL authentication is currently in progress, construct and\n            // send a response packet immediately, rather than queuing a\n            // response as with other packets.\n            if (clientTunneledAuthenticationInProgress()) {\n                GetSASLRequest request = new GetSASLRequest();\n                request.deserialize(bbia,\"token\");\n                zooKeeperSaslClient.respondToServer(request.getToken(),\n                  ClientCnxn.this);\n                return;\n            }\n\n            Packet packet;\n            synchronized (pendingQueue) {\n                if (pendingQueue.size() == 0) {\n                    throw new IOException(\"Nothing in the queue, but got \"\n                            + replyHdr.getXid());\n                }\n                packet = pendingQueue.remove();\n            }\n            /*\n             * Since requests are processed in order, we better get a response\n             * to the first request!\n             */\n            try {\n                if (packet.requestHeader.getXid() != replyHdr.getXid()) {\n                    packet.replyHeader.setErr(\n                            KeeperException.Code.CONNECTIONLOSS.intValue());\n                    throw new IOException(\"Xid out of order. Got Xid \"\n                            + replyHdr.getXid() + \" with err \" +\n                            + replyHdr.getErr() +\n                            \" expected Xid \"\n                            + packet.requestHeader.getXid()\n                            + \" for a packet with details: \"\n                            + packet );\n                }\n\n                packet.replyHeader.setXid(replyHdr.getXid());\n                packet.replyHeader.setErr(replyHdr.getErr());\n                packet.replyHeader.setZxid(replyHdr.getZxid());\n                if (replyHdr.getZxid() > 0) {\n                    lastZxid = replyHdr.getZxid();\n                }\n                if (packet.response != null && replyHdr.getErr() == 0) {\n                    packet.response.deserialize(bbia, \"response\");\n                }\n\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Reading reply sessionid:0x\"\n                            + Long.toHexString(sessionId) + \", packet:: \" + packet);\n                }\n            } finally {\n                finishPacket(packet);\n            }\n        }\n\n        SendThread(ClientCnxnSocket clientCnxnSocket) {\n            super(makeThreadName(\"-SendThread()\"));\n            state = States.CONNECTING;\n            this.clientCnxnSocket = clientCnxnSocket;\n            setDaemon(true);\n        }\n\n        // TODO: can not name this method getState since Thread.getState()\n        // already exists\n        // It would be cleaner to make class SendThread an implementation of\n        // Runnable\n        /**\n         * Used by ClientCnxnSocket\n         * \n         * @return\n         */\n        ZooKeeper.States getZkState() {\n            return state;\n        }\n\n        ClientCnxnSocket getClientCnxnSocket() {\n            return clientCnxnSocket;\n        }\n\n        void primeConnection() throws IOException {\n            LOG.info(\"Socket connection established to \"\n                     + clientCnxnSocket.getRemoteSocketAddress()\n                     + \", initiating session\");\n            isFirstConnect = false;\n            long sessId = (seenRwServerBefore) ? sessionId : 0;\n            ConnectRequest conReq = new ConnectRequest(0, lastZxid,\n                    sessionTimeout, sessId, sessionPasswd);\n            synchronized (outgoingQueue) {\n                // We add backwards since we are pushing into the front\n                // Only send if there's a pending watch\n                // TODO: here we have the only remaining use of zooKeeper in\n                // this class. It's to be eliminated!\n                if (!disableAutoWatchReset) {\n                    List<String> dataWatches = zooKeeper.getDataWatches();\n                    List<String> existWatches = zooKeeper.getExistWatches();\n                    List<String> childWatches = zooKeeper.getChildWatches();\n                    if (!dataWatches.isEmpty()\n                                || !existWatches.isEmpty() || !childWatches.isEmpty()) {\n\n                        Iterator<String> dataWatchesIter = prependChroot(dataWatches).iterator();\n                        Iterator<String> existWatchesIter = prependChroot(existWatches).iterator();\n                        Iterator<String> childWatchesIter = prependChroot(childWatches).iterator();\n                        long setWatchesLastZxid = lastZxid;\n\n                        while (dataWatchesIter.hasNext()\n                                       || existWatchesIter.hasNext() || childWatchesIter.hasNext()) {\n                            List<String> dataWatchesBatch = new ArrayList<String>();\n                            List<String> existWatchesBatch = new ArrayList<String>();\n                            List<String> childWatchesBatch = new ArrayList<String>();\n                            int batchLength = 0;\n\n                            // Note, we may exceed our max length by a bit when we add the last\n                            // watch in the batch. This isn't ideal, but it makes the code simpler.\n                            while (batchLength < SET_WATCHES_MAX_LENGTH) {\n                                final String watch;\n                                if (dataWatchesIter.hasNext()) {\n                                    watch = dataWatchesIter.next();\n                                    dataWatchesBatch.add(watch);\n                                } else if (existWatchesIter.hasNext()) {\n                                    watch = existWatchesIter.next();\n                                    existWatchesBatch.add(watch);\n                                } else if (childWatchesIter.hasNext()) {\n                                    watch = childWatchesIter.next();\n                                    childWatchesBatch.add(watch);\n                                } else {\n                                    break;\n                                }\n                                batchLength += watch.length();\n                            }\n\n                            SetWatches sw = new SetWatches(setWatchesLastZxid,\n                                    dataWatchesBatch,\n                                    existWatchesBatch,\n                                    childWatchesBatch);\n                            RequestHeader h = new RequestHeader();\n                            h.setType(ZooDefs.OpCode.setWatches);\n                            h.setXid(-8);\n                            Packet packet = new Packet(h, new ReplyHeader(), sw, null, null);\n                            outgoingQueue.addFirst(packet);\n                        }\n                    }\n                }\n\n                for (AuthData id : authInfo) {\n                    outgoingQueue.addFirst(new Packet(new RequestHeader(-4,\n                            OpCode.auth), null, new AuthPacket(0, id.scheme,\n                            id.data), null, null));\n                }\n                outgoingQueue.addFirst(new Packet(null, null, conReq,\n                            null, null, readOnly));\n            }\n            clientCnxnSocket.enableReadWriteOnly();\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Session establishment request sent on \"\n                        + clientCnxnSocket.getRemoteSocketAddress());\n            }\n        }\n\n        private List<String> prependChroot(List<String> paths) {\n            if (chrootPath != null && !paths.isEmpty()) {\n                for (int i = 0; i < paths.size(); ++i) {\n                    String clientPath = paths.get(i);\n                    String serverPath;\n                    // handle clientPath = \"/\"\n                    if (clientPath.length() == 1) {\n                        serverPath = chrootPath;\n                    } else {\n                        serverPath = chrootPath + clientPath;\n                    }\n                    paths.set(i, serverPath);\n                }\n            }\n            return paths;\n        }\n\n        private void sendPing() {\n            lastPingSentNs = System.nanoTime();\n            RequestHeader h = new RequestHeader(-2, OpCode.ping);\n            queuePacket(h, null, null, null, null, null, null, null, null);\n        }\n\n        private InetSocketAddress rwServerAddress = null;\n\n        private final static int minPingRwTimeout = 100;\n\n        private final static int maxPingRwTimeout = 60000;\n\n        private int pingRwTimeout = minPingRwTimeout;\n\n        // Set to true if and only if constructor of ZooKeeperSaslClient\n        // throws a LoginException: see startConnect() below.\n        private boolean saslLoginFailed = false;\n\n        private void startConnect(InetSocketAddress addr) throws IOException {\n            // initializing it for new connection\n            saslLoginFailed = false;\n            state = States.CONNECTING;\n\n            setName(getName().replaceAll(\"\\\\(.*\\\\)\",\n                    \"(\" + addr.getHostName() + \":\" + addr.getPort() + \")\"));\n            if (ZooKeeperSaslClient.isEnabled()) {\n                try {\n                    String principalUserName = System.getProperty(\n                            ZK_SASL_CLIENT_USERNAME, \"zookeeper\");\n                    zooKeeperSaslClient =\n                        new ZooKeeperSaslClient(\n                                principalUserName+\"/\"+addr.getHostName());\n                } catch (LoginException e) {\n                    // An authentication error occurred when the SASL client tried to initialize:\n                    // for Kerberos this means that the client failed to authenticate with the KDC.\n                    // This is different from an authentication error that occurs during communication\n                    // with the Zookeeper server, which is handled below.\n                    LOG.warn(\"SASL configuration failed: \" + e + \" Will continue connection to Zookeeper server without \"\n                      + \"SASL authentication, if Zookeeper server allows it.\");\n                    eventThread.queueEvent(new WatchedEvent(\n                      Watcher.Event.EventType.None,\n                      Watcher.Event.KeeperState.AuthFailed, null));\n                    saslLoginFailed = true;\n                }\n            }\n            logStartConnect(addr);\n\n            clientCnxnSocket.connect(addr);\n        }\n\n        private void logStartConnect(InetSocketAddress addr) {\n            String msg = \"Opening socket connection to server \" + addr;\n            if (zooKeeperSaslClient != null) {\n              msg += \". \" + zooKeeperSaslClient.getConfigStatus();\n            }\n            LOG.info(msg);\n        }\n\n        private static final String RETRY_CONN_MSG =\n            \", closing socket connection and attempting reconnect\";\n        \n        @Override\n        public void run() {\n            clientCnxnSocket.introduce(this,sessionId);\n            clientCnxnSocket.updateNow();\n            clientCnxnSocket.updateLastSendAndHeard();\n            int to;\n            long lastPingRwServer = Time.currentElapsedTime();\n            final int MAX_SEND_PING_INTERVAL = 10000; //10 seconds\n            InetSocketAddress serverAddress = null;\n            while (state.isAlive()) {\n                try {\n                    if (!clientCnxnSocket.isConnected()) {\n                        if(!isFirstConnect){\n                            try {\n                                Thread.sleep(r.nextInt(1000));\n                            } catch (InterruptedException e) {\n                                LOG.warn(\"Unexpected exception\", e);\n                            }\n                        }\n                        // don't re-establish connection if we are closing\n                        if (closing || !state.isAlive()) {\n                            break;\n                        }\n                        if (rwServerAddress != null) {\n                            serverAddress = rwServerAddress;\n                            rwServerAddress = null;\n                        } else {\n                            serverAddress = hostProvider.next(1000);\n                        }\n                        startConnect(serverAddress);\n                        clientCnxnSocket.updateLastSendAndHeard();\n                    }\n\n                    if (state.isConnected()) {\n                        // determine whether we need to send an AuthFailed event.\n                        if (zooKeeperSaslClient != null) {\n                            boolean sendAuthEvent = false;\n                            if (zooKeeperSaslClient.getSaslState() == ZooKeeperSaslClient.SaslState.INITIAL) {\n                                try {\n                                    zooKeeperSaslClient.initialize(ClientCnxn.this);\n                                } catch (SaslException e) {\n                                   LOG.error(\"SASL authentication with Zookeeper Quorum member failed: \" + e);\n                                    state = States.AUTH_FAILED;\n                                    sendAuthEvent = true;\n                                }\n                            }\n                            KeeperState authState = zooKeeperSaslClient.getKeeperState();\n                            if (authState != null) {\n                                if (authState == KeeperState.AuthFailed) {\n                                    // An authentication error occurred during authentication with the Zookeeper Server.\n                                    state = States.AUTH_FAILED;\n                                    sendAuthEvent = true;\n                                } else {\n                                    if (authState == KeeperState.SaslAuthenticated) {\n                                        sendAuthEvent = true;\n                                    }\n                                }\n                            }\n\n                            if (sendAuthEvent == true) {\n                                eventThread.queueEvent(new WatchedEvent(\n                                      Watcher.Event.EventType.None,\n                                      authState,null));\n                            }\n                        }\n                        to = readTimeout - clientCnxnSocket.getIdleRecv();\n                    } else {\n                        to = connectTimeout - clientCnxnSocket.getIdleRecv();\n                    }\n                    \n                    if (to <= 0) {\n                        String warnInfo;\n                        warnInfo = \"Client session timed out, have not heard from server in \"\n                            + clientCnxnSocket.getIdleRecv()\n                            + \"ms\"\n                            + \" for sessionid 0x\"\n                            + Long.toHexString(sessionId);\n                        LOG.warn(warnInfo);\n                        throw new SessionTimeoutException(warnInfo);\n                    }\n                    if (state.isConnected()) {\n                    \t//1000(1 second) is to prevent race condition missing to send the second ping\n                    \t//also make sure not to send too many pings when readTimeout is small \n                        int timeToNextPing = readTimeout / 2 - clientCnxnSocket.getIdleSend() - \n                        \t\t((clientCnxnSocket.getIdleSend() > 1000) ? 1000 : 0);\n                        //send a ping request either time is due or no packet sent out within MAX_SEND_PING_INTERVAL\n                        if (timeToNextPing <= 0 || clientCnxnSocket.getIdleSend() > MAX_SEND_PING_INTERVAL) {\n                            sendPing();\n                            clientCnxnSocket.updateLastSend();\n                        } else {\n                            if (timeToNextPing < to) {\n                                to = timeToNextPing;\n                            }\n                        }\n                    }\n\n                    // If we are in read-only mode, seek for read/write server\n                    if (state == States.CONNECTEDREADONLY) {\n                        long now = Time.currentElapsedTime();\n                        int idlePingRwServer = (int) (now - lastPingRwServer);\n                        if (idlePingRwServer >= pingRwTimeout) {\n                            lastPingRwServer = now;\n                            idlePingRwServer = 0;\n                            pingRwTimeout =\n                                Math.min(2*pingRwTimeout, maxPingRwTimeout);\n                            pingRwServer();\n                        }\n                        to = Math.min(to, pingRwTimeout - idlePingRwServer);\n                    }\n\n                    clientCnxnSocket.doTransport(to, pendingQueue, outgoingQueue, ClientCnxn.this);\n                } catch (Throwable e) {\n                    if (closing) {\n                        if (LOG.isDebugEnabled()) {\n                            // closing so this is expected\n                            LOG.debug(\"An exception was thrown while closing send thread for session 0x\"\n                                    + Long.toHexString(getSessionId())\n                                    + \" : \" + e.getMessage());\n                        }\n                        break;\n                    } else {\n                        // this is ugly, you have a better way speak up\n                        if (e instanceof SessionExpiredException) {\n                            LOG.info(e.getMessage() + \", closing socket connection\");\n                        } else if (e instanceof SessionTimeoutException) {\n                            LOG.info(e.getMessage() + RETRY_CONN_MSG);\n                        } else if (e instanceof EndOfStreamException) {\n                            LOG.info(e.getMessage() + RETRY_CONN_MSG);\n                        } else if (e instanceof RWServerFoundException) {\n                            LOG.info(e.getMessage());\n                        } else if (e instanceof SocketException) {\n                            LOG.info(\"Socket error occurred: {}: {}\", serverAddress, e.getMessage());\n                        } else {\n                            LOG.warn(\"Session 0x{} for server {}, unexpected error{}\",\n                                            Long.toHexString(getSessionId()),\n                                            serverAddress,\n                                            RETRY_CONN_MSG,\n                                            e);\n                        }\n                        cleanup();\n                        if (state.isAlive()) {\n                            eventThread.queueEvent(new WatchedEvent(\n                                    Event.EventType.None,\n                                    Event.KeeperState.Disconnected,\n                                    null));\n                        }\n                        clientCnxnSocket.updateNow();\n                        clientCnxnSocket.updateLastSendAndHeard();\n                    }\n                }\n            }\n            cleanup();\n            clientCnxnSocket.close();\n            if (state.isAlive()) {\n                eventThread.queueEvent(new WatchedEvent(Event.EventType.None,\n                        Event.KeeperState.Disconnected, null));\n            }\n            ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(),\n                    \"SendThread exited loop for session: 0x\"\n                           + Long.toHexString(getSessionId()));\n        }\n\n        private void pingRwServer() throws RWServerFoundException {\n            String result = null;\n            InetSocketAddress addr = hostProvider.next(0);\n            LOG.info(\"Checking server \" + addr + \" for being r/w.\" +\n                    \" Timeout \" + pingRwTimeout);\n\n            Socket sock = null;\n            BufferedReader br = null;\n            try {\n                sock = new Socket(addr.getHostName(), addr.getPort());\n                sock.setSoLinger(false, -1);\n                sock.setSoTimeout(1000);\n                sock.setTcpNoDelay(true);\n                sock.getOutputStream().write(\"isro\".getBytes());\n                sock.getOutputStream().flush();\n                sock.shutdownOutput();\n                br = new BufferedReader(\n                        new InputStreamReader(sock.getInputStream()));\n                result = br.readLine();\n            } catch (ConnectException e) {\n                // ignore, this just means server is not up\n            } catch (IOException e) {\n                // some unexpected error, warn about it\n                LOG.warn(\"Exception while seeking for r/w server \" +\n                        e.getMessage(), e);\n            } finally {\n                if (sock != null) {\n                    try {\n                        sock.close();\n                    } catch (IOException e) {\n                        LOG.warn(\"Unexpected exception\", e);\n                    }\n                }\n                if (br != null) {\n                    try {\n                        br.close();\n                    } catch (IOException e) {\n                        LOG.warn(\"Unexpected exception\", e);\n                    }\n                }\n            }\n\n            if (\"rw\".equals(result)) {\n                pingRwTimeout = minPingRwTimeout;\n                // save the found address so that it's used during the next\n                // connection attempt\n                rwServerAddress = addr;\n                throw new RWServerFoundException(\"Majority server found at \"\n                        + addr.getHostName() + \":\" + addr.getPort());\n            }\n        }\n\n        private void cleanup() {\n            clientCnxnSocket.cleanup();\n            synchronized (pendingQueue) {\n                for (Packet p : pendingQueue) {\n                    conLossPacket(p);\n                }\n                pendingQueue.clear();\n            }\n            synchronized (outgoingQueue) {\n                for (Packet p : outgoingQueue) {\n                    conLossPacket(p);\n                }\n                outgoingQueue.clear();\n            }\n        }\n\n        /**\n         * Callback invoked by the ClientCnxnSocket once a connection has been\n         * established.\n         * \n         * @param _negotiatedSessionTimeout\n         * @param _sessionId\n         * @param _sessionPasswd\n         * @param isRO\n         * @throws IOException\n         */\n        void onConnected(int _negotiatedSessionTimeout, long _sessionId,\n                byte[] _sessionPasswd, boolean isRO) throws IOException {\n            negotiatedSessionTimeout = _negotiatedSessionTimeout;\n            if (negotiatedSessionTimeout <= 0) {\n                state = States.CLOSED;\n\n                eventThread.queueEvent(new WatchedEvent(\n                        Watcher.Event.EventType.None,\n                        Watcher.Event.KeeperState.Expired, null));\n                eventThread.queueEventOfDeath();\n\n                String warnInfo;\n                warnInfo = \"Unable to reconnect to ZooKeeper service, session 0x\"\n                    + Long.toHexString(sessionId) + \" has expired\";\n                LOG.warn(warnInfo);\n                throw new SessionExpiredException(warnInfo);\n            }\n            if (!readOnly && isRO) {\n                LOG.error(\"Read/write client got connected to read-only server\");\n            }\n            readTimeout = negotiatedSessionTimeout * 2 / 3;\n            connectTimeout = negotiatedSessionTimeout / hostProvider.size();\n            hostProvider.onConnected();\n            sessionId = _sessionId;\n            sessionPasswd = _sessionPasswd;\n            state = (isRO) ?\n                    States.CONNECTEDREADONLY : States.CONNECTED;\n            seenRwServerBefore |= !isRO;\n            LOG.info(\"Session establishment complete on server \"\n                    + clientCnxnSocket.getRemoteSocketAddress()\n                    + \", sessionid = 0x\" + Long.toHexString(sessionId)\n                    + \", negotiated timeout = \" + negotiatedSessionTimeout\n                    + (isRO ? \" (READ-ONLY mode)\" : \"\"));\n            KeeperState eventState = (isRO) ?\n                    KeeperState.ConnectedReadOnly : KeeperState.SyncConnected;\n            eventThread.queueEvent(new WatchedEvent(\n                    Watcher.Event.EventType.None,\n                    eventState, null));\n        }\n\n        void close() {\n            state = States.CLOSED;\n            clientCnxnSocket.wakeupCnxn();\n        }\n\n        void testableCloseSocket() throws IOException {\n            clientCnxnSocket.testableCloseSocket();\n        }\n\n        public boolean clientTunneledAuthenticationInProgress() {\n            // 1. SASL client is disabled.\n            if (!ZooKeeperSaslClient.isEnabled()) {\n                return false;\n            }\n\n            // 2. SASL login failed.\n            if (saslLoginFailed == true) {\n                return false;\n            }\n\n            // 3. SendThread has not created the authenticating object yet,\n            // therefore authentication is (at the earliest stage of being) in progress.\n            if (zooKeeperSaslClient == null) {\n                return true;\n            }\n\n            // 4. authenticating object exists, so ask it for its progress.\n            return zooKeeperSaslClient.clientTunneledAuthenticationInProgress();\n        }\n\n        public void sendPacket(Packet p) throws IOException {\n            clientCnxnSocket.sendPacket(p);\n        }\n    }\n\n    /**\n     * Shutdown the send/event threads. This method should not be called\n     * directly - rather it should be called as part of close operation. This\n     * method is primarily here to allow the tests to verify disconnection\n     * behavior.\n     */\n    public void disconnect() {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Disconnecting client for session: 0x\"\n                      + Long.toHexString(getSessionId()));\n        }\n\n        sendThread.close();\n        eventThread.queueEventOfDeath();\n    }\n\n    /**\n     * Close the connection, which includes; send session disconnect to the\n     * server, shutdown the send/event threads.\n     *\n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Closing client for session: 0x\"\n                      + Long.toHexString(getSessionId()));\n        }\n\n        try {\n            RequestHeader h = new RequestHeader();\n            h.setType(ZooDefs.OpCode.closeSession);\n\n            submitRequest(h, null, null, null);\n        } catch (InterruptedException e) {\n            // ignore, close the send/event threads\n        } finally {\n            disconnect();\n        }\n    }\n\n    private int xid = 1;\n\n    private volatile States state = States.NOT_CONNECTED;\n\n    /*\n     * getXid() is called externally by ClientCnxnNIO::doIO() when packets are sent from the outgoingQueue to\n     * the server. Thus, getXid() must be public.\n     */\n    synchronized public int getXid() {\n        return xid++;\n    }\n\n    public ReplyHeader submitRequest(RequestHeader h, Record request,\n            Record response, WatchRegistration watchRegistration)\n            throws InterruptedException {\n        ReplyHeader r = new ReplyHeader();\n        Packet packet = queuePacket(h, r, request, response, null, null, null,\n                    null, watchRegistration);\n        synchronized (packet) {\n            while (!packet.finished) {\n                packet.wait();\n            }\n        }\n        return r;\n    }\n\n    public void enableWrite() {\n        sendThread.getClientCnxnSocket().enableWrite();\n    }\n\n    public void sendPacket(Record request, Record response, AsyncCallback cb, int opCode)\n    throws IOException {\n        // Generate Xid now because it will be sent immediately,\n        // by call to sendThread.sendPacket() below.\n        int xid = getXid();\n        RequestHeader h = new RequestHeader();\n        h.setXid(xid);\n        h.setType(opCode);\n\n        ReplyHeader r = new ReplyHeader();\n        r.setXid(xid);\n\n        Packet p = new Packet(h, r, request, response, null, false);\n        p.cb = cb;\n        sendThread.sendPacket(p);\n    }\n\n    Packet queuePacket(RequestHeader h, ReplyHeader r, Record request,\n            Record response, AsyncCallback cb, String clientPath,\n            String serverPath, Object ctx, WatchRegistration watchRegistration)\n    {\n        Packet packet = null;\n\n        // Note that we do not generate the Xid for the packet yet. It is\n        // generated later at send-time, by an implementation of ClientCnxnSocket::doIO(),\n        // where the packet is actually sent.\n        synchronized (outgoingQueue) {\n            packet = new Packet(h, r, request, response, watchRegistration);\n            packet.cb = cb;\n            packet.ctx = ctx;\n            packet.clientPath = clientPath;\n            packet.serverPath = serverPath;\n            if (!state.isAlive() || closing) {\n                conLossPacket(packet);\n            } else {\n                // If the client is asking to close the session then\n                // mark as closing\n                if (h.getType() == OpCode.closeSession) {\n                    closing = true;\n                }\n                outgoingQueue.add(packet);\n            }\n        }\n        sendThread.getClientCnxnSocket().wakeupCnxn();\n        return packet;\n    }\n\n    public void addAuthInfo(String scheme, byte auth[]) {\n        if (!state.isAlive()) {\n            return;\n        }\n        authInfo.add(new AuthData(scheme, auth));\n        queuePacket(new RequestHeader(-4, OpCode.auth), null,\n                new AuthPacket(0, scheme, auth), null, null, null, null,\n                null, null);\n    }\n\n    States getState() {\n        return state;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ClientCnxnSocket.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.zookeeper.ClientCnxn.Packet;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.proto.ConnectResponse;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A ClientCnxnSocket does the lower level communication with a socket\n * implementation.\n * \n * This code has been moved out of ClientCnxn so that a Netty implementation can\n * be provided as an alternative to the NIO socket code.\n * \n */\nabstract class ClientCnxnSocket {\n    private static final Logger LOG = LoggerFactory.getLogger(ClientCnxnSocket.class);\n\n    protected boolean initialized;\n\n    /**\n     * This buffer is only used to read the length of the incoming message.\n     */\n    protected final ByteBuffer lenBuffer = ByteBuffer.allocateDirect(4);\n\n    /**\n     * After the length is read, a new incomingBuffer is allocated in\n     * readLength() to receive the full message.\n     */\n    protected ByteBuffer incomingBuffer = lenBuffer;\n    protected long sentCount = 0;\n    protected long recvCount = 0;\n    protected long lastHeard;\n    protected long lastSend;\n    protected long now;\n    protected ClientCnxn.SendThread sendThread;\n\n    /**\n     * The sessionId is only available here for Log and Exception messages.\n     * Otherwise the socket doesn't need to know it.\n     */\n    protected long sessionId;\n\n    void introduce(ClientCnxn.SendThread sendThread, long sessionId) {\n        this.sendThread = sendThread;\n        this.sessionId = sessionId;\n    }\n\n    void updateNow() {\n        now = Time.currentElapsedTime();\n    }\n\n    int getIdleRecv() {\n        return (int) (now - lastHeard);\n    }\n\n    int getIdleSend() {\n        return (int) (now - lastSend);\n    }\n\n    long getSentCount() {\n        return sentCount;\n    }\n\n    long getRecvCount() {\n        return recvCount;\n    }\n\n    void updateLastHeard() {\n        this.lastHeard = now;\n    }\n\n    void updateLastSend() {\n        this.lastSend = now;\n    }\n\n    void updateLastSendAndHeard() {\n        this.lastSend = now;\n        this.lastHeard = now;\n    }\n\n    protected void readLength() throws IOException {\n        int len = incomingBuffer.getInt();\n        if (len < 0 || len >= ClientCnxn.packetLen) {\n            throw new IOException(\"Packet len\" + len + \" is out of range!\");\n        }\n        incomingBuffer = ByteBuffer.allocate(len);\n    }\n\n    void readConnectResult() throws IOException {\n        if (LOG.isTraceEnabled()) {\n            StringBuilder buf = new StringBuilder(\"0x[\");\n            for (byte b : incomingBuffer.array()) {\n                buf.append(Integer.toHexString(b) + \",\");\n            }\n            buf.append(\"]\");\n            LOG.trace(\"readConnectResult \" + incomingBuffer.remaining() + \" \"\n                    + buf.toString());\n        }\n        ByteBufferInputStream bbis = new ByteBufferInputStream(incomingBuffer);\n        BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);\n        ConnectResponse conRsp = new ConnectResponse();\n        conRsp.deserialize(bbia, \"connect\");\n\n        // read \"is read-only\" flag\n        boolean isRO = false;\n        try {\n            isRO = bbia.readBool(\"readOnly\");\n        } catch (IOException e) {\n            // this is ok -- just a packet from an old server which\n            // doesn't contain readOnly field\n            LOG.warn(\"Connected to an old server; r-o mode will be unavailable\");\n        }\n\n        this.sessionId = conRsp.getSessionId();\n        sendThread.onConnected(conRsp.getTimeOut(), this.sessionId,\n                conRsp.getPasswd(), isRO);\n    }\n\n    abstract boolean isConnected();\n\n    abstract void connect(InetSocketAddress addr) throws IOException;\n\n    abstract SocketAddress getRemoteSocketAddress();\n\n    abstract SocketAddress getLocalSocketAddress();\n\n    abstract void cleanup();\n\n    abstract void close();\n\n    abstract void wakeupCnxn();\n\n    abstract void enableWrite();\n\n    abstract void disableWrite();\n\n    abstract void enableReadWriteOnly();\n\n    abstract void doTransport(int waitTimeOut, List<Packet> pendingQueue,\n            LinkedList<Packet> outgoingQueue, ClientCnxn cnxn)\n            throws IOException, InterruptedException;\n\n    abstract void testableCloseSocket() throws IOException;\n\n    abstract void sendPacket(Packet p) throws IOException;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ClientCnxnSocketNIO.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Set;\n\nimport org.apache.zookeeper.ClientCnxn.EndOfStreamException;\nimport org.apache.zookeeper.ClientCnxn.Packet;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ClientCnxnSocketNIO extends ClientCnxnSocket {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(ClientCnxnSocketNIO.class);\n\n    private final Selector selector = Selector.open();\n\n    private SelectionKey sockKey;\n\n    ClientCnxnSocketNIO() throws IOException {\n        super();\n    }\n\n    @Override\n    boolean isConnected() {\n        return sockKey != null;\n    }\n    \n    /**\n     * @return true if a packet was received\n     * @throws InterruptedException\n     * @throws IOException\n     */\n    void doIO(List<Packet> pendingQueue, LinkedList<Packet> outgoingQueue, ClientCnxn cnxn)\n      throws InterruptedException, IOException {\n        SocketChannel sock = (SocketChannel) sockKey.channel();\n        if (sock == null) {\n            throw new IOException(\"Socket is null!\");\n        }\n        if (sockKey.isReadable()) {\n            int rc = sock.read(incomingBuffer);\n            if (rc < 0) {\n                throw new EndOfStreamException(\n                        \"Unable to read additional data from server sessionid 0x\"\n                                + Long.toHexString(sessionId)\n                                + \", likely server has closed socket\");\n            }\n            if (!incomingBuffer.hasRemaining()) {\n                incomingBuffer.flip();\n                if (incomingBuffer == lenBuffer) {\n                    recvCount++;\n                    readLength();\n                } else if (!initialized) {\n                    readConnectResult();\n                    enableRead();\n                    if (findSendablePacket(outgoingQueue,\n                            cnxn.sendThread.clientTunneledAuthenticationInProgress()) != null) {\n                        // Since SASL authentication has completed (if client is configured to do so),\n                        // outgoing packets waiting in the outgoingQueue can now be sent.\n                        enableWrite();\n                    }\n                    lenBuffer.clear();\n                    incomingBuffer = lenBuffer;\n                    updateLastHeard();\n                    initialized = true;\n                } else {\n                    sendThread.readResponse(incomingBuffer);\n                    lenBuffer.clear();\n                    incomingBuffer = lenBuffer;\n                    updateLastHeard();\n                }\n            }\n        }\n        if (sockKey.isWritable()) {\n            synchronized(outgoingQueue) {\n                Packet p = findSendablePacket(outgoingQueue,\n                        cnxn.sendThread.clientTunneledAuthenticationInProgress());\n\n                if (p != null) {\n                    updateLastSend();\n                    // If we already started writing p, p.bb will already exist\n                    if (p.bb == null) {\n                        if ((p.requestHeader != null) &&\n                                (p.requestHeader.getType() != OpCode.ping) &&\n                                (p.requestHeader.getType() != OpCode.auth)) {\n                            p.requestHeader.setXid(cnxn.getXid());\n                        }\n                        p.createBB();\n                    }\n                    sock.write(p.bb);\n                    if (!p.bb.hasRemaining()) {\n                        sentCount++;\n                        outgoingQueue.removeFirstOccurrence(p);\n                        if (p.requestHeader != null\n                                && p.requestHeader.getType() != OpCode.ping\n                                && p.requestHeader.getType() != OpCode.auth) {\n                            synchronized (pendingQueue) {\n                                pendingQueue.add(p);\n                            }\n                        }\n                    }\n                }\n                if (outgoingQueue.isEmpty()) {\n                    // No more packets to send: turn off write interest flag.\n                    // Will be turned on later by a later call to enableWrite(),\n                    // from within ZooKeeperSaslClient (if client is configured\n                    // to attempt SASL authentication), or in either doIO() or\n                    // in doTransport() if not.\n                    disableWrite();\n                } else if (!initialized && p != null && !p.bb.hasRemaining()) {\n                    // On initial connection, write the complete connect request\n                    // packet, but then disable further writes until after\n                    // receiving a successful connection response.  If the\n                    // session is expired, then the server sends the expiration\n                    // response and immediately closes its end of the socket.  If\n                    // the client is simultaneously writing on its end, then the\n                    // TCP stack may choose to abort with RST, in which case the\n                    // client would never receive the session expired event.  See\n                    // http://docs.oracle.com/javase/6/docs/technotes/guides/net/articles/connection_release.html\n                    disableWrite();\n                } else {\n                    // Just in case\n                    enableWrite();\n                }\n            }\n        }\n    }\n\n    private Packet findSendablePacket(LinkedList<Packet> outgoingQueue,\n                                      boolean clientTunneledAuthenticationInProgress) {\n        synchronized (outgoingQueue) {\n            if (outgoingQueue.isEmpty()) {\n                return null;\n            }\n            if (outgoingQueue.getFirst().bb != null // If we've already starting sending the first packet, we better finish\n                || !clientTunneledAuthenticationInProgress) {\n                return outgoingQueue.getFirst();\n            }\n\n            // Since client's authentication with server is in progress,\n            // send only the null-header packet queued by primeConnection().\n            // This packet must be sent so that the SASL authentication process\n            // can proceed, but all other packets should wait until\n            // SASL authentication completes.\n            ListIterator<Packet> iter = outgoingQueue.listIterator();\n            while (iter.hasNext()) {\n                Packet p = iter.next();\n                if (p.requestHeader == null) {\n                    // We've found the priming-packet. Move it to the beginning of the queue.\n                    iter.remove();\n                    outgoingQueue.add(0, p);\n                    return p;\n                } else {\n                    // Non-priming packet: defer it until later, leaving it in the queue\n                    // until authentication completes.\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"deferring non-priming packet: \" + p +\n                                \"until SASL authentication completes.\");\n                    }\n                }\n            }\n            // no sendable packet found.\n            return null;\n        }\n    }\n\n    @Override\n    void cleanup() {\n        if (sockKey != null) {\n            SocketChannel sock = (SocketChannel) sockKey.channel();\n            sockKey.cancel();\n            try {\n                sock.socket().shutdownInput();\n            } catch (IOException e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Ignoring exception during shutdown input\", e);\n                }\n            }\n            try {\n                sock.socket().shutdownOutput();\n            } catch (IOException e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Ignoring exception during shutdown output\",\n                            e);\n                }\n            }\n            try {\n                sock.socket().close();\n            } catch (IOException e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Ignoring exception during socket close\", e);\n                }\n            }\n            try {\n                sock.close();\n            } catch (IOException e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Ignoring exception during channel close\", e);\n                }\n            }\n        }\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"SendThread interrupted during sleep, ignoring\");\n            }\n        }\n        sockKey = null;\n    }\n \n    @Override\n    void close() {\n        try {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Doing client selector close\");\n            }\n            selector.close();\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Closed client selector\");\n            }\n        } catch (IOException e) {\n            LOG.warn(\"Ignoring exception during selector close\", e);\n        }\n    }\n    \n    /**\n     * create a socket channel.\n     * @return the created socket channel\n     * @throws IOException\n     */\n    SocketChannel createSock() throws IOException {\n        SocketChannel sock;\n        sock = SocketChannel.open();\n        sock.configureBlocking(false);\n        sock.socket().setSoLinger(false, -1);\n        sock.socket().setTcpNoDelay(true);\n        return sock;\n    }\n\n    /**\n     * register with the selection and connect\n     * @param sock the {@link SocketChannel} \n     * @param addr the address of remote host\n     * @throws IOException\n     */\n    void registerAndConnect(SocketChannel sock, InetSocketAddress addr) \n    throws IOException {\n        sockKey = sock.register(selector, SelectionKey.OP_CONNECT);\n        boolean immediateConnect = sock.connect(addr);\n        if (immediateConnect) {\n            sendThread.primeConnection();\n        }\n    }\n    \n    @Override\n    void connect(InetSocketAddress addr) throws IOException {\n        SocketChannel sock = createSock();\n        try {\n           registerAndConnect(sock, addr);\n        } catch (IOException e) {\n            LOG.error(\"Unable to open socket to \" + addr);\n            sock.close();\n            throw e;\n        }\n        initialized = false;\n\n        /*\n         * Reset incomingBuffer\n         */\n        lenBuffer.clear();\n        incomingBuffer = lenBuffer;\n    }\n\n    /**\n     * Returns the address to which the socket is connected.\n     * \n     * @return ip address of the remote side of the connection or null if not\n     *         connected\n     */\n    @Override\n    SocketAddress getRemoteSocketAddress() {\n        // a lot could go wrong here, so rather than put in a bunch of code\n        // to check for nulls all down the chain let's do it the simple\n        // yet bulletproof way\n        try {\n            return ((SocketChannel) sockKey.channel()).socket()\n                    .getRemoteSocketAddress();\n        } catch (NullPointerException e) {\n            return null;\n        }\n    }\n\n    /**\n     * Returns the local address to which the socket is bound.\n     * \n     * @return ip address of the remote side of the connection or null if not\n     *         connected\n     */\n    @Override\n    SocketAddress getLocalSocketAddress() {\n        // a lot could go wrong here, so rather than put in a bunch of code\n        // to check for nulls all down the chain let's do it the simple\n        // yet bulletproof way\n        try {\n            return ((SocketChannel) sockKey.channel()).socket()\n                    .getLocalSocketAddress();\n        } catch (NullPointerException e) {\n            return null;\n        }\n    }\n\n    @Override\n    synchronized void wakeupCnxn() {\n        selector.wakeup();\n    }\n    \n    @Override\n    void doTransport(int waitTimeOut, List<Packet> pendingQueue, LinkedList<Packet> outgoingQueue,\n                     ClientCnxn cnxn)\n            throws IOException, InterruptedException {\n        selector.select(waitTimeOut);\n        Set<SelectionKey> selected;\n        synchronized (this) {\n            selected = selector.selectedKeys();\n        }\n        // Everything below and until we get back to the select is\n        // non blocking, so time is effectively a constant. That is\n        // Why we just have to do this once, here\n        updateNow();\n        for (SelectionKey k : selected) {\n            SocketChannel sc = ((SocketChannel) k.channel());\n            if ((k.readyOps() & SelectionKey.OP_CONNECT) != 0) {\n                if (sc.finishConnect()) {\n                    updateLastSendAndHeard();\n                    sendThread.primeConnection();\n                }\n            } else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {\n                doIO(pendingQueue, outgoingQueue, cnxn);\n            }\n        }\n        if (sendThread.getZkState().isConnected()) {\n            synchronized(outgoingQueue) {\n                if (findSendablePacket(outgoingQueue,\n                        cnxn.sendThread.clientTunneledAuthenticationInProgress()) != null) {\n                    enableWrite();\n                }\n            }\n        }\n        selected.clear();\n    }\n\n    //TODO should this be synchronized?\n    @Override\n    void testableCloseSocket() throws IOException {\n        LOG.info(\"testableCloseSocket() called\");\n        ((SocketChannel) sockKey.channel()).socket().close();\n    }\n\n    @Override\n    synchronized void enableWrite() {\n        int i = sockKey.interestOps();\n        if ((i & SelectionKey.OP_WRITE) == 0) {\n            sockKey.interestOps(i | SelectionKey.OP_WRITE);\n        }\n    }\n\n    @Override\n    public synchronized void disableWrite() {\n        int i = sockKey.interestOps();\n        if ((i & SelectionKey.OP_WRITE) != 0) {\n            sockKey.interestOps(i & (~SelectionKey.OP_WRITE));\n        }\n    }\n\n    synchronized private void enableRead() {\n        int i = sockKey.interestOps();\n        if ((i & SelectionKey.OP_READ) == 0) {\n            sockKey.interestOps(i | SelectionKey.OP_READ);\n        }\n    }\n\n    @Override\n    synchronized void enableReadWriteOnly() {\n        sockKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);\n    }\n\n    Selector getSelector() {\n        return selector;\n    }\n\n    @Override\n    void sendPacket(Packet p) throws IOException {\n        SocketChannel sock = (SocketChannel) sockKey.channel();\n        if (sock == null) {\n            throw new IOException(\"Socket is null!\");\n        }\n        p.createBB();\n        ByteBuffer pbb = p.bb;\n        sock.write(pbb);\n    }\n\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ClientWatchManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.util.Set;\n\n/**\n */\npublic interface ClientWatchManager {\n    /**\n     * Return a set of watchers that should be notified of the event. The \n     * manager must not notify the watcher(s), however it will update it's \n     * internal structure as if the watches had triggered. The intent being \n     * that the callee is now responsible for notifying the watchers of the \n     * event, possibly at some later time.\n     * \n     * @param state event state\n     * @param type event type\n     * @param path event path\n     * @return may be empty set but must not be null\n     */\n    public Set<Watcher> materialize(Watcher.Event.KeeperState state,\n        Watcher.Event.EventType type, String path);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/CreateMode.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\n\n/***\n *  CreateMode value determines how the znode is created on ZooKeeper.\n */\n@InterfaceAudience.Public\npublic enum CreateMode {\n    \n    /**\n     * The znode will not be automatically deleted upon client's disconnect.\n     */\n    PERSISTENT (0, false, false),\n    /**\n    * The znode will not be automatically deleted upon client's disconnect,\n    * and its name will be appended with a monotonically increasing number.\n    */\n    PERSISTENT_SEQUENTIAL (2, false, true),\n    /**\n     * The znode will be deleted upon the client's disconnect.\n     */\n    EPHEMERAL (1, true, false),\n    /**\n     * The znode will be deleted upon the client's disconnect, and its name\n     * will be appended with a monotonically increasing number.\n     */\n    EPHEMERAL_SEQUENTIAL (3, true, true);\n\n    private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);\n\n    private boolean ephemeral;\n    private boolean sequential;\n    private int flag;\n\n    CreateMode(int flag, boolean ephemeral, boolean sequential) {\n        this.flag = flag;\n        this.ephemeral = ephemeral;\n        this.sequential = sequential;\n    }\n\n    public boolean isEphemeral() { \n        return ephemeral;\n    }\n\n    public boolean isSequential() { \n        return sequential;\n    }\n\n    public int toFlag() {\n        return flag;\n    }\n\n    /**\n     * Map an integer value to a CreateMode value\n     */\n    static public CreateMode fromFlag(int flag) throws KeeperException {\n        switch(flag) {\n        case 0: return CreateMode.PERSISTENT;\n\n        case 1: return CreateMode.EPHEMERAL;\n\n        case 2: return CreateMode.PERSISTENT_SEQUENTIAL;\n\n        case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;\n\n        default:\n            String errMsg = \"Received an invalid flag value: \" + flag\n                    + \" to convert to a CreateMode\";\n            LOG.error(errMsg);\n            throw new KeeperException.BadArgumentsException(errMsg);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Environment.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Provide insight into the runtime environment.\n *\n */\npublic class Environment {\n    public static final String JAAS_CONF_KEY = \"java.security.auth.login.config\";\n\n    public static class Entry {\n        private String k;\n        private String v;\n        public Entry(String k, String v) {\n            this.k = k;\n            this.v = v;\n        }\n        public String getKey() { return k; }\n        public String getValue() { return v; }\n        \n        @Override\n        public String toString() {\n            return k + \"=\" + v;\n        }\n    }\n\n    private static void put(ArrayList<Entry> l, String k, String v) {\n        l.add(new Entry(k,v));\n    }\n\n    public static List<Entry> list() {\n        ArrayList<Entry> l = new ArrayList<Entry>();\n        put(l, \"zookeeper.version\", Version.getFullVersion());\n\n        try {\n            put(l, \"host.name\",\n                InetAddress.getLocalHost().getCanonicalHostName());\n        } catch (UnknownHostException e) {\n            put(l, \"host.name\", \"<NA>\");\n        }\n\n        put(l, \"java.version\",\n                System.getProperty(\"java.version\", \"<NA>\"));\n        put(l, \"java.vendor\",\n                System.getProperty(\"java.vendor\", \"<NA>\"));\n        put(l, \"java.home\",\n                System.getProperty(\"java.home\", \"<NA>\"));\n        put(l, \"java.class.path\",\n                System.getProperty(\"java.class.path\", \"<NA>\"));\n        put(l, \"java.library.path\",\n                System.getProperty(\"java.library.path\", \"<NA>\"));\n        put(l, \"java.io.tmpdir\",\n                System.getProperty(\"java.io.tmpdir\", \"<NA>\"));\n        put(l, \"java.compiler\",\n                System.getProperty(\"java.compiler\", \"<NA>\"));\n        put(l, \"os.name\",\n                System.getProperty(\"os.name\", \"<NA>\"));\n        put(l, \"os.arch\",\n                System.getProperty(\"os.arch\", \"<NA>\"));\n        put(l, \"os.version\",\n                System.getProperty(\"os.version\", \"<NA>\"));\n        put(l, \"user.name\",\n                System.getProperty(\"user.name\", \"<NA>\"));\n        put(l, \"user.home\",\n                System.getProperty(\"user.home\", \"<NA>\"));\n        put(l, \"user.dir\",\n                System.getProperty(\"user.dir\", \"<NA>\"));\n        \n        return l;\n    }\n    \n    public static void logEnv(String msg, Logger log) {\n        List<Entry> env = Environment.list();\n        for (Entry e : env) {\n            log.info(msg + e.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/JLineZNodeCompletor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.util.List;\n\nimport jline.Completor;\n\nclass JLineZNodeCompletor implements Completor {\n    private ZooKeeper zk;\n\n    public JLineZNodeCompletor(ZooKeeper zk) {\n        this.zk = zk;\n    }\n\n    @SuppressWarnings(value={\"unchecked\", \"rawtypes\"})\n    public int complete(String buffer, int cursor, List candidates) {\n        // Guarantee that the final token is the one we're expanding\n        buffer = buffer.substring(0,cursor);\n        String token = \"\";\n        if (!buffer.endsWith(\" \")) {\n            String[] tokens = buffer.split(\" \");\n            if (tokens.length != 0) {\n                token = tokens[tokens.length-1] ;\n            }\n        }\n\n        if (token.startsWith(\"/\")){\n            return completeZNode( buffer, token, candidates);\n        }\n        return completeCommand(buffer, token, candidates);\n    }\n\n    private int completeCommand(String buffer, String token,\n            List<String> candidates)\n    {\n        for (String cmd : ZooKeeperMain.getCommands()) {\n            if (cmd.startsWith( token )) {\n                candidates.add(cmd);\n            }\n        }\n        return buffer.lastIndexOf(\" \")+1;\n    }\n\n    private int completeZNode( String buffer, String token,\n            List<String> candidates)\n    {\n        String path = token;\n        int idx = path.lastIndexOf(\"/\") + 1;\n        String prefix = path.substring(idx);\n        try {\n            // Only the root path can end in a /, so strip it off every other prefix\n            String dir = idx == 1 ? \"/\" : path.substring(0,idx-1);\n            List<String> children = zk.getChildren(dir, false);\n            for (String child : children) {\n                if (child.startsWith(prefix)) {\n                    candidates.add( child );\n                }\n            }\n        } catch( InterruptedException e) {\n            return 0;\n        }\n        catch( KeeperException e) {\n            return 0;\n        }\n        return candidates.size() == 0 ? buffer.length() : buffer.lastIndexOf(\"/\") + 1;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/KeeperException.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\n\nimport java.util.ArrayList;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@SuppressWarnings(\"serial\")\n@InterfaceAudience.Public\npublic abstract class KeeperException extends Exception {\n    /**\n     * All multi-requests that result in an exception retain the results\n     * here so that it is possible to examine the problems in the catch\n     * scope.  Non-multi requests will get a null if they try to access\n     * these results.\n     */\n    private List<OpResult> results;\n\n    /**\n     * All non-specific keeper exceptions should be constructed via\n     * this factory method in order to guarantee consistency in error\n     * codes and such.  If you know the error code, then you should\n     * construct the special purpose exception directly.  That will\n     * allow you to have the most specific possible declarations of\n     * what exceptions might actually be thrown.\n     *\n     * @param code The error code.\n     * @param path The ZooKeeper path being operated on.\n     * @return The specialized exception, presumably to be thrown by\n     *  the caller.\n     */\n    public static KeeperException create(Code code, String path) {\n        KeeperException r = create(code);\n        r.path = path;\n        return r;\n    }\n\n    /**\n     * @deprecated deprecated in 3.1.0, use {@link #create(Code, String)}\n     * instead\n     */\n    @Deprecated\n    public static KeeperException create(int code, String path) {\n        KeeperException r = create(Code.get(code));\n        r.path = path;\n        return r;\n    }\n\n    /**\n     * @deprecated deprecated in 3.1.0, use {@link #create(Code)}\n     * instead\n     */\n    @Deprecated\n    public static KeeperException create(int code) {\n        return create(Code.get(code));\n    }\n\n    /**\n     * All non-specific keeper exceptions should be constructed via\n     * this factory method in order to guarantee consistency in error\n     * codes and such.  If you know the error code, then you should\n     * construct the special purpose exception directly.  That will\n     * allow you to have the most specific possible declarations of\n     * what exceptions might actually be thrown.\n     *\n     * @param code The error code of your new exception.  This will\n     * also determine the specific type of the exception that is\n     * returned.\n     * @return The specialized exception, presumably to be thrown by\n     * the caller.\n     */\n    public static KeeperException create(Code code) {\n        switch (code) {\n            case SYSTEMERROR:\n                return new SystemErrorException();\n            case RUNTIMEINCONSISTENCY:\n                return new RuntimeInconsistencyException();\n            case DATAINCONSISTENCY:\n                return new DataInconsistencyException();\n            case CONNECTIONLOSS:\n                return new ConnectionLossException();\n            case MARSHALLINGERROR:\n                return new MarshallingErrorException();\n            case UNIMPLEMENTED:\n                return new UnimplementedException();\n            case OPERATIONTIMEOUT:\n                return new OperationTimeoutException();\n            case BADARGUMENTS:\n                return new BadArgumentsException();\n            case APIERROR:\n                return new APIErrorException();\n            case NONODE:\n                return new NoNodeException();\n            case NOAUTH:\n                return new NoAuthException();\n            case BADVERSION:\n                return new BadVersionException();\n            case NOCHILDRENFOREPHEMERALS:\n                return new NoChildrenForEphemeralsException();\n            case NODEEXISTS:\n                return new NodeExistsException();\n            case INVALIDACL:\n                return new InvalidACLException();\n            case AUTHFAILED:\n                return new AuthFailedException();\n            case NOTEMPTY:\n                return new NotEmptyException();\n            case SESSIONEXPIRED:\n                return new SessionExpiredException();\n            case INVALIDCALLBACK:\n                return new InvalidCallbackException();\n            case SESSIONMOVED:\n                return new SessionMovedException();\n            case NOTREADONLY:\n                return new NotReadOnlyException();\n\n            case OK:\n            default:\n                throw new IllegalArgumentException(\"Invalid exception code\");\n        }\n    }\n\n    /**\n     * Set the code for this exception\n     * @param code error code\n     * @deprecated deprecated in 3.1.0, exceptions should be immutable, this\n     * method should not be used\n     */\n    @Deprecated\n    public void setCode(int code) {\n        this.code = Code.get(code);\n    }\n\n    /** This interface contains the original static final int constants\n     * which have now been replaced with an enumeration in Code. Do not\n     * reference this class directly, if necessary (legacy code) continue\n     * to access the constants through Code.\n     * Note: an interface is used here due to the fact that enums cannot\n     * reference constants defined within the same enum as said constants\n     * are considered initialized _after_ the enum itself. By using an\n     * interface as a super type this allows the deprecated constants to\n     * be initialized first and referenced when constructing the enums. I\n     * didn't want to have constants declared twice. This\n     * interface should be private, but it's declared public to enable\n     * javadoc to include in the user API spec.\n     */\n    @Deprecated\n    @InterfaceAudience.Public\n    public interface CodeDeprecated {\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#OK} instead\n         */\n        @Deprecated\n        public static final int Ok = 0;\n\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#SYSTEMERROR} instead\n         */\n        @Deprecated\n        public static final int SystemError = -1;\n        /**\n         * @deprecated deprecated in 3.1.0, use\n         * {@link Code#RUNTIMEINCONSISTENCY} instead\n         */\n        @Deprecated\n        public static final int RuntimeInconsistency = -2;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#DATAINCONSISTENCY}\n         * instead\n         */\n        @Deprecated\n        public static final int DataInconsistency = -3;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#CONNECTIONLOSS}\n         * instead\n         */\n        @Deprecated\n        public static final int ConnectionLoss = -4;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#MARSHALLINGERROR}\n         * instead\n         */\n        @Deprecated\n        public static final int MarshallingError = -5;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#UNIMPLEMENTED}\n         * instead\n         */\n        @Deprecated\n        public static final int Unimplemented = -6;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#OPERATIONTIMEOUT}\n         * instead\n         */\n        @Deprecated\n        public static final int OperationTimeout = -7;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#BADARGUMENTS}\n         * instead\n         */\n        @Deprecated\n        public static final int BadArguments = -8;\n\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#APIERROR} instead\n         */\n        @Deprecated\n        public static final int APIError = -100;\n\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#NONODE} instead\n         */\n        @Deprecated\n        public static final int NoNode = -101;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#NOAUTH} instead\n         */\n        @Deprecated\n        public static final int NoAuth = -102;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#BADVERSION} instead\n         */\n        @Deprecated\n        public static final int BadVersion = -103;\n        /**\n         * @deprecated deprecated in 3.1.0, use\n         * {@link Code#NOCHILDRENFOREPHEMERALS}\n         * instead\n         */\n        @Deprecated\n        public static final int NoChildrenForEphemerals = -108;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#NODEEXISTS} instead\n         */\n        @Deprecated\n        public static final int NodeExists = -110;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#NOTEMPTY} instead\n         */\n        @Deprecated\n        public static final int NotEmpty = -111;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#SESSIONEXPIRED} instead\n         */\n        @Deprecated\n        public static final int SessionExpired = -112;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#INVALIDCALLBACK}\n         * instead\n         */\n        @Deprecated\n        public static final int InvalidCallback = -113;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#INVALIDACL} instead\n         */\n        @Deprecated\n        public static final int InvalidACL = -114;\n        /**\n         * @deprecated deprecated in 3.1.0, use {@link Code#AUTHFAILED} instead\n         */\n        @Deprecated\n        public static final int AuthFailed = -115;\n        /**\n         * This value will be used directly in {@link CODE#SESSIONMOVED}\n         */\n        // public static final int SessionMoved = -118;\n    }\n\n    /** Codes which represent the various KeeperException\n     * types. This enum replaces the deprecated earlier static final int\n     * constants. The old, deprecated, values are in \"camel case\" while the new\n     * enum values are in all CAPS.\n     */\n    @InterfaceAudience.Public\n    public static enum Code implements CodeDeprecated {\n        /** Everything is OK */\n        OK (Ok),\n\n        /** System and server-side errors.\n         * This is never thrown by the server, it shouldn't be used other than\n         * to indicate a range. Specifically error codes greater than this\n         * value, but lesser than {@link #APIERROR}, are system errors.\n         */\n        SYSTEMERROR (SystemError),\n\n        /** A runtime inconsistency was found */\n        RUNTIMEINCONSISTENCY (RuntimeInconsistency),\n        /** A data inconsistency was found */\n        DATAINCONSISTENCY (DataInconsistency),\n        /** Connection to the server has been lost */\n        CONNECTIONLOSS (ConnectionLoss),\n        /** Error while marshalling or unmarshalling data */\n        MARSHALLINGERROR (MarshallingError),\n        /** Operation is unimplemented */\n        UNIMPLEMENTED (Unimplemented),\n        /** Operation timeout */\n        OPERATIONTIMEOUT (OperationTimeout),\n        /** Invalid arguments */\n        BADARGUMENTS (BadArguments),\n        \n        /** API errors.\n         * This is never thrown by the server, it shouldn't be used other than\n         * to indicate a range. Specifically error codes greater than this\n         * value are API errors (while values less than this indicate a\n         * {@link #SYSTEMERROR}).\n         */\n        APIERROR (APIError),\n\n        /** Node does not exist */\n        NONODE (NoNode),\n        /** Not authenticated */\n        NOAUTH (NoAuth),\n        /** Version conflict */\n        BADVERSION (BadVersion),\n        /** Ephemeral nodes may not have children */\n        NOCHILDRENFOREPHEMERALS (NoChildrenForEphemerals),\n        /** The node already exists */\n        NODEEXISTS (NodeExists),\n        /** The node has children */\n        NOTEMPTY (NotEmpty),\n        /** The session has been expired by the server */\n        SESSIONEXPIRED (SessionExpired),\n        /** Invalid callback specified */\n        INVALIDCALLBACK (InvalidCallback),\n        /** Invalid ACL specified */\n        INVALIDACL (InvalidACL),\n        /** Client authentication failed */\n        AUTHFAILED (AuthFailed),\n        /** Session moved to another server, so operation is ignored */\n        SESSIONMOVED (-118),\n        /** State-changing request is passed to read-only server */\n        NOTREADONLY (-119);\n\n        private static final Map<Integer,Code> lookup\n            = new HashMap<Integer,Code>();\n\n        static {\n            for(Code c : EnumSet.allOf(Code.class))\n                lookup.put(c.code, c);\n        }\n\n        private final int code;\n        Code(int code) {\n            this.code = code;\n        }\n\n        /**\n         * Get the int value for a particular Code.\n         * @return error code as integer\n         */\n        public int intValue() { return code; }\n\n        /**\n         * Get the Code value for a particular integer error code\n         * @param code int error code\n         * @return Code value corresponding to specified int code, or null\n         */\n        public static Code get(int code) {\n            return lookup.get(code);\n        }\n    }\n\n    static String getCodeMessage(Code code) {\n        switch (code) {\n            case OK:\n                return \"ok\";\n            case SYSTEMERROR:\n                return \"SystemError\";\n            case RUNTIMEINCONSISTENCY:\n                return \"RuntimeInconsistency\";\n            case DATAINCONSISTENCY:\n                return \"DataInconsistency\";\n            case CONNECTIONLOSS:\n                return \"ConnectionLoss\";\n            case MARSHALLINGERROR:\n                return \"MarshallingError\";\n            case UNIMPLEMENTED:\n                return \"Unimplemented\";\n            case OPERATIONTIMEOUT:\n                return \"OperationTimeout\";\n            case BADARGUMENTS:\n                return \"BadArguments\";\n            case APIERROR:\n                return \"APIError\";\n            case NONODE:\n                return \"NoNode\";\n            case NOAUTH:\n                return \"NoAuth\";\n            case BADVERSION:\n                return \"BadVersion\";\n            case NOCHILDRENFOREPHEMERALS:\n                return \"NoChildrenForEphemerals\";\n            case NODEEXISTS:\n                return \"NodeExists\";\n            case INVALIDACL:\n                return \"InvalidACL\";\n            case AUTHFAILED:\n                return \"AuthFailed\";\n            case NOTEMPTY:\n                return \"Directory not empty\";\n            case SESSIONEXPIRED:\n                return \"Session expired\";\n            case INVALIDCALLBACK:\n                return \"Invalid callback\";\n            case SESSIONMOVED:\n                return \"Session moved\";\n            case NOTREADONLY:\n                return \"Not a read-only call\";\n            default:\n                return \"Unknown error \" + code;\n        }\n    }\n\n    private Code code;\n\n    private String path;\n\n    public KeeperException(Code code) {\n        this.code = code;\n    }\n\n    KeeperException(Code code, String path) {\n        this.code = code;\n        this.path = path;\n    }\n\n    /**\n     * Read the error code for this exception\n     * @return the error code for this exception\n     * @deprecated deprecated in 3.1.0, use {@link #code()} instead\n     */\n    @Deprecated\n    public int getCode() {\n        return code.code;\n    }\n\n    /**\n     * Read the error Code for this exception\n     * @return the error Code for this exception\n     */\n    public Code code() {\n        return code;\n    }\n\n    /**\n     * Read the path for this exception\n     * @return the path associated with this error, null if none\n     */\n    public String getPath() {\n        return path;\n    }\n\n    @Override\n    public String getMessage() {\n        if (path == null) {\n            return \"KeeperErrorCode = \" + getCodeMessage(code);\n        }\n        return \"KeeperErrorCode = \" + getCodeMessage(code) + \" for \" + path;\n    }\n\n    void setMultiResults(List<OpResult> results) {\n        this.results = results;\n    }\n\n    /**\n     * If this exception was thrown by a multi-request then the (partial) results\n     * and error codes can be retrieved using this getter.\n     * @return A copy of the list of results from the operations in the multi-request.\n     *\n     * @since 3.4.0\n     *\n     */\n    public List<OpResult> getResults() {\n        return results != null ? new ArrayList<OpResult>(results) : null;\n    }\n\n    /**\n     *  @see Code#APIERROR\n     */\n    @InterfaceAudience.Public\n    public static class APIErrorException extends KeeperException {\n        public APIErrorException() {\n            super(Code.APIERROR);\n        }\n    }\n\n    /**\n     *  @see Code#AUTHFAILED\n     */\n    @InterfaceAudience.Public\n    public static class AuthFailedException extends KeeperException {\n        public AuthFailedException() {\n            super(Code.AUTHFAILED);\n        }\n    }\n\n    /**\n     *  @see Code#BADARGUMENTS\n     */\n    @InterfaceAudience.Public\n    public static class BadArgumentsException extends KeeperException {\n        public BadArgumentsException() {\n            super(Code.BADARGUMENTS);\n        }\n        public BadArgumentsException(String path) {\n            super(Code.BADARGUMENTS, path);\n        }\n    }\n\n    /**\n     * @see Code#BADVERSION\n     */\n    @InterfaceAudience.Public\n    public static class BadVersionException extends KeeperException {\n        public BadVersionException() {\n            super(Code.BADVERSION);\n        }\n        public BadVersionException(String path) {\n            super(Code.BADVERSION, path);\n        }\n    }\n\n    /**\n     * @see Code#CONNECTIONLOSS\n     */\n    @InterfaceAudience.Public\n    public static class ConnectionLossException extends KeeperException {\n        public ConnectionLossException() {\n            super(Code.CONNECTIONLOSS);\n        }\n    }\n\n    /**\n     * @see Code#DATAINCONSISTENCY\n     */\n    @InterfaceAudience.Public\n    public static class DataInconsistencyException extends KeeperException {\n        public DataInconsistencyException() {\n            super(Code.DATAINCONSISTENCY);\n        }\n    }\n\n    /**\n     * @see Code#INVALIDACL\n     */\n    @InterfaceAudience.Public\n    public static class InvalidACLException extends KeeperException {\n        public InvalidACLException() {\n            super(Code.INVALIDACL);\n        }\n        public InvalidACLException(String path) {\n            super(Code.INVALIDACL, path);\n        }\n    }\n\n    /**\n     * @see Code#INVALIDCALLBACK\n     */\n    @InterfaceAudience.Public\n    public static class InvalidCallbackException extends KeeperException {\n        public InvalidCallbackException() {\n            super(Code.INVALIDCALLBACK);\n        }\n    }\n\n    /**\n     * @see Code#MARSHALLINGERROR\n     */\n    @InterfaceAudience.Public\n    public static class MarshallingErrorException extends KeeperException {\n        public MarshallingErrorException() {\n            super(Code.MARSHALLINGERROR);\n        }\n    }\n\n    /**\n     * @see Code#NOAUTH\n     */\n    @InterfaceAudience.Public\n    public static class NoAuthException extends KeeperException {\n        public NoAuthException() {\n            super(Code.NOAUTH);\n        }\n    }\n\n    /**\n     * @see Code#NOCHILDRENFOREPHEMERALS\n     */\n    @InterfaceAudience.Public\n    public static class NoChildrenForEphemeralsException extends KeeperException {\n        public NoChildrenForEphemeralsException() {\n            super(Code.NOCHILDRENFOREPHEMERALS);\n        }\n        public NoChildrenForEphemeralsException(String path) {\n            super(Code.NOCHILDRENFOREPHEMERALS, path);\n        }\n    }\n\n    /**\n     * @see Code#NODEEXISTS\n     */\n    @InterfaceAudience.Public\n    public static class NodeExistsException extends KeeperException {\n        public NodeExistsException() {\n            super(Code.NODEEXISTS);\n        }\n        public NodeExistsException(String path) {\n            super(Code.NODEEXISTS, path);\n        }\n    }\n\n    /**\n     * @see Code#NONODE\n     */\n    @InterfaceAudience.Public\n    public static class NoNodeException extends KeeperException {\n        public NoNodeException() {\n            super(Code.NONODE);\n        }\n        public NoNodeException(String path) {\n            super(Code.NONODE, path);\n        }\n    }\n\n    /**\n     * @see Code#NOTEMPTY\n     */\n    @InterfaceAudience.Public\n    public static class NotEmptyException extends KeeperException {\n        public NotEmptyException() {\n            super(Code.NOTEMPTY);\n        }\n        public NotEmptyException(String path) {\n            super(Code.NOTEMPTY, path);\n        }\n    }\n\n    /**\n     * @see Code#OPERATIONTIMEOUT\n     */\n    @InterfaceAudience.Public\n    public static class OperationTimeoutException extends KeeperException {\n        public OperationTimeoutException() {\n            super(Code.OPERATIONTIMEOUT);\n        }\n    }\n\n    /**\n     * @see Code#RUNTIMEINCONSISTENCY\n     */\n    @InterfaceAudience.Public\n    public static class RuntimeInconsistencyException extends KeeperException {\n        public RuntimeInconsistencyException() {\n            super(Code.RUNTIMEINCONSISTENCY);\n        }\n    }\n\n    /**\n     * @see Code#SESSIONEXPIRED\n     */\n    @InterfaceAudience.Public\n    public static class SessionExpiredException extends KeeperException {\n        public SessionExpiredException() {\n            super(Code.SESSIONEXPIRED);\n        }\n    }\n\n    /**\n     * @see Code#SESSIONMOVED\n     */\n    @InterfaceAudience.Public\n    public static class SessionMovedException extends KeeperException {\n        public SessionMovedException() {\n            super(Code.SESSIONMOVED);\n        }\n    }\n\n    /**\n     * @see Code#NOTREADONLY\n     */\n    @InterfaceAudience.Public\n    public static class NotReadOnlyException extends KeeperException {\n        public NotReadOnlyException() {\n            super(Code.NOTREADONLY);\n        }\n    }\n\n    /**\n     * @see Code#SYSTEMERROR\n     */\n    @InterfaceAudience.Public\n    public static class SystemErrorException extends KeeperException {\n        public SystemErrorException() {\n            super(Code.SYSTEMERROR);\n        }\n    }\n\n    /**\n     * @see Code#UNIMPLEMENTED\n     */\n    @InterfaceAudience.Public\n    public static class UnimplementedException extends KeeperException {\n        public UnimplementedException() {\n            super(Code.UNIMPLEMENTED);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Login.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\n/** \n * This class is responsible for refreshing Kerberos credentials for\n * logins for both Zookeeper client and server.\n * See ZooKeeperSaslServer for server-side usage.\n * See ZooKeeperSaslClient for client-side usage.\n */\n\nimport javax.security.auth.kerberos.KerberosPrincipal;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginContext;\nimport javax.security.auth.login.LoginException;\nimport javax.security.auth.callback.CallbackHandler;\n\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport javax.security.auth.kerberos.KerberosTicket;\nimport javax.security.auth.Subject;\nimport java.util.Date;\nimport java.util.Random;\nimport java.util.Set;\n\npublic class Login {\n    private static final Logger LOG = LoggerFactory.getLogger(Login.class);\n    public CallbackHandler callbackHandler;\n\n    // LoginThread will sleep until 80% of time from last refresh to\n    // ticket's expiry has been reached, at which time it will wake\n    // and try to renew the ticket.\n    private static final float TICKET_RENEW_WINDOW = 0.80f;\n\n    /**\n     * Percentage of random jitter added to the renewal time\n     */\n    private static final float TICKET_RENEW_JITTER = 0.05f;\n\n    // Regardless of TICKET_RENEW_WINDOW setting above and the ticket expiry time,\n    // thread will not sleep between refresh attempts any less than 1 minute (60*1000 milliseconds = 1 minute).\n    // Change the '1' to e.g. 5, to change this to 5 minutes.\n    private static final long MIN_TIME_BEFORE_RELOGIN = 1 * 60 * 1000L;\n\n    private Subject subject = null;\n    private Thread t = null;\n    private boolean isKrbTicket = false;\n    private boolean isUsingTicketCache = false;\n    private boolean isUsingKeytab = false;\n\n    /** Random number generator */\n    private static Random rng = new Random();\n\n    private LoginContext login = null;\n    private String loginContextName = null;\n    private String keytabFile = null;\n    private String principal = null;\n\n    // Initialize 'lastLogin' to do a login at first time\n    private long lastLogin = Time.currentElapsedTime() - MIN_TIME_BEFORE_RELOGIN;\n\n    /**\n     * LoginThread constructor. The constructor starts the thread used\n     * to periodically re-login to the Kerberos Ticket Granting Server.\n     * @param loginContextName\n     *               name of section in JAAS file that will be use to login.\n     *               Passed as first param to javax.security.auth.login.LoginContext().\n     *\n     * @param callbackHandler\n     *               Passed as second param to javax.security.auth.login.LoginContext().\n     * @throws javax.security.auth.login.LoginException\n     *               Thrown if authentication fails.\n     */\n    public Login(final String loginContextName, CallbackHandler callbackHandler)\n            throws LoginException {\n        this.callbackHandler = callbackHandler;\n        login = login(loginContextName);\n        this.loginContextName = loginContextName;\n        subject = login.getSubject();\n        isKrbTicket = !subject.getPrivateCredentials(KerberosTicket.class).isEmpty();\n        AppConfigurationEntry entries[] = Configuration.getConfiguration().getAppConfigurationEntry(loginContextName);\n        for (AppConfigurationEntry entry: entries) {\n            // there will only be a single entry, so this for() loop will only be iterated through once.\n            if (entry.getOptions().get(\"useTicketCache\") != null) {\n                String val = (String)entry.getOptions().get(\"useTicketCache\");\n                if (val.equals(\"true\")) {\n                    isUsingTicketCache = true;\n                }\n            }\n            if (entry.getOptions().get(\"keyTab\") != null) {\n                keytabFile = (String)entry.getOptions().get(\"keyTab\");\n                isUsingKeytab = true;\n            }\n            if (entry.getOptions().get(\"principal\") != null) {\n                principal = (String)entry.getOptions().get(\"principal\");\n            }\n            break;\n        }\n\n        if (!isKrbTicket) {\n            // if no TGT, do not bother with ticket management.\n            return;\n        }\n\n        // Refresh the Ticket Granting Ticket (TGT) periodically. How often to refresh is determined by the\n        // TGT's existing expiry date and the configured MIN_TIME_BEFORE_RELOGIN. For testing and development,\n        // you can decrease the interval of expiration of tickets (for example, to 3 minutes) by running :\n        //  \"modprinc -maxlife 3mins <principal>\" in kadmin.\n        t = new Thread(new Runnable() {\n            public void run() {\n                LOG.info(\"TGT refresh thread started.\");\n                while (true) {  // renewal thread's main loop. if it exits from here, thread will exit.\n                    KerberosTicket tgt = getTGT();\n                    long now = Time.currentWallTime();\n                    long nextRefresh;\n                    Date nextRefreshDate;\n                    if (tgt == null) {\n                        nextRefresh = now + MIN_TIME_BEFORE_RELOGIN;\n                        nextRefreshDate = new Date(nextRefresh);\n                        LOG.warn(\"No TGT found: will try again at \" + nextRefreshDate);\n                    } else {\n                        nextRefresh = getRefreshTime(tgt);\n                        long expiry = tgt.getEndTime().getTime();\n                        Date expiryDate = new Date(expiry);\n                        if ((isUsingTicketCache) && (tgt.getEndTime().equals(tgt.getRenewTill()))) {\n                            LOG.error(\"The TGT cannot be renewed beyond the next expiry date: \" + expiryDate + \".\" +\n                                    \"This process will not be able to authenticate new SASL connections after that \" +\n                                    \"time (for example, it will not be authenticate a new connection with a Zookeeper \" +\n                                    \"Quorum member).  Ask your system administrator to either increase the \" +\n                                    \"'renew until' time by doing : 'modprinc -maxrenewlife \" + principal + \"' within \" +\n                                    \"kadmin, or instead, to generate a keytab for \" + principal + \". Because the TGT's \" +\n                                    \"expiry cannot be further extended by refreshing, exiting refresh thread now.\");\n                            return;\n                        }\n                        // determine how long to sleep from looking at ticket's expiry.\n                        // We should not allow the ticket to expire, but we should take into consideration\n                        // MIN_TIME_BEFORE_RELOGIN. Will not sleep less than MIN_TIME_BEFORE_RELOGIN, unless doing so\n                        // would cause ticket expiration.\n                        if ((nextRefresh > expiry) ||\n                                ((now + MIN_TIME_BEFORE_RELOGIN) > expiry)) {\n                            // expiry is before next scheduled refresh).\n                            nextRefresh = now;\n                        } else {\n                            if (nextRefresh < (now + MIN_TIME_BEFORE_RELOGIN)) {\n                                // next scheduled refresh is sooner than (now + MIN_TIME_BEFORE_LOGIN).\n                                Date until = new Date(nextRefresh);\n                                Date newuntil = new Date(now + MIN_TIME_BEFORE_RELOGIN);\n                                LOG.warn(\"TGT refresh thread time adjusted from : \" + until + \" to : \" + newuntil + \" since \"\n                                        + \"the former is sooner than the minimum refresh interval (\"\n                                        + MIN_TIME_BEFORE_RELOGIN / 1000 + \" seconds) from now.\");\n                            }\n                            nextRefresh = Math.max(nextRefresh, now + MIN_TIME_BEFORE_RELOGIN);\n                        }\n                        nextRefreshDate = new Date(nextRefresh);\n                        if (nextRefresh > expiry) {\n                            LOG.error(\"next refresh: \" + nextRefreshDate + \" is later than expiry \" + expiryDate\n                                    + \". This may indicate a clock skew problem. Check that this host and the KDC's \"\n                                    + \"hosts' clocks are in sync. Exiting refresh thread.\");\n                            return;\n                        }\n                    }\n                    if (now == nextRefresh) {\n                        LOG.info(\"refreshing now because expiry is before next scheduled refresh time.\");\n                    } else if (now < nextRefresh) {\n                        Date until = new Date(nextRefresh);\n                        LOG.info(\"TGT refresh sleeping until: \" + until.toString());\n                        try {\n                            Thread.sleep(nextRefresh - now);\n                        } catch (InterruptedException ie) {\n                            LOG.warn(\"TGT renewal thread has been interrupted and will exit.\");\n                            break;\n                        }\n                    }\n                    else {\n                        LOG.error(\"nextRefresh:\" + nextRefreshDate + \" is in the past: exiting refresh thread. Check\"\n                                + \" clock sync between this host and KDC - (KDC's clock is likely ahead of this host).\"\n                                + \" Manual intervention will be required for this client to successfully authenticate.\"\n                                + \" Exiting refresh thread.\");\n                        break;\n                    }\n                    if (isUsingTicketCache) {\n                        String cmd = \"/usr/bin/kinit\";\n                        if (System.getProperty(\"zookeeper.kinit\") != null) {\n                            cmd = System.getProperty(\"zookeeper.kinit\");\n                        }\n                        String kinitArgs = \"-R\";\n                        int retry = 1;\n                        while (retry >= 0) {\n                            try {\n                                LOG.debug(\"running ticket cache refresh command: \" + cmd + \" \" + kinitArgs);\n                                Shell.execCommand(cmd, kinitArgs);\n                                break;\n                            } catch (Exception e) {\n                                if (retry > 0) {\n                                    --retry;\n                                    // sleep for 10 seconds\n                                    try {\n                                        Thread.sleep(10 * 1000);\n                                    } catch (InterruptedException ie) {\n                                        LOG.error(\"Interrupted while renewing TGT, exiting Login thread\");\n                                        return;\n                                    }\n                                } else {\n                                    LOG.warn(\"Could not renew TGT due to problem running shell command: '\" + cmd\n                                            + \" \" + kinitArgs + \"'\" + \"; exception was:\" + e + \". Exiting refresh thread.\",e);\n                                    return;\n                                }\n                            }\n                        }\n                    }\n                    try {\n                        int retry = 1;\n                        while (retry >= 0) {\n                            try {\n                                reLogin();\n                                break;\n                            } catch (LoginException le) {\n                                if (retry > 0) {\n                                    --retry;\n                                    // sleep for 10 seconds.\n                                    try {\n                                        Thread.sleep(10 * 1000);\n                                    } catch (InterruptedException e) {\n                                        LOG.error(\"Interrupted during login retry after LoginException:\", le);\n                                        throw le;\n                                    }\n                                } else {\n                                    LOG.error(\"Could not refresh TGT for principal: \" + principal + \".\", le);\n                                }\n                            }\n                        }\n                    } catch (LoginException le) {\n                        LOG.error(\"Failed to refresh TGT: refresh thread exiting now.\",le);\n                        break;\n                    }\n                }\n            }\n        });\n        t.setDaemon(true);\n    }\n\n    public void startThreadIfNeeded() {\n        // thread object 't' will be null if a refresh thread is not needed.\n        if (t != null) {\n            t.start();\n        }\n    }\n\n    public void shutdown() {\n        if ((t != null) && (t.isAlive())) {\n            t.interrupt();\n            try {\n                t.join();\n            } catch (InterruptedException e) {\n                LOG.warn(\"error while waiting for Login thread to shutdown: \" + e);\n            }\n        }\n    }\n\n    public Subject getSubject() {\n        return subject;\n    }\n\n    public String getLoginContextName() {\n        return loginContextName;\n    }\n\n    private synchronized LoginContext login(final String loginContextName) throws LoginException {\n        if (loginContextName == null) {\n            throw new LoginException(\"loginContext name (JAAS file section header) was null. \" +\n                    \"Please check your java.security.login.auth.config (=\" +\n                    System.getProperty(\"java.security.login.auth.config\") +\n                    \") and your \" + ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY + \"(=\" + \n                    System.getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"Client\") + \")\");\n        }\n        LoginContext loginContext = new LoginContext(loginContextName,callbackHandler);\n        loginContext.login();\n        LOG.info(\"{} successfully logged in.\", loginContextName);\n        return loginContext;\n    }\n\n    // c.f. org.apache.hadoop.security.UserGroupInformation.\n    private long getRefreshTime(KerberosTicket tgt) {\n        long start = tgt.getStartTime().getTime();\n        long expires = tgt.getEndTime().getTime();\n        LOG.info(\"TGT valid starting at:        \" + tgt.getStartTime().toString());\n        LOG.info(\"TGT expires:                  \" + tgt.getEndTime().toString());\n        long proposedRefresh = start + (long) ((expires - start) *\n                (TICKET_RENEW_WINDOW + (TICKET_RENEW_JITTER * rng.nextDouble())));\n        if (proposedRefresh > expires) {\n            // proposedRefresh is too far in the future: it's after ticket expires: simply return now.\n            return Time.currentWallTime();\n        }\n        else {\n            return proposedRefresh;\n        }\n    }\n\n    private synchronized KerberosTicket getTGT() {\n        Set<KerberosTicket> tickets = subject.getPrivateCredentials(KerberosTicket.class);\n        for(KerberosTicket ticket: tickets) {\n            KerberosPrincipal server = ticket.getServer();\n            if (server.getName().equals(\"krbtgt/\" + server.getRealm() + \"@\" + server.getRealm())) {\n                LOG.debug(\"Client principal is \\\"\" + ticket.getClient().getName() + \"\\\".\");\n                LOG.debug(\"Server principal is \\\"\" + ticket.getServer().getName() + \"\\\".\");\n                return ticket;\n            }\n        }\n        return null;\n    }\n\n    private boolean hasSufficientTimeElapsed() {\n        long now = Time.currentElapsedTime();\n        if (now - getLastLogin() < MIN_TIME_BEFORE_RELOGIN ) {\n            LOG.warn(\"Not attempting to re-login since the last re-login was \" +\n                    \"attempted less than \" + (MIN_TIME_BEFORE_RELOGIN/1000) + \" seconds\"+\n                    \" before.\");\n            return false;\n        }\n        // register most recent relogin attempt\n        setLastLogin(now);\n        return true;\n    }\n\n    /**\n     * Returns login object\n     * @return login\n     */\n    private LoginContext getLogin() {\n        return login;\n    }\n\n    /**\n     * Set the login object\n     * @param login\n     */\n    private void setLogin(LoginContext login) {\n        this.login = login;\n    }\n\n    /**\n     * Set the last login time.\n     * @param time the number of milliseconds since the beginning of time\n     */\n    private void setLastLogin(long time) {\n        lastLogin = time;\n    }\n\n    /**\n     * Get the time of the last login.\n     * @return the number of milliseconds since the beginning of time.\n     */\n    private long getLastLogin() {\n        return lastLogin;\n    }\n\n    /**\n     * Re-login a principal. This method assumes that {@link #login(String)} has happened already.\n     * @throws javax.security.auth.login.LoginException on a failure\n     */\n    // c.f. HADOOP-6559\n    private synchronized void reLogin()\n            throws LoginException {\n        if (!isKrbTicket) {\n            return;\n        }\n        LoginContext login = getLogin();\n        if (login  == null) {\n            throw new LoginException(\"login must be done first\");\n        }\n        if (!hasSufficientTimeElapsed()) {\n            return;\n        }\n        LOG.info(\"Initiating logout for \" + principal);\n        synchronized (Login.class) {\n            //clear up the kerberos state. But the tokens are not cleared! As per\n            //the Java kerberos login module code, only the kerberos credentials\n            //are cleared\n            login.logout();\n            //login and also update the subject field of this instance to\n            //have the new credentials (pass it to the LoginContext constructor)\n            login = new LoginContext(loginContextName, getSubject());\n            LOG.info(\"Initiating re-login for \" + principal);\n            login.login();\n            setLogin(login);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/MultiResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.proto.CreateResponse;\nimport org.apache.zookeeper.proto.MultiHeader;\nimport org.apache.zookeeper.proto.SetDataResponse;\nimport org.apache.zookeeper.proto.ErrorResponse;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Handles the response from a multi request.  Such a response consists of\n * a sequence of responses each prefixed by a MultiResponse that indicates\n * the type of the response.  The end of the list is indicated by a MultiHeader\n * with a negative type.  Each individual response is in the same format as\n * with the corresponding operation in the original request list.\n */\npublic class MultiResponse implements Record, Iterable<OpResult> {\n    private List<OpResult> results = new ArrayList<OpResult>();\n\n    public void add(OpResult x) {\n        results.add(x);\n    }\n\n    @Override\n    public Iterator<OpResult> iterator() {\n        return results.iterator();\n    }\n\n    public int size() {\n        return results.size();\n    }\n\n    @Override\n    public void serialize(OutputArchive archive, String tag) throws IOException {\n        archive.startRecord(this, tag);\n\n        int index = 0;\n        for (OpResult result : results) {\n            int err = result.getType() == ZooDefs.OpCode.error ? ((OpResult.ErrorResult)result).getErr() : 0;\n\n            new MultiHeader(result.getType(), false, err).serialize(archive, tag);\n\n            switch (result.getType()) {\n                case ZooDefs.OpCode.create:\n                    new CreateResponse(((OpResult.CreateResult) result).getPath()).serialize(archive, tag);\n                    break;\n                case ZooDefs.OpCode.delete:\n                case ZooDefs.OpCode.check:\n                    break;\n                case ZooDefs.OpCode.setData:\n                    new SetDataResponse(((OpResult.SetDataResult) result).getStat()).serialize(archive, tag);\n                    break;\n                case ZooDefs.OpCode.error:\n                    new ErrorResponse(((OpResult.ErrorResult) result).getErr()).serialize(archive, tag);\n                    break;\n                default:\n                    throw new IOException(\"Invalid type \" + result.getType() + \" in MultiResponse\");\n            }\n        }\n        new MultiHeader(-1, true, -1).serialize(archive, tag);\n        archive.endRecord(this, tag);\n    }\n\n    @Override\n    public void deserialize(InputArchive archive, String tag) throws IOException {\n        results = new ArrayList<OpResult>();\n\n        archive.startRecord(tag);\n        MultiHeader h = new MultiHeader();\n        h.deserialize(archive, tag);\n        while (!h.getDone()) {\n            switch (h.getType()) {\n                case ZooDefs.OpCode.create:\n                    CreateResponse cr = new CreateResponse();\n                    cr.deserialize(archive, tag);\n                    results.add(new OpResult.CreateResult(cr.getPath()));\n                    break;\n\n                case ZooDefs.OpCode.delete:\n                    results.add(new OpResult.DeleteResult());\n                    break;\n\n                case ZooDefs.OpCode.setData:\n                    SetDataResponse sdr = new SetDataResponse();\n                    sdr.deserialize(archive, tag);\n                    results.add(new OpResult.SetDataResult(sdr.getStat()));\n                    break;\n\n                case ZooDefs.OpCode.check:\n                    results.add(new OpResult.CheckResult());\n                    break;\n\n                case ZooDefs.OpCode.error:\n                    //FIXME: need way to more cleanly serialize/deserialize exceptions\n                    ErrorResponse er = new ErrorResponse();\n                    er.deserialize(archive, tag);\n                    results.add(new OpResult.ErrorResult(er.getErr()));\n                    break;\n\n                default:\n                    throw new IOException(\"Invalid type \" + h.getType() + \" in MultiResponse\");\n            }\n            h.deserialize(archive, tag);\n        }\n        archive.endRecord(tag);\n    }\n\n    public List<OpResult> getResultList() {\n        return results;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof MultiResponse)) return false;\n\n        MultiResponse other = (MultiResponse) o;\n\n        if (results != null) {\n            Iterator<OpResult> i = other.results.iterator();\n            for (OpResult result : results) {\n                if (i.hasNext()) {\n                    if (!result.equals(i.next())) {\n                        return false;\n                    }\n                } else {\n                    return false;\n                }\n            }\n            return !i.hasNext();\n        }\n        else return other.results == null;\n    }\n\n    @Override\n    public int hashCode() {\n        int hash = results.size();\n        for (OpResult result : results) {\n            hash = (hash * 35) + result.hashCode();\n        }\n        return hash;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/MultiTransactionRecord.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.proto.*;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Encodes a composite transaction.  In the wire format, each transaction\n * consists of a single MultiHeader followed by the appropriate request.\n * Each of these MultiHeaders has a type which indicates\n * the type of the following transaction or a negative number if no more transactions\n * are included.\n */\npublic class MultiTransactionRecord implements Record, Iterable<Op> {\n    private List<Op> ops = new ArrayList<Op>();\n\n    public MultiTransactionRecord() {\n    }\n\n    public MultiTransactionRecord(Iterable<Op> ops) {\n        for (Op op : ops) {\n            add(op);\n        }\n    }\n\n    @Override\n    public Iterator<Op> iterator() {\n        return ops.iterator() ;\n    }\n\n    public void add(Op op) {\n        ops.add(op);\n    }\n\n    public int size() {\n        return ops.size();\n    }\n\n    @Override\n    public void serialize(OutputArchive archive, String tag) throws IOException {\n        archive.startRecord(this, tag);\n        int index = 0 ;\n        for (Op op : ops) {\n            MultiHeader h = new MultiHeader(op.getType(), false, -1);\n            h.serialize(archive, tag);\n            switch (op.getType()) {\n               case ZooDefs.OpCode.create:\n                    op.toRequestRecord().serialize(archive, tag);\n                    break;\n                case ZooDefs.OpCode.delete:\n                    op.toRequestRecord().serialize(archive, tag);\n                    break;\n                case ZooDefs.OpCode.setData:\n                    op.toRequestRecord().serialize(archive, tag);\n                    break;\n                case ZooDefs.OpCode.check:\n                    op.toRequestRecord().serialize(archive, tag);\n                    break;\n                default:\n                    throw new IOException(\"Invalid type of op\");\n            }\n        }\n        new MultiHeader(-1, true, -1).serialize(archive, tag);\n        archive.endRecord(this, tag);\n    }\n\n    @Override\n    public void deserialize(InputArchive archive, String tag) throws IOException {\n        archive.startRecord(tag);\n        MultiHeader h = new MultiHeader();\n        h.deserialize(archive, tag);\n\n        while (!h.getDone()) {\n            switch (h.getType()) {\n               case ZooDefs.OpCode.create:\n                    CreateRequest cr = new CreateRequest();\n                    cr.deserialize(archive, tag);\n                    add(Op.create(cr.getPath(), cr.getData(), cr.getAcl(), cr.getFlags()));\n                    break;\n                case ZooDefs.OpCode.delete:\n                    DeleteRequest dr = new DeleteRequest();\n                    dr.deserialize(archive, tag);\n                    add(Op.delete(dr.getPath(), dr.getVersion()));\n                    break;\n                case ZooDefs.OpCode.setData:\n                    SetDataRequest sdr = new SetDataRequest();\n                    sdr.deserialize(archive, tag);\n                    add(Op.setData(sdr.getPath(), sdr.getData(), sdr.getVersion()));\n                    break;\n                case ZooDefs.OpCode.check:\n                    CheckVersionRequest cvr = new CheckVersionRequest();\n                    cvr.deserialize(archive, tag);\n                    add(Op.check(cvr.getPath(), cvr.getVersion()));\n                    break;\n                default:\n                    throw new IOException(\"Invalid type of op\");\n            }\n            h.deserialize(archive, tag);\n        }\n        archive.endRecord(tag);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof MultiTransactionRecord)) return false;\n\n        MultiTransactionRecord that = (MultiTransactionRecord) o;\n\n        if (ops != null) {\n            Iterator<Op> other = that.ops.iterator();\n            for (Op op : ops) {\n                boolean hasMoreData = other.hasNext();\n                if (!hasMoreData) {\n                    return false;\n                }\n                Op otherOp = other.next();\n                if (!op.equals(otherOp)) {\n                    return false;\n                }\n            }\n            return !other.hasNext();\n        } else {\n            return that.ops == null;\n        }\n\n    }\n\n    @Override\n    public int hashCode() {\n        int h = 1023;\n        for (Op op : ops) {\n            h = h * 25 + op.hashCode();\n        }\n        return h;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Op.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.common.PathUtils;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.proto.CheckVersionRequest;\nimport org.apache.zookeeper.proto.CreateRequest;\nimport org.apache.zookeeper.proto.DeleteRequest;\nimport org.apache.zookeeper.proto.SetDataRequest;\n\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Represents a single operation in a multi-operation transaction.  Each operation can be a create, update\n * or delete or can just be a version check.\n *\n * Sub-classes of Op each represent each detailed type but should not normally be referenced except via\n * the provided factory methods.\n *\n * @see ZooKeeper#create(String, byte[], java.util.List, CreateMode)\n * @see ZooKeeper#create(String, byte[], java.util.List, CreateMode, org.apache.zookeeper.AsyncCallback.StringCallback, Object)\n * @see ZooKeeper#delete(String, int)\n * @see ZooKeeper#setData(String, byte[], int)\n */\npublic abstract class Op {\n    private int type;\n    private String path;\n\n    // prevent untyped construction\n    private Op(int type, String path) {\n        this.type = type;\n        this.path = path;\n    }\n\n    /**\n     * Constructs a create operation.  Arguments are as for the ZooKeeper method of the same name.\n     * @see ZooKeeper#create(String, byte[], java.util.List, CreateMode)\n     * @see CreateMode#fromFlag(int)\n     *\n     * @param path\n     *                the path for the node\n     * @param data\n     *                the initial data for the node\n     * @param acl\n     *                the acl for the node\n     * @param flags\n     *                specifying whether the node to be created is ephemeral\n     *                and/or sequential but using the integer encoding.\n     */\n    public static Op create(String path, byte[] data, List<ACL> acl, int flags) {\n        return new Create(path, data, acl, flags);\n    }\n\n    /**\n     * Constructs a create operation.  Arguments are as for the ZooKeeper method of the same name.\n     * @see ZooKeeper#create(String, byte[], java.util.List, CreateMode)\n     *\n     * @param path\n     *                the path for the node\n     * @param data\n     *                the initial data for the node\n     * @param acl\n     *                the acl for the node\n     * @param createMode\n     *                specifying whether the node to be created is ephemeral\n     *                and/or sequential\n     */\n    public static Op create(String path, byte[] data, List<ACL> acl, CreateMode createMode) {\n        return new Create(path, data, acl, createMode);\n    }\n\n    /**\n     * Constructs a delete operation.  Arguments are as for the ZooKeeper method of the same name.\n     * @see ZooKeeper#delete(String, int)\n     *\n     * @param path\n     *                the path of the node to be deleted.\n     * @param version\n     *                the expected node version.\n     */\n    public static Op delete(String path, int version) {\n        return new Delete(path, version);\n    }\n\n    /**\n     * Constructs an update operation.  Arguments are as for the ZooKeeper method of the same name.\n     * @see ZooKeeper#setData(String, byte[], int)\n     *\n     * @param path\n     *                the path of the node\n     * @param data\n     *                the data to set\n     * @param version\n     *                the expected matching version\n     */\n    public static Op setData(String path, byte[] data, int version) {\n        return new SetData(path, data, version);\n    }\n\n\n    /**\n     * Constructs an version check operation.  Arguments are as for the ZooKeeper.setData method except that\n     * no data is provided since no update is intended.  The purpose for this is to allow read-modify-write\n     * operations that apply to multiple znodes, but where some of the znodes are involved only in the read,\n     * not the write.  A similar effect could be achieved by writing the same data back, but that leads to\n     * way more version updates than are necessary and more writing in general.\n     *\n     * @param path\n     *                the path of the node\n     * @param version\n     *                the expected matching version\n     */\n    public static Op check(String path, int version) {\n        return new Check(path, version);\n    }\n\n    /**\n     * Gets the integer type code for an Op.  This code should be as from ZooDefs.OpCode\n     * @see ZooDefs.OpCode\n     * @return  The type code.\n     */\n    public int getType() {\n        return type;\n    }\n\n    /**\n     * Gets the path for an Op.\n     * @return  The path.\n     */\n    public String getPath() {\n        return path;\n    }\n\n    /**\n     * Encodes an op for wire transmission.\n     * @return An appropriate Record structure.\n     */\n    public abstract Record toRequestRecord() ;\n\n    /**\n     * Reconstructs the transaction with the chroot prefix.\n     * \n     * @return transaction with chroot.\n     */\n    abstract Op withChroot(String addRootPrefix);\n\n    /**\n     * Performs client path validations.\n     * \n     * @throws IllegalArgumentException\n     *             if an invalid path is specified\n     * @throws KeeperException.BadArgumentsException\n     *             if an invalid create mode flag is specified\n     */\n    void validate() throws KeeperException {\n        PathUtils.validatePath(path);\n    }\n\n    //////////////////\n    // these internal classes are public, but should not generally be referenced.\n    //\n    public static class Create extends Op {\n        private byte[] data;\n        private List<ACL> acl;\n        private int flags;\n\n        private Create(String path, byte[] data, List<ACL> acl, int flags) {\n            super(ZooDefs.OpCode.create, path);\n            this.data = data;\n            this.acl = acl;\n            this.flags = flags;\n        }\n\n        private Create(String path, byte[] data, List<ACL> acl, CreateMode createMode) {\n            super(ZooDefs.OpCode.create, path);\n            this.data = data;\n            this.acl = acl;\n            this.flags = createMode.toFlag();\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof Create)) return false;\n\n            Create op = (Create) o;\n\n            boolean aclEquals = true;\n            Iterator<ACL> i = op.acl.iterator();\n            for (ACL acl : op.acl) {\n                boolean hasMoreData = i.hasNext();\n                if (!hasMoreData) {\n                    aclEquals = false;\n                    break;\n                }\n                ACL otherAcl = i.next();\n                if (!acl.equals(otherAcl)) {\n                    aclEquals = false;\n                    break;\n                }\n            }\n            return !i.hasNext() && getType() == op.getType() && Arrays.equals(data, op.data) && flags == op.flags && aclEquals;\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() + getPath().hashCode() + Arrays.hashCode(data);\n        }\n\n        @Override\n        public Record toRequestRecord() {\n            return new CreateRequest(getPath(), data, acl, flags);\n        }\n\n        @Override\n        Op withChroot(String path) {\n            return new Create(path, data, acl, flags);\n        }\n\n        @Override\n        void validate() throws KeeperException {\n            CreateMode createMode = CreateMode.fromFlag(flags);\n            PathUtils.validatePath(getPath(), createMode.isSequential());\n        }\n    }\n\n    public static class Delete extends Op {\n        private int version;\n\n        private Delete(String path, int version) {\n            super(ZooDefs.OpCode.delete, path);\n            this.version = version;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof Delete)) return false;\n\n            Delete op = (Delete) o;\n\n            return getType() == op.getType() && version == op.version \n                   && getPath().equals(op.getPath());\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() + getPath().hashCode() + version;\n        }\n\n        @Override\n        public Record toRequestRecord() {\n            return new DeleteRequest(getPath(), version);\n        }\n\n        @Override\n        Op withChroot(String path) {\n            return new Delete(path, version);\n        }\n    }\n\n    public static class SetData extends Op {\n        private byte[] data;\n        private int version;\n\n        private SetData(String path, byte[] data, int version) {\n            super(ZooDefs.OpCode.setData, path);\n            this.data = data;\n            this.version = version;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof SetData)) return false;\n\n            SetData op = (SetData) o;\n\n            return getType() == op.getType() && version == op.version \n                   && getPath().equals(op.getPath()) && Arrays.equals(data, op.data);\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() + getPath().hashCode() + Arrays.hashCode(data) + version;\n        }\n\n        @Override\n        public Record toRequestRecord() {\n            return new SetDataRequest(getPath(), data, version);\n        }\n\n        @Override\n        Op withChroot(String path) {\n            return new SetData(path, data, version);\n        }\n    }\n\n    public static class Check extends Op {\n        private int version;\n\n        private Check(String path, int version) {\n            super(ZooDefs.OpCode.check, path);\n            this.version = version;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof Check)) return false;\n\n            Check op = (Check) o;\n\n            return getType() == op.getType() && getPath().equals(op.getPath()) && version == op.version;\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() + getPath().hashCode() + version;\n        }\n\n        @Override\n        public Record toRequestRecord() {\n            return new CheckVersionRequest(getPath(), version);\n        }\n\n        @Override\n        Op withChroot(String path) {\n            return new Check(path, version);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/OpResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\n\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * Encodes the result of a single part of a multiple operation commit.\n */\npublic abstract class OpResult {\n    private int type;\n\n    private OpResult(int type) {\n        this.type = type;\n    }\n\n    /**\n     * Encodes the return type as from ZooDefs.OpCode.  Can be used\n     * to dispatch to the correct cast needed for getting the desired\n     * additional result data.\n     * @see ZooDefs.OpCode\n     * @return an integer identifying what kind of operation this result came from.\n     */\n    public int getType() {\n        return type;\n    }\n\n    /**\n     * A result from a create operation.  This kind of result allows the\n     * path to be retrieved since the create might have been a sequential\n     * create.\n     */\n    public static class CreateResult extends OpResult {\n        private String path;\n\n        public CreateResult(String path) {\n            super(ZooDefs.OpCode.create);\n            this.path = path;\n        }\n\n        public String getPath() {\n            return path;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof CreateResult)) return false;\n\n            CreateResult other = (CreateResult) o;\n            return getType() == other.getType() && path.equals(other.getPath());\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() * 35 + path.hashCode();\n        }\n    }\n\n    /**\n     * A result from a delete operation.  No special values are available.\n     */\n    public static class DeleteResult extends OpResult {\n        public DeleteResult() {\n            super(ZooDefs.OpCode.delete);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof DeleteResult)) return false;\n\n            DeleteResult opResult = (DeleteResult) o;\n            return getType() == opResult.getType();\n        }\n\n        @Override\n        public int hashCode() {\n            return getType();\n        }\n    }\n\n    /**\n     * A result from a setData operation.  This kind of result provides access\n     * to the Stat structure from the update.\n     */\n    public static class SetDataResult extends OpResult {\n        private Stat stat;\n\n        public SetDataResult(Stat stat) {\n            super(ZooDefs.OpCode.setData);\n            this.stat = stat;\n        }\n\n        public Stat getStat() {\n            return stat;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof SetDataResult)) return false;\n\n            SetDataResult other = (SetDataResult) o;\n            return getType() == other.getType() && stat.getMzxid() == other.stat.getMzxid();\n        }\n\n        @Override\n        public int hashCode() {\n            return (int) (getType() * 35 + stat.getMzxid());\n        }\n    }\n\n    /**\n     * A result from a version check operation.  No special values are available.\n     */\n    public static class CheckResult extends OpResult {\n        public CheckResult() {\n            super(ZooDefs.OpCode.check);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof CheckResult)) return false;\n\n            CheckResult other = (CheckResult) o;\n            return getType() == other.getType();\n        }\n\n        @Override\n        public int hashCode() {\n            return getType();\n        }\n    }\n\n    /**\n     * An error result from any kind of operation.  The point of error results\n     * is that they contain an error code which helps understand what happened.\n     * @see KeeperException.Code\n     *\n     */\n    public static class ErrorResult extends OpResult {\n        private int err;\n\n        public ErrorResult(int err) {\n            super(ZooDefs.OpCode.error);\n            this.err = err;\n        }\n\n        public int getErr() {\n            return err;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof ErrorResult)) return false;\n\n            ErrorResult other = (ErrorResult) o;\n            return getType() == other.getType() && err == other.getErr();\n        }\n\n        @Override\n        public int hashCode() {\n            return getType() * 35 + err;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Quotas.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\n/**\n * this class manages quotas\n * and has many other utils\n * for quota\n */\npublic class Quotas {\n\n    /** the zookeeper nodes that acts as the management and status node **/\n    public static final String procZookeeper = \"/zookeeper\";\n\n    /** the zookeeper quota node that acts as the quota\n     * management node for zookeeper */\n    public static final String quotaZookeeper = \"/zookeeper/quota\";\n\n    /**\n     * the limit node that has the limit of\n     * a subtree\n     */\n    public static final String limitNode = \"zookeeper_limits\";\n\n    /**\n     * the stat node that monitors the limit of\n     * a subtree.\n     */\n    public static final String statNode = \"zookeeper_stats\";\n\n    /**\n     * return the quota path associated with this\n     * prefix\n     * @param path the actual path in zookeeper.\n     * @return the limit quota path\n     */\n    public static String quotaPath(String path) {\n        return quotaZookeeper + path +\n        \"/\" + limitNode;\n    }\n\n    /**\n     * return the stat quota path associated with this\n     * prefix.\n     * @param path the actual path in zookeeper\n     * @return the stat quota path\n     */\n    public static String statPath(String path) {\n        return quotaZookeeper + path + \"/\" +\n        statNode;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/SaslClientCallbackHandler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport javax.security.auth.callback.Callback;\nimport javax.security.auth.callback.CallbackHandler;\nimport javax.security.auth.callback.NameCallback;\nimport javax.security.auth.callback.PasswordCallback;\nimport javax.security.auth.callback.UnsupportedCallbackException;\nimport javax.security.sasl.AuthorizeCallback;\nimport javax.security.sasl.RealmCallback;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This is used by the SASL mechanisms to get further information to complete\n * the authentication. For example, a SASL mechanism might use this callback\n * handler to do verification operation. The CallbackHandler interface here\n * refers to javax.security.auth.callback.CallbackHandler. It should not be\n * confused with ZooKeeper packet callbacks like\n * org.apache.zookeeper.server.auth.SaslServerCallbackHandler.\n */\npublic class SaslClientCallbackHandler implements CallbackHandler {\n    private String password = null;\n    private static final Logger LOG = LoggerFactory.getLogger(SaslClientCallbackHandler.class);\n    private final String entity;\n    public SaslClientCallbackHandler(String password, String client) {\n        this.password = password;\n        this.entity = client;\n    }\n\n    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {\n        for (Callback callback : callbacks) {\n            if (callback instanceof NameCallback) {\n                NameCallback nc = (NameCallback) callback;\n                nc.setName(nc.getDefaultName());\n            }\n            else {\n                if (callback instanceof PasswordCallback) {\n                    PasswordCallback pc = (PasswordCallback)callback;\n                    if (password != null) {\n                        pc.setPassword(this.password.toCharArray());\n                    } else {\n                        LOG.warn(\"Could not login: the {} is being asked for a password, but the ZooKeeper {}\" +\n                          \" code does not currently support obtaining a password from the user.\" +\n                          \" Make sure that the {} is configured to use a ticket cache (using\" +\n                          \" the JAAS configuration setting 'useTicketCache=true)' and restart the {}. If\" +\n                          \" you still get this message after that, the TGT in the ticket cache has expired and must\" +\n                          \" be manually refreshed. To do so, first determine if you are using a password or a\" +\n                          \" keytab. If the former, run kinit in a Unix shell in the environment of the user who\" +\n                          \" is running this Zookeeper {} using the command\" +\n                          \" 'kinit <princ>' (where <princ> is the name of the {}'s Kerberos principal).\" +\n                          \" If the latter, do\" +\n                          \" 'kinit -k -t <keytab> <princ>' (where <princ> is the name of the Kerberos principal, and\" +\n                          \" <keytab> is the location of the keytab file). After manually refreshing your cache,\" +\n                          \" restart this {}. If you continue to see this message after manually refreshing\" +\n                          \" your cache, ensure that your KDC host's clock is in sync with this host's clock.\",\n                          new Object[]{entity, entity, entity, entity, entity, entity, entity});\n                    }\n                }\n                else {\n                    if (callback instanceof RealmCallback) {\n                        RealmCallback rc = (RealmCallback) callback;\n                        rc.setText(rc.getDefaultText());\n                    }\n                    else {\n                        if (callback instanceof AuthorizeCallback) {\n                            AuthorizeCallback ac = (AuthorizeCallback) callback;\n                            String authid = ac.getAuthenticationID();\n                            String authzid = ac.getAuthorizationID();\n                            if (authid.equals(authzid)) {\n                                ac.setAuthorized(true);\n                            } else {\n                                ac.setAuthorized(false);\n                            }\n                            if (ac.isAuthorized()) {\n                                ac.setAuthorizedID(authzid);\n                            }\n                        }\n                        else {\n                            throw new UnsupportedCallbackException(callback, \"Unrecognized SASL \" + entity + \"Callback\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ServerAdminClient.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.util.StringTokenizer;\n\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.ZooTrace;\n\n@InterfaceAudience.Public\npublic class ServerAdminClient {\n    private static final Logger LOG = LoggerFactory.getLogger(ServerAdminClient.class);\n\n    private static long getMask(String mask) {\n        long retv = 0;\n        if (mask.equalsIgnoreCase(\"CLIENT_REQUEST_TRACE_MASK\")) {\n            retv = ZooTrace.CLIENT_REQUEST_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"CLIENT_DATA_PACKET_TRACE_MASK\")) {\n            retv = ZooTrace.CLIENT_DATA_PACKET_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"CLIENT_PING_TRACE_MASK\")) {\n            retv = ZooTrace.CLIENT_PING_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"SERVER_PACKET_TRACE_MASK\")) {\n            retv = ZooTrace.SERVER_PACKET_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"SESSION_TRACE_MASK\")) {\n            retv = ZooTrace.SESSION_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"EVENT_DELIVERY_TRACE_MASK\")) {\n            retv = ZooTrace.EVENT_DELIVERY_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"SERVER_PING_TRACE_MASK\")) {\n            retv = ZooTrace.SERVER_PING_TRACE_MASK;\n        } else if (mask.equalsIgnoreCase(\"WARNING_TRACE_MASK\")) {\n            retv = ZooTrace.WARNING_TRACE_MASK;\n        }\n        return retv;\n    }\n\n    private static long getMasks(String masks) {\n        long retv = 0;\n        StringTokenizer st = new StringTokenizer(masks, \"|\");\n        while (st.hasMoreTokens()) {\n            String mask = st.nextToken().trim();\n            retv = retv | getMask(mask);\n        }\n        return retv;\n    }\n\n    public static void ruok(String host, int port) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[4];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            req.putInt(ByteBuffer.wrap(\"ruok\".getBytes()).getInt());\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n\n            byte[] resBytes = new byte[4];\n\n            int rc = is.read(resBytes);\n            String retv = new String(resBytes);\n            System.out.println(\"rc=\" + rc + \" retv=\" + retv);\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    public static void dump(String host, int port) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[4];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            req.putInt(ByteBuffer.wrap(\"dump\".getBytes()).getInt());\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n\n            byte[] resBytes = new byte[1024];\n\n            int rc = is.read(resBytes);\n            String retv = new String(resBytes);\n            System.out.println(\"rc=\" + rc + \" retv=\" + retv);\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    public static void stat(String host, int port) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[4];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            req.putInt(ByteBuffer.wrap(\"stat\".getBytes()).getInt());\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n\n            byte[] resBytes = new byte[1024];\n\n            int rc = is.read(resBytes);\n            String retv = new String(resBytes);\n            System.out.println(\"rc=\" + rc + \" retv=\" + retv);\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    public static void kill(String host, int port) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[4];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            req.putInt(ByteBuffer.wrap(\"kill\".getBytes()).getInt());\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n            byte[] resBytes = new byte[4];\n\n            int rc = is.read(resBytes);\n            String retv = new String(resBytes);\n            System.out.println(\"rc=\" + rc + \" retv=\" + retv);\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    public static void setTraceMask(String host, int port, String traceMaskStr) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[12];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            long traceMask = Long.parseLong(traceMaskStr, 8);\n            req.putInt(ByteBuffer.wrap(\"stmk\".getBytes()).getInt());\n            req.putLong(traceMask);\n\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n\n            byte[] resBytes = new byte[8];\n\n            int rc = is.read(resBytes);\n            ByteBuffer res = ByteBuffer.wrap(resBytes);\n            long retv = res.getLong();\n            System.out.println(\"rc=\" + rc + \" retv=0\"\n                    + Long.toOctalString(retv) + \" masks=0\"\n                    + Long.toOctalString(traceMask));\n            assert (retv == traceMask);\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    public static void getTraceMask(String host, int port) {\n        Socket s = null;\n        try {\n            byte[] reqBytes = new byte[12];\n            ByteBuffer req = ByteBuffer.wrap(reqBytes);\n            req.putInt(ByteBuffer.wrap(\"gtmk\".getBytes()).getInt());\n\n            s = new Socket();\n            s.setSoLinger(false, 10);\n            s.setSoTimeout(20000);\n            s.connect(new InetSocketAddress(host, port));\n\n            InputStream is = s.getInputStream();\n            OutputStream os = s.getOutputStream();\n\n            os.write(reqBytes);\n\n            byte[] resBytes = new byte[8];\n\n            int rc = is.read(resBytes);\n            ByteBuffer res = ByteBuffer.wrap(resBytes);\n            long retv = res.getLong();\n            System.out.println(\"rc=\" + rc + \" retv=0\"\n                    + Long.toOctalString(retv));\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (IOException e) {\n                    LOG.warn(\"Unexpected exception\", e);\n                }\n            }\n        }\n    }\n\n    private static void usage() {\n        System.out\n                .println(\"usage: java [-cp CLASSPATH] org.apache.zookeeper.ServerAdminClient \"\n                        + \"host port op (ruok|stat|dump|kill|gettracemask|settracemask) [arguments]\");\n\n    }\n\n    public static void main(String[] args) {\n        if (args.length < 3) {\n            usage();\n            return;\n        }\n        String host = args[0];\n        int port = Integer.parseInt(args[1]);\n        String op = args[2];\n        if (op.equalsIgnoreCase(\"gettracemask\")) {\n            getTraceMask(host, port);\n        } else if (op.equalsIgnoreCase(\"settracemask\")) {\n            setTraceMask(host, port, args[3]);\n        } else if (op.equalsIgnoreCase(\"ruok\")) {\n            ruok(host, port);\n        } else if (op.equalsIgnoreCase(\"kill\")) {\n            kill(host, port);\n        } else if (op.equalsIgnoreCase(\"stat\")) {\n            stat(host, port);\n        } else if (op.equalsIgnoreCase(\"dump\")) {\n            dump(host, port);\n        } else {\n            System.out.println(\"Unrecognized op: \" + op);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Shell.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* This file copied from Hadoop's security branch,\n  * with the following changes:\n  * 1. package changed from org.apache.hadoop.util to\n  *    org.apache.zookeeper.\n  * 2. Usage of Hadoop's Configuration class removed since\n  *    it is not available in Zookeeper: instead, system properties\n  *    are used.\n  * 3. The deprecated getUlimitMemoryCommand() method removed since\n  *    it is not needed.\n  */\n\n\npackage org.apache.zookeeper;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.Map;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport org.apache.log4j.Logger;\nimport org.apache.zookeeper.common.Time;\n\n/**\n * A base class for running a Unix command.\n * \n * <code>Shell</code> can be used to run unix commands like <code>du</code> or\n * <code>df</code>. It also offers facilities to gate commands by \n * time-intervals.\n */\nabstract public class Shell {\n  \n  Logger LOG = Logger.getLogger(Shell.class);\n  \n  /** a Unix command to get the current user's name */\n  public final static String USER_NAME_COMMAND = \"whoami\";\n  /** a Unix command to get the current user's groups list */\n  public static String[] getGroupsCommand() {\n    return new String[]{\"bash\", \"-c\", \"groups\"};\n  }\n  /** a Unix command to get a given user's groups list */\n  public static String[] getGroupsForUserCommand(final String user) {\n    //'groups username' command return is non-consistent across different unixes\n    return new String [] {\"bash\", \"-c\", \"id -Gn \" + user};\n  }\n  /** a Unix command to set permission */\n  public static final String SET_PERMISSION_COMMAND = \"chmod\";\n  /** a Unix command to set owner */\n  public static final String SET_OWNER_COMMAND = \"chown\";\n  public static final String SET_GROUP_COMMAND = \"chgrp\";\n  /** Return a Unix command to get permission information. */\n  public static String[] getGET_PERMISSION_COMMAND() {\n    //force /bin/ls, except on windows.\n    return new String[] {(WINDOWS ? \"ls\" : \"/bin/ls\"), \"-ld\"};\n  }\n\n  /**Time after which the executing script would be timedout*/\n  protected long timeOutInterval = 0L;\n  /** If or not script timed out*/\n  private AtomicBoolean timedOut;\n\n  /** a Unix command to get ulimit of a process. */\n  public static final String ULIMIT_COMMAND = \"ulimit\";\n  \n  /** \n   * Get the Unix command for setting the maximum virtual memory available\n   * to a given child process. This is only relevant when we are forking a\n   * process from within the Mapper or the Reducer implementations.\n   * Also see Hadoop Pipes and Hadoop Streaming.\n   * \n   * It also checks to ensure that we are running on a *nix platform else \n   * (e.g. in Cygwin/Windows) it returns <code>null</code>.\n   * @param memoryLimit virtual memory limit\n   * @return a <code>String[]</code> with the ulimit command arguments or \n   *         <code>null</code> if we are running on a non *nix platform or\n   *         if the limit is unspecified.\n   */\n  public static String[] getUlimitMemoryCommand(int memoryLimit) {\n    // ulimit isn't supported on Windows\n    if (WINDOWS) {\n      return null;\n    }\n    \n    return new String[] {ULIMIT_COMMAND, \"-v\", String.valueOf(memoryLimit)};\n  }\n\n  /** Set to true on Windows platforms */\n  public static final boolean WINDOWS /* borrowed from Path.WINDOWS */\n                = System.getProperty(\"os.name\").startsWith(\"Windows\");\n  \n  private long    interval;   // refresh interval in msec\n  private long    lastTime;   // last time the command was performed\n  private Map<String, String> environment; // env for the command execution\n  private File dir;\n  private Process process; // sub process used to execute the command\n  private int exitCode;\n\n  /**If or not script finished executing*/\n  private volatile AtomicBoolean completed;\n  \n  public Shell() {\n    this(0L);\n  }\n  \n  /**\n   * @param interval the minimum duration to wait before re-executing the \n   *        command.\n   */\n  public Shell( long interval ) {\n    this.interval = interval;\n    this.lastTime = (interval<0) ? 0 : -interval;\n  }\n  \n  /** set the environment for the command \n   * @param env Mapping of environment variables\n   */\n  protected void setEnvironment(Map<String, String> env) {\n    this.environment = env;\n  }\n\n  /** set the working directory \n   * @param dir The directory where the command would be executed\n   */\n  protected void setWorkingDirectory(File dir) {\n    this.dir = dir;\n  }\n\n  /** check to see if a command needs to be executed and execute if needed */\n  protected void run() throws IOException {\n    if (lastTime + interval > Time.currentElapsedTime())\n      return;\n    exitCode = 0; // reset for next run\n    runCommand();\n  }\n\n  /** Run a command */\n  private void runCommand() throws IOException { \n    ProcessBuilder builder = new ProcessBuilder(getExecString());\n    Timer timeOutTimer = null;\n    ShellTimeoutTimerTask timeoutTimerTask = null;\n    timedOut = new AtomicBoolean(false);\n    completed = new AtomicBoolean(false);\n    \n    if (environment != null) {\n      builder.environment().putAll(this.environment);\n    }\n    if (dir != null) {\n      builder.directory(this.dir);\n    }\n    \n    process = builder.start();\n    if (timeOutInterval > 0) {\n      timeOutTimer = new Timer();\n      timeoutTimerTask = new ShellTimeoutTimerTask(\n          this);\n      //One time scheduling.\n      timeOutTimer.schedule(timeoutTimerTask, timeOutInterval);\n    }\n    final BufferedReader errReader = \n            new BufferedReader(new InputStreamReader(process\n                                                     .getErrorStream()));\n    BufferedReader inReader = \n            new BufferedReader(new InputStreamReader(process\n                                                     .getInputStream()));\n    final StringBuffer errMsg = new StringBuffer();\n    \n    // read error and input streams as this would free up the buffers\n    // free the error stream buffer\n    Thread errThread = new Thread() {\n      @Override\n      public void run() {\n        try {\n          String line = errReader.readLine();\n          while((line != null) && !isInterrupted()) {\n            errMsg.append(line);\n            errMsg.append(System.getProperty(\"line.separator\"));\n            line = errReader.readLine();\n          }\n        } catch(IOException ioe) {\n          LOG.warn(\"Error reading the error stream\", ioe);\n        }\n      }\n    };\n    try {\n      errThread.start();\n    } catch (IllegalStateException ise) { }\n    try {\n      parseExecResult(inReader); // parse the output\n      // clear the input stream buffer\n      String line = inReader.readLine();\n      while(line != null) { \n        line = inReader.readLine();\n      }\n      // wait for the process to finish and check the exit code\n      exitCode  = process.waitFor();\n      try {\n        // make sure that the error thread exits\n        errThread.join();\n      } catch (InterruptedException ie) {\n        LOG.warn(\"Interrupted while reading the error stream\", ie);\n      }\n      completed.set(true);\n      //the timeout thread handling\n      //taken care in finally block\n      if (exitCode != 0) {\n        throw new ExitCodeException(exitCode, errMsg.toString());\n      }\n    } catch (InterruptedException ie) {\n      throw new IOException(ie.toString());\n    } finally {\n      if ((timeOutTimer!=null) && !timedOut.get()) {\n        timeOutTimer.cancel();\n      }\n      // close the input stream\n      try {\n        inReader.close();\n      } catch (IOException ioe) {\n        LOG.warn(\"Error while closing the input stream\", ioe);\n      }\n      if (!completed.get()) {\n        errThread.interrupt();\n      }\n      try {\n        errReader.close();\n      } catch (IOException ioe) {\n        LOG.warn(\"Error while closing the error stream\", ioe);\n      }\n      process.destroy();\n      lastTime = Time.currentElapsedTime();\n    }\n  }\n\n  /** return an array containing the command name & its parameters */ \n  protected abstract String[] getExecString();\n  \n  /** Parse the execution result */\n  protected abstract void parseExecResult(BufferedReader lines)\n  throws IOException;\n\n  /** get the current sub-process executing the given command \n   * @return process executing the command\n   */\n  public Process getProcess() {\n    return process;\n  }\n\n  /** get the exit code \n   * @return the exit code of the process\n   */\n  public int getExitCode() {\n    return exitCode;\n  }\n\n  /**\n   * This is an IOException with exit code added.\n   */\n  @SuppressWarnings(\"serial\")\n  public static class ExitCodeException extends IOException {\n    int exitCode;\n    \n    public ExitCodeException(int exitCode, String message) {\n      super(message);\n      this.exitCode = exitCode;\n    }\n    \n    public int getExitCode() {\n      return exitCode;\n    }\n  }\n  \n  /**\n   * A simple shell command executor.\n   * \n   * <code>ShellCommandExecutor</code>should be used in cases where the output \n   * of the command needs no explicit parsing and where the command, working \n   * directory and the environment remains unchanged. The output of the command \n   * is stored as-is and is expected to be small.\n   */\n  public static class ShellCommandExecutor extends Shell {\n    \n    private String[] command;\n    private StringBuffer output;\n    \n    \n    public ShellCommandExecutor(String[] execString) {\n      this(execString, null);\n    }\n    \n    public ShellCommandExecutor(String[] execString, File dir) {\n      this(execString, dir, null);\n    }\n   \n    public ShellCommandExecutor(String[] execString, File dir, \n                                 Map<String, String> env) {\n      this(execString, dir, env , 0L);\n    }\n\n    /**\n     * Create a new instance of the ShellCommandExecutor to execute a command.\n     * \n     * @param execString The command to execute with arguments\n     * @param dir If not-null, specifies the directory which should be set\n     *            as the current working directory for the command.\n     *            If null, the current working directory is not modified.\n     * @param env If not-null, environment of the command will include the\n     *            key-value pairs specified in the map. If null, the current\n     *            environment is not modified.\n     * @param timeout Specifies the time in milliseconds, after which the\n     *                command will be killed and the status marked as timedout.\n     *                If 0, the command will not be timed out. \n     */\n    public ShellCommandExecutor(String[] execString, File dir, \n        Map<String, String> env, long timeout) {\n      command = execString.clone();\n      if (dir != null) {\n        setWorkingDirectory(dir);\n      }\n      if (env != null) {\n        setEnvironment(env);\n      }\n      timeOutInterval = timeout;\n    }\n        \n\n    /** Execute the shell command. */\n    public void execute() throws IOException {\n      this.run();    \n    }\n\n    protected String[] getExecString() {\n      return command;\n    }\n\n    protected void parseExecResult(BufferedReader lines) throws IOException {\n      output = new StringBuffer();\n      char[] buf = new char[512];\n      int nRead;\n      while ( (nRead = lines.read(buf, 0, buf.length)) > 0 ) {\n        output.append(buf, 0, nRead);\n      }\n    }\n    \n    /** Get the output of the shell command.*/\n    public String getOutput() {\n      return (output == null) ? \"\" : output.toString();\n    }\n\n    /**\n     * Returns the commands of this instance.\n     * Arguments with spaces in are presented with quotes round; other\n     * arguments are presented raw\n     *\n     * @return a string representation of the object.\n     */\n    public String toString() {\n      StringBuilder builder = new StringBuilder();\n      String[] args = getExecString();\n      for (String s : args) {\n        if (s.indexOf(' ') >= 0) {\n          builder.append('\"').append(s).append('\"');\n        } else {\n          builder.append(s);\n        }\n        builder.append(' ');\n      }\n      return builder.toString();\n    }\n  }\n  \n  /**\n   * To check if the passed script to shell command executor timed out or\n   * not.\n   * \n   * @return if the script timed out.\n   */\n  public boolean isTimedOut() {\n    return timedOut.get();\n  }\n  \n  /**\n   * Set if the command has timed out.\n   * \n   */\n  private void setTimedOut() {\n    this.timedOut.set(true);\n  }\n  \n  /** \n   * Static method to execute a shell command. \n   * Covers most of the simple cases without requiring the user to implement  \n   * the <code>Shell</code> interface.\n   * @param cmd shell command to execute.\n   * @return the output of the executed command.\n   */\n  public static String execCommand(String ... cmd) throws IOException {\n    return execCommand(null, cmd, 0L);\n  }\n  \n  /** \n   * Static method to execute a shell command. \n   * Covers most of the simple cases without requiring the user to implement  \n   * the <code>Shell</code> interface.\n   * @param env the map of environment key=value\n   * @param cmd shell command to execute.\n   * @param timeout time in milliseconds after which script should be marked timeout\n   * @return the output of the executed command.o\n   */\n  \n  public static String execCommand(Map<String, String> env, String[] cmd,\n      long timeout) throws IOException {\n    ShellCommandExecutor exec = new ShellCommandExecutor(cmd, null, env, \n                                                          timeout);\n    exec.execute();\n    return exec.getOutput();\n  }\n\n  /** \n   * Static method to execute a shell command. \n   * Covers most of the simple cases without requiring the user to implement  \n   * the <code>Shell</code> interface.\n   * @param env the map of environment key=value\n   * @param cmd shell command to execute.\n   * @return the output of the executed command.\n   */\n  public static String execCommand(Map<String,String> env, String ... cmd) \n  throws IOException {\n    return execCommand(env, cmd, 0L);\n  }\n  \n  /**\n   * Timer which is used to timeout scripts spawned off by shell.\n   */\n  private static class ShellTimeoutTimerTask extends TimerTask {\n\n    private Shell shell;\n\n    public ShellTimeoutTimerTask(Shell shell) {\n      this.shell = shell;\n    }\n\n    @Override\n    public void run() {\n      Process p = shell.getProcess();\n      try {\n        p.exitValue();\n      } catch (Exception e) {\n        //Process has not terminated.\n        //So check if it has completed \n        //if not just destroy it.\n        if (p != null && !shell.completed.get()) {\n          shell.setTimedOut();\n          p.destroy();\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/StatsTrack.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\n/**\n * a class that represents the stats associated with quotas\n */\npublic class StatsTrack {\n    private int count;\n    private long bytes;\n    private String countStr = \"count\";\n    private String byteStr = \"bytes\";\n\n    /**\n     * a default constructor for\n     * stats\n     */\n    public StatsTrack() {\n        this(null);\n    }\n    /**\n     * the stat string should be of the form count=int,bytes=long\n     * if stats is called with null the count and bytes are initialized\n     * to -1.\n     * @param stats the stat string to be intialized with\n     */\n    public StatsTrack(String stats) {\n        if (stats == null) {\n            stats = \"count=-1,bytes=-1\";\n        }\n        String[] split = stats.split(\",\");\n        if (split.length != 2) {\n            throw new IllegalArgumentException(\"invalid string \" + stats);\n        }\n        count = Integer.parseInt(split[0].split(\"=\")[1]);\n        bytes = Long.parseLong(split[1].split(\"=\")[1]);\n    }\n\n\n    /**\n     * get the count of nodes allowed as part of quota\n     *\n     * @return the count as part of this string\n     */\n    public int getCount() {\n        return this.count;\n    }\n\n    /**\n     * set the count for this stat tracker.\n     *\n     * @param count\n     *            the count to set with\n     */\n    public void setCount(int count) {\n        this.count = count;\n    }\n\n    /**\n     * get the count of bytes allowed as part of quota\n     *\n     * @return the bytes as part of this string\n     */\n    public long getBytes() {\n        return this.bytes;\n    }\n\n    /**\n     * set teh bytes for this stat tracker.\n     *\n     * @param bytes\n     *            the bytes to set with\n     */\n    public void setBytes(long bytes) {\n        this.bytes = bytes;\n    }\n\n    @Override\n    /*\n     * returns the string that maps to this stat tracking.\n     */\n    public String toString() {\n        return countStr + \"=\" + count + \",\" + byteStr + \"=\" + bytes;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Transaction.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.AsyncCallback.MultiCallback;\nimport org.apache.zookeeper.data.ACL;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Provides a builder style interface for doing multiple updates.  This is\n * really just a thin layer on top of Zookeeper.multi().\n *\n * @since 3.4.0\n *\n */\n@InterfaceAudience.Public\npublic class Transaction {\n    private ZooKeeper zk;\n    private List<Op> ops = new ArrayList<Op>();\n\n    protected Transaction(ZooKeeper zk) {\n        this.zk = zk;\n    }\n\n    public Transaction create(final String path, byte data[], List<ACL> acl,\n                              CreateMode createMode) {\n        ops.add(Op.create(path, data, acl, createMode.toFlag()));\n        return this;\n    }\n\n    public Transaction delete(final String path, int version) {\n        ops.add(Op.delete(path, version));\n        return this;\n    }\n\n    public Transaction check(String path, int version) {\n        ops.add(Op.check(path, version));\n        return this;\n    }\n\n    public Transaction setData(final String path, byte data[], int version) {\n        ops.add(Op.setData(path, data, version));\n        return this;\n    }\n\n    public List<OpResult> commit() throws InterruptedException, KeeperException {\n        return zk.multi(ops);\n    }\n\n    public void commit(MultiCallback cb, Object ctx) {\n        zk.multi(ops, cb, ctx);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Version.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\npublic class Version implements org.apache.zookeeper.version.Info {\n\n    /*\n     * Since the SVN to Git port this field doesn't return the revision anymore\n     * TODO: remove this method and associated field declaration in VerGen\n     * @see {@link #getHashRevision()}\n     * @return the default value -1\n     */\n    @Deprecated\n    public static int getRevision() {\n        return REVISION;\n    }\n\n    public static String getRevisionHash() {\n        return REVISION_HASH;\n    }\n\n    public static String getBuildDate() {\n        return BUILD_DATE;\n    }\n\n    public static String getVersion() {\n        return MAJOR + \".\" + MINOR + \".\" + MICRO\n            + (QUALIFIER == null ? \"\" : \"-\" + QUALIFIER);\n    }\n\n    public static String getVersionRevision() {\n        return getVersion() + \"-\" + getRevisionHash();\n    }\n\n    public static String getFullVersion() {\n        return getVersionRevision() + \", built on \" + getBuildDate();\n    }\n\n    public static void printUsage() {\n        System.out\n                .print(\"Usage:\\tjava -cp ... org.apache.zookeeper.Version \"\n                        + \"[--full | --short | --revision],\\n\\tPrints --full version \"\n                        + \"info if no arg specified.\");\n        System.exit(1);\n    }\n\n    /**\n     * Prints the current version, revision and build date to the standard out.\n     * \n     * @param args\n     *            <ul>\n     *            <li> --short - prints a short version string \"1.2.3\"\n     *            <li> --revision - prints a short version string with the SVN\n     *            repository revision \"1.2.3-94\"\n     *            <li> --full - prints the revision and the build date\n     *            </ul>\n     */\n    public static void main(String[] args) {\n        if (args.length > 1) {\n            printUsage();\n        }\n        if (args.length == 0 || (args.length == 1 && args[0].equals(\"--full\"))) {\n            System.out.println(getFullVersion());\n            System.exit(0);\n        }\n        if (args[0].equals(\"--short\"))\n            System.out.println(getVersion());\n        else if (args[0].equals(\"--revision\"))\n            System.out.println(getVersionRevision());\n        else\n            printUsage();\n        System.exit(0);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/WatchedEvent.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.proto.WatcherEvent;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\n\n/**\n *  A WatchedEvent represents a change on the ZooKeeper that a Watcher\n *  is able to respond to.  The WatchedEvent includes exactly what happened,\n *  the current state of the ZooKeeper, and the path of the znode that\n *  was involved in the event.\n */\n@InterfaceAudience.Public\npublic class WatchedEvent {\n    final private KeeperState keeperState;\n    final private EventType eventType;\n    private String path;\n    \n    /**\n     * Create a WatchedEvent with specified type, state and path\n     */\n    public WatchedEvent(EventType eventType, KeeperState keeperState, String path) {\n        this.keeperState = keeperState;\n        this.eventType = eventType;\n        this.path = path;\n    }\n    \n    /**\n     * Convert a WatcherEvent sent over the wire into a full-fledged WatcherEvent\n     */\n    public WatchedEvent(WatcherEvent eventMessage) {\n        keeperState = KeeperState.fromInt(eventMessage.getState());\n        eventType = EventType.fromInt(eventMessage.getType());\n        path = eventMessage.getPath();\n    }\n    \n    public KeeperState getState() {\n        return keeperState;\n    }\n    \n    public EventType getType() {\n        return eventType;\n    }\n    \n    public String getPath() {\n        return path;\n    }\n\n    @Override\n    public String toString() {\n        return \"WatchedEvent state:\" + keeperState\n            + \" type:\" + eventType + \" path:\" + path;\n    }\n\n    /**\n     *  Convert WatchedEvent to type that can be sent over network\n     */\n    public WatcherEvent getWrapper() {\n        return new WatcherEvent(eventType.getIntValue(), \n                                keeperState.getIntValue(), \n                                path);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/Watcher.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\n\n/**\n * This interface specifies the public interface an event handler class must\n * implement. A ZooKeeper client will get various events from the ZooKeeper\n * server it connects to. An application using such a client handles these\n * events by registering a callback object with the client. The callback object\n * is expected to be an instance of a class that implements Watcher interface.\n * \n */\n@InterfaceAudience.Public\npublic interface Watcher {\n\n    /**\n     * This interface defines the possible states an Event may represent\n     */\n    @InterfaceAudience.Public\n    public interface Event {\n        /**\n         * Enumeration of states the ZooKeeper may be at the event\n         */\n        @InterfaceAudience.Public\n        public enum KeeperState {\n            /** Unused, this state is never generated by the server */\n            @Deprecated\n            Unknown (-1),\n\n            /** The client is in the disconnected state - it is not connected\n             * to any server in the ensemble. */\n            Disconnected (0),\n\n            /** Unused, this state is never generated by the server */\n            @Deprecated\n            NoSyncConnected (1),\n\n            /** The client is in the connected state - it is connected\n             * to a server in the ensemble (one of the servers specified\n             * in the host connection parameter during ZooKeeper client\n             * creation). */\n            SyncConnected (3),\n\n            /**\n             * Auth failed state\n             */\n            AuthFailed (4),\n\n            /**\n             * The client is connected to a read-only server, that is the\n             * server which is not currently connected to the majority.\n             * The only operations allowed after receiving this state is\n             * read operations.\n             * This state is generated for read-only clients only since\n             * read/write clients aren't allowed to connect to r/o servers.\n             */\n            ConnectedReadOnly (5),\n\n            /**\n              * SaslAuthenticated: used to notify clients that they are SASL-authenticated,\n              * so that they can perform Zookeeper actions with their SASL-authorized permissions.\n              */\n            SaslAuthenticated(6),\n\n            /** The serving cluster has expired this session. The ZooKeeper\n             * client connection (the session) is no longer valid. You must\n             * create a new client connection (instantiate a new ZooKeeper\n             * instance) if you with to access the ensemble. */\n            Expired (-112);\n\n            private final int intValue;     // Integer representation of value\n                                            // for sending over wire\n\n            KeeperState(int intValue) {\n                this.intValue = intValue;\n            }\n\n            public int getIntValue() {\n                return intValue;\n            }\n\n            public static KeeperState fromInt(int intValue) {\n                switch(intValue) {\n                    case   -1: return KeeperState.Unknown;\n                    case    0: return KeeperState.Disconnected;\n                    case    1: return KeeperState.NoSyncConnected;\n                    case    3: return KeeperState.SyncConnected;\n                    case    4: return KeeperState.AuthFailed;\n                    case    5: return KeeperState.ConnectedReadOnly;\n                    case    6: return KeeperState.SaslAuthenticated;\n                    case -112: return KeeperState.Expired;\n\n                    default:\n                        throw new RuntimeException(\"Invalid integer value for conversion to KeeperState\");\n                }\n            }\n        }\n\n        /**\n         * Enumeration of types of events that may occur on the ZooKeeper\n         */\n        @InterfaceAudience.Public\n        public enum EventType {\n            None (-1),\n            NodeCreated (1),\n            NodeDeleted (2),\n            NodeDataChanged (3),\n            NodeChildrenChanged (4);\n\n            private final int intValue;     // Integer representation of value\n                                            // for sending over wire\n\n            EventType(int intValue) {\n                this.intValue = intValue;\n            }\n\n            public int getIntValue() {\n                return intValue;\n            }\n\n            public static EventType fromInt(int intValue) {\n                switch(intValue) {\n                    case -1: return EventType.None;\n                    case  1: return EventType.NodeCreated;\n                    case  2: return EventType.NodeDeleted;\n                    case  3: return EventType.NodeDataChanged;\n                    case  4: return EventType.NodeChildrenChanged;\n\n                    default:\n                        throw new RuntimeException(\"Invalid integer value for conversion to EventType\");\n                }\n            }           \n        }\n    }\n\n    abstract public void process(WatchedEvent event);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ZKUtil.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.common.PathUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n         \npublic class ZKUtil {\n    private static final Logger LOG = LoggerFactory.getLogger(ZKUtil.class);\n    /**\n     * Recursively delete the node with the given path. \n     * <p>\n     * Important: All versions, of all nodes, under the given node are deleted.\n     * <p>\n     * If there is an error with deleting one of the sub-nodes in the tree, \n     * this operation would abort and would be the responsibility of the app to handle the same.\n     * \n     * See {@link #delete(String, int)} for more details.\n     * \n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public static void deleteRecursive(ZooKeeper zk, final String pathRoot)\n        throws InterruptedException, KeeperException\n    {\n        PathUtils.validatePath(pathRoot);\n      \n        List<String> tree = listSubTreeBFS(zk, pathRoot);\n        LOG.debug(\"Deleting \" + tree);\n        LOG.debug(\"Deleting \" + tree.size() + \" subnodes \");\n        for (int i = tree.size() - 1; i >= 0 ; --i) {\n            //Delete the leaves first and eventually get rid of the root\n            zk.delete(tree.get(i), -1); //Delete all versions of the node with -1.\n        }\n    }\n    \n\n    /**\n     * Recursively delete the node with the given path. (async version).\n     * \n     * <p>\n     * Important: All versions, of all nodes, under the given node are deleted.\n     * <p>\n     * If there is an error with deleting one of the sub-nodes in the tree, \n     * this operation would abort and would be the responsibility of the app to handle the same.\n     * <p>\n     * @param zk the zookeeper handle\n     * @param pathRoot the path to be deleted\n     * @param cb call back method\n     * @param ctx the context the callback method is called with\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public static void deleteRecursive(ZooKeeper zk, final String pathRoot, VoidCallback cb,\n        Object ctx)\n        throws InterruptedException, KeeperException\n    {\n        PathUtils.validatePath(pathRoot);\n      \n        List<String> tree = listSubTreeBFS(zk, pathRoot);\n        LOG.debug(\"Deleting \" + tree);\n        LOG.debug(\"Deleting \" + tree.size() + \" subnodes \");\n        for (int i = tree.size() - 1; i >= 0 ; --i) {\n            //Delete the leaves first and eventually get rid of the root\n            zk.delete(tree.get(i), -1, cb, ctx); //Delete all versions of the node with -1.\n        }\n    }\n    \n    /**\n     * BFS Traversal of the system under pathRoot, with the entries in the list, in the \n     * same order as that of the traversal.\n     * <p>\n     * <b>Important:</b> This is <i>not an atomic snapshot</i> of the tree ever, but the\n     *  state as it exists across multiple RPCs from zkClient to the ensemble.\n     * For practical purposes, it is suggested to bring the clients to the ensemble \n     * down (i.e. prevent writes to pathRoot) to 'simulate' a snapshot behavior.   \n     * \n     * @param zk the zookeeper handle\n     * @param pathRoot The znode path, for which the entire subtree needs to be listed.\n     * @throws InterruptedException \n     * @throws KeeperException \n     */\n    public static List<String> listSubTreeBFS(ZooKeeper zk, final String pathRoot) throws \n        KeeperException, InterruptedException {\n        Deque<String> queue = new LinkedList<String>();\n        List<String> tree = new ArrayList<String>();\n        queue.add(pathRoot);\n        tree.add(pathRoot);\n        while (true) {\n            String node = queue.pollFirst();\n            if (node == null) {\n                break;\n            }\n            List<String> children = zk.getChildren(node, false);\n            for (final String child : children) {\n                final String childPath = node + \"/\" + child;\n                queue.add(childPath);\n                tree.add(childPath);\n            }\n        }\n        return tree;\n    }\n    \n} \n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ZooDefs.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\n\n@InterfaceAudience.Public\npublic class ZooDefs {\n\n    @InterfaceAudience.Public\n    public interface OpCode {\n        public final int notification = 0;\n\n        public final int create = 1;\n\n        public final int delete = 2;\n\n        public final int exists = 3;\n\n        public final int getData = 4;\n\n        public final int setData = 5;\n\n        public final int getACL = 6;\n\n        public final int setACL = 7;\n\n        public final int getChildren = 8;\n\n        public final int sync = 9;\n\n        public final int ping = 11;\n\n        public final int getChildren2 = 12;\n\n        public final int check = 13;\n\n        public final int multi = 14;\n\n        public final int auth = 100;\n\n        public final int setWatches = 101;\n\n        public final int sasl = 102;\n\n        public final int createSession = -10;\n\n        public final int closeSession = -11;\n\n        public final int error = -1;\n    }\n\n    @InterfaceAudience.Public\n    public interface Perms {\n        int READ = 1 << 0;\n\n        int WRITE = 1 << 1;\n\n        int CREATE = 1 << 2;\n\n        int DELETE = 1 << 3;\n\n        int ADMIN = 1 << 4;\n\n        int ALL = READ | WRITE | CREATE | DELETE | ADMIN;\n    }\n\n    @InterfaceAudience.Public\n    public interface Ids {\n        /**\n         * This Id represents anyone.\n         */\n        public final Id ANYONE_ID_UNSAFE = new Id(\"world\", \"anyone\");\n\n        /**\n         * This Id is only usable to set ACLs. It will get substituted with the\n         * Id's the client authenticated with.\n         */\n        public final Id AUTH_IDS = new Id(\"auth\", \"\");\n\n        /**\n         * This is a completely open ACL .\n         */\n        public final ArrayList<ACL> OPEN_ACL_UNSAFE = new ArrayList<ACL>(\n                Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));\n\n        /**\n         * This ACL gives the creators authentication id's all permissions.\n         */\n        public final ArrayList<ACL> CREATOR_ALL_ACL = new ArrayList<ACL>(\n                Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));\n\n        /**\n         * This ACL gives the world the ability to read.\n         */\n        public final ArrayList<ACL> READ_ACL_UNSAFE = new ArrayList<ACL>(\n                Collections\n                        .singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));\n    }\n\n    final public static String[] opNames = { \"notification\", \"create\",\n            \"delete\", \"exists\", \"getData\", \"setData\", \"getACL\", \"setACL\",\n            \"getChildren\", \"getChildren2\", \"getMaxChildren\", \"setMaxChildren\", \"ping\" };\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ZooKeeper.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.AsyncCallback.*;\nimport org.apache.zookeeper.OpResult.ErrorResult;\nimport org.apache.zookeeper.client.ConnectStringParser;\nimport org.apache.zookeeper.client.HostProvider;\nimport org.apache.zookeeper.client.StaticHostProvider;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.apache.zookeeper.common.PathUtils;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.proto.*;\nimport org.apache.zookeeper.server.DataTree;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.net.SocketAddress;\nimport java.util.*;\n\n/**\n * This is the main class of ZooKeeper client library. To use a ZooKeeper\n * service, an application must first instantiate an object of ZooKeeper class.\n * All the iterations will be done by calling the methods of ZooKeeper class.\n * The methods of this class are thread-safe unless otherwise noted.\n * <p>\n * Once a connection to a server is established, a session ID is assigned to the\n * client. The client will send heart beats to the server periodically to keep\n * the session valid.\n * <p>\n * The application can call ZooKeeper APIs through a client as long as the\n * session ID of the client remains valid.\n * <p>\n * If for some reason, the client fails to send heart beats to the server for a\n * prolonged period of time (exceeding the sessionTimeout value, for instance),\n * the server will expire the session, and the session ID will become invalid.\n * The client object will no longer be usable. To make ZooKeeper API calls, the\n * application must create a new client object.\n * <p>\n * If the ZooKeeper server the client currently connects to fails or otherwise\n * does not respond, the client will automatically try to connect to another\n * server before its session ID expires. If successful, the application can\n * continue to use the client.\n * <p>\n * The ZooKeeper API methods are either synchronous or asynchronous. Synchronous\n * methods blocks until the server has responded. Asynchronous methods just queue\n * the request for sending and return immediately. They take a callback object that\n * will be executed either on successful execution of the request or on error with\n * an appropriate return code (rc) indicating the error.\n * <p>\n * Some successful ZooKeeper API calls can leave watches on the \"data nodes\" in\n * the ZooKeeper server. Other successful ZooKeeper API calls can trigger those\n * watches. Once a watch is triggered, an event will be delivered to the client\n * which left the watch at the first place. Each watch can be triggered only\n * once. Thus, up to one event will be delivered to a client for every watch it\n * leaves.\n * <p>\n * A client needs an object of a class implementing Watcher interface for\n * processing the events delivered to the client.\n *\n * When a client drops the current connection and re-connects to a server, all the\n * existing watches are considered as being triggered but the undelivered events\n * are lost. To emulate this, the client will generate a special event to tell\n * the event handler a connection has been dropped. This special event has\n * EventType None and KeeperState Disconnected.\n *\n */\n@InterfaceAudience.Public\npublic class ZooKeeper {\n\n    public static final String ZOOKEEPER_CLIENT_CNXN_SOCKET = \"zookeeper.clientCnxnSocket\";\n\n    protected final ClientCnxn cnxn;\n    private static final Logger LOG;\n    static {\n        //Keep these two lines together to keep the initialization order explicit\n        LOG = LoggerFactory.getLogger(ZooKeeper.class);\n        Environment.logEnv(\"Client environment:\", LOG);\n    }\n\n    public ZooKeeperSaslClient getSaslClient() {\n        return cnxn.zooKeeperSaslClient;\n    }\n\n    private final ZKWatchManager watchManager = new ZKWatchManager();\n\n    List<String> getDataWatches() {\n        synchronized(watchManager.dataWatches) {\n            List<String> rc = new ArrayList<String>(watchManager.dataWatches.keySet());\n            return rc;\n        }\n    }\n    List<String> getExistWatches() {\n        synchronized(watchManager.existWatches) {\n            List<String> rc =  new ArrayList<String>(watchManager.existWatches.keySet());\n            return rc;\n        }\n    }\n    List<String> getChildWatches() {\n        synchronized(watchManager.childWatches) {\n            List<String> rc = new ArrayList<String>(watchManager.childWatches.keySet());\n            return rc;\n        }\n    }\n\n    /**\n     * Manage watchers & handle events generated by the ClientCnxn object.\n     *\n     * We are implementing this as a nested class of ZooKeeper so that\n     * the public methods will not be exposed as part of the ZooKeeper client\n     * API.\n     */\n    private static class ZKWatchManager implements ClientWatchManager {\n        private final Map<String, Set<Watcher>> dataWatches =\n            new HashMap<String, Set<Watcher>>();\n        private final Map<String, Set<Watcher>> existWatches =\n            new HashMap<String, Set<Watcher>>();\n        private final Map<String, Set<Watcher>> childWatches =\n            new HashMap<String, Set<Watcher>>();\n\n        private volatile Watcher defaultWatcher;\n\n        final private void addTo(Set<Watcher> from, Set<Watcher> to) {\n            if (from != null) {\n                to.addAll(from);\n            }\n        }\n\n        /* (non-Javadoc)\n         * @see org.apache.zookeeper.ClientWatchManager#materialize(Event.KeeperState, \n         *                                                        Event.EventType, java.lang.String)\n         */\n        @Override\n        public Set<Watcher> materialize(Watcher.Event.KeeperState state,\n                                        Watcher.Event.EventType type,\n                                        String clientPath)\n        {\n            Set<Watcher> result = new HashSet<Watcher>();\n\n            switch (type) {\n            case None:\n                result.add(defaultWatcher);\n                boolean clear = ClientCnxn.getDisableAutoResetWatch() &&\n                        state != Watcher.Event.KeeperState.SyncConnected;\n\n                synchronized(dataWatches) {\n                    for(Set<Watcher> ws: dataWatches.values()) {\n                        result.addAll(ws);\n                    }\n                    if (clear) {\n                        dataWatches.clear();\n                    }\n                }\n\n                synchronized(existWatches) {\n                    for(Set<Watcher> ws: existWatches.values()) {\n                        result.addAll(ws);\n                    }\n                    if (clear) {\n                        existWatches.clear();\n                    }\n                }\n\n                synchronized(childWatches) {\n                    for(Set<Watcher> ws: childWatches.values()) {\n                        result.addAll(ws);\n                    }\n                    if (clear) {\n                        childWatches.clear();\n                    }\n                }\n\n                return result;\n            case NodeDataChanged:\n            case NodeCreated:\n                synchronized (dataWatches) {\n                    addTo(dataWatches.remove(clientPath), result);\n                }\n                synchronized (existWatches) {\n                    addTo(existWatches.remove(clientPath), result);\n                }\n                break;\n            case NodeChildrenChanged:\n                synchronized (childWatches) {\n                    addTo(childWatches.remove(clientPath), result);\n                }\n                break;\n            case NodeDeleted:\n                synchronized (dataWatches) {\n                    addTo(dataWatches.remove(clientPath), result);\n                }\n                // XXX This shouldn't be needed, but just in case\n                synchronized (existWatches) {\n                    Set<Watcher> list = existWatches.remove(clientPath);\n                    if (list != null) {\n                        addTo(list, result);\n                        LOG.warn(\"We are triggering an exists watch for delete! Shouldn't happen!\");\n                    }\n                }\n                synchronized (childWatches) {\n                    addTo(childWatches.remove(clientPath), result);\n                }\n                break;\n            default:\n                String msg = \"Unhandled watch event type \" + type\n                    + \" with state \" + state + \" on path \" + clientPath;\n                LOG.error(msg);\n                throw new RuntimeException(msg);\n            }\n\n            return result;\n        }\n    }\n\n    /**\n     * Register a watcher for a particular path.\n     */\n    abstract class WatchRegistration {\n        private Watcher watcher;\n        private String clientPath;\n        public WatchRegistration(Watcher watcher, String clientPath)\n        {\n            this.watcher = watcher;\n            this.clientPath = clientPath;\n        }\n\n        abstract protected Map<String, Set<Watcher>> getWatches(int rc);\n\n        /**\n         * Register the watcher with the set of watches on path.\n         * @param rc the result code of the operation that attempted to\n         * add the watch on the path.\n         */\n        public void register(int rc) {\n            if (shouldAddWatch(rc)) {\n                Map<String, Set<Watcher>> watches = getWatches(rc);\n                synchronized(watches) {\n                    Set<Watcher> watchers = watches.get(clientPath);\n                    if (watchers == null) {\n                        watchers = new HashSet<Watcher>();\n                        watches.put(clientPath, watchers);\n                    }\n                    watchers.add(watcher);\n                }\n            }\n        }\n        /**\n         * Determine whether the watch should be added based on return code.\n         * @param rc the result code of the operation that attempted to add the\n         * watch on the node\n         * @return true if the watch should be added, otw false\n         */\n        protected boolean shouldAddWatch(int rc) {\n            return rc == 0;\n        }\n    }\n\n    /** Handle the special case of exists watches - they add a watcher\n     * even in the case where NONODE result code is returned.\n     */\n    class ExistsWatchRegistration extends WatchRegistration {\n        public ExistsWatchRegistration(Watcher watcher, String clientPath) {\n            super(watcher, clientPath);\n        }\n\n        @Override\n        protected Map<String, Set<Watcher>> getWatches(int rc) {\n            return rc == 0 ?  watchManager.dataWatches : watchManager.existWatches;\n        }\n\n        @Override\n        protected boolean shouldAddWatch(int rc) {\n            return rc == 0 || rc == KeeperException.Code.NONODE.intValue();\n        }\n    }\n\n    class DataWatchRegistration extends WatchRegistration {\n        public DataWatchRegistration(Watcher watcher, String clientPath) {\n            super(watcher, clientPath);\n        }\n\n        @Override\n        protected Map<String, Set<Watcher>> getWatches(int rc) {\n            return watchManager.dataWatches;\n        }\n    }\n\n    class ChildWatchRegistration extends WatchRegistration {\n        public ChildWatchRegistration(Watcher watcher, String clientPath) {\n            super(watcher, clientPath);\n        }\n\n        @Override\n        protected Map<String, Set<Watcher>> getWatches(int rc) {\n            return watchManager.childWatches;\n        }\n    }\n\n    @InterfaceAudience.Public\n    public enum States {\n        CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY,\n        CLOSED, AUTH_FAILED, NOT_CONNECTED;\n\n        public boolean isAlive() {\n            return this != CLOSED && this != AUTH_FAILED;\n        }\n\n        /**\n         * Returns whether we are connected to a server (which\n         * could possibly be read-only, if this client is allowed\n         * to go to read-only mode)\n         * */\n        public boolean isConnected() {\n            return this == CONNECTED || this == CONNECTEDREADONLY;\n        }\n    }\n\n    /**\n     * To create a ZooKeeper client object, the application needs to pass a\n     * connection string containing a comma separated list of host:port pairs,\n     * each corresponding to a ZooKeeper server.\n     * <p>\n     * Session establishment is asynchronous. This constructor will initiate\n     * connection to the server and return immediately - potentially (usually)\n     * before the session is fully established. The watcher argument specifies\n     * the watcher that will be notified of any changes in state. This\n     * notification can come at any point before or after the constructor call\n     * has returned.\n     * <p>\n     * The instantiated ZooKeeper client object will pick an arbitrary server\n     * from the connectString and attempt to connect to it. If establishment of\n     * the connection fails, another server in the connect string will be tried\n     * (the order is non-deterministic, as we random shuffle the list), until a\n     * connection is established. The client will continue attempts until the\n     * session is explicitly closed.\n     * <p>\n     * Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the\n     * connection string. This will run the client commands while interpreting\n     * all paths relative to this root (similar to the unix chroot command).\n     *\n     * @param connectString\n     *            comma separated host:port pairs, each corresponding to a zk\n     *            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\" If\n     *            the optional chroot suffix is used the example would look\n     *            like: \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\"\n     *            where the client would be rooted at \"/app/a\" and all paths\n     *            would be relative to this root - ie getting/setting/etc...\n     *            \"/foo/bar\" would result in operations being run on\n     *            \"/app/a/foo/bar\" (from the server perspective).\n     * @param sessionTimeout\n     *            session timeout in milliseconds\n     * @param watcher\n     *            a watcher object which will be notified of state changes, may\n     *            also be notified for node events\n     *\n     * @throws IOException\n     *             in cases of network failure\n     * @throws IllegalArgumentException\n     *             if an invalid chroot path is specified\n     */\n    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)\n        throws IOException\n    {\n        this(connectString, sessionTimeout, watcher, false);\n    }\n\n    /**\n     * To create a ZooKeeper client object, the application needs to pass a\n     * connection string containing a comma separated list of host:port pairs,\n     * each corresponding to a ZooKeeper server.\n     * <p>\n     * Session establishment is asynchronous. This constructor will initiate\n     * connection to the server and return immediately - potentially (usually)\n     * before the session is fully established. The watcher argument specifies\n     * the watcher that will be notified of any changes in state. This\n     * notification can come at any point before or after the constructor call\n     * has returned.\n     * <p>\n     * The instantiated ZooKeeper client object will pick an arbitrary server\n     * from the connectString and attempt to connect to it. If establishment of\n     * the connection fails, another server in the connect string will be tried\n     * (the order is non-deterministic, as we random shuffle the list), until a\n     * connection is established. The client will continue attempts until the\n     * session is explicitly closed.\n     * <p>\n     * Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the\n     * connection string. This will run the client commands while interpreting\n     * all paths relative to this root (similar to the unix chroot command).\n     *\n     * @param connectString\n     *            comma separated host:port pairs, each corresponding to a zk\n     *            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\" If\n     *            the optional chroot suffix is used the example would look\n     *            like: \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\"\n     *            where the client would be rooted at \"/app/a\" and all paths\n     *            would be relative to this root - ie getting/setting/etc...\n     *            \"/foo/bar\" would result in operations being run on\n     *            \"/app/a/foo/bar\" (from the server perspective).\n     * @param sessionTimeout\n     *            session timeout in milliseconds\n     * @param watcher\n     *            a watcher object which will be notified of state changes, may\n     *            also be notified for node events\n     * @param canBeReadOnly\n     *            (added in 3.4) whether the created client is allowed to go to\n     *            read-only mode in case of partitioning. Read-only mode\n     *            basically means that if the client can't find any majority\n     *            servers but there's partitioned server it could reach, it\n     *            connects to one in read-only mode, i.e. read requests are\n     *            allowed while write requests are not. It continues seeking for\n     *            majority in the background.\n     *\n     * @throws IOException\n     *             in cases of network failure\n     * @throws IllegalArgumentException\n     *             if an invalid chroot path is specified\n     */\n    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,\n            boolean canBeReadOnly)\n        throws IOException\n    {\n        LOG.info(\"Initiating client connection, connectString=\" + connectString\n                + \" sessionTimeout=\" + sessionTimeout + \" watcher=\" + watcher);\n\n        watchManager.defaultWatcher = watcher;\n\n        ConnectStringParser connectStringParser = new ConnectStringParser(\n                connectString);\n        HostProvider hostProvider = new StaticHostProvider(\n                connectStringParser.getServerAddresses());\n        cnxn = new ClientCnxn(connectStringParser.getChrootPath(),\n                hostProvider, sessionTimeout, this, watchManager,\n                getClientCnxnSocket(), canBeReadOnly);\n        cnxn.start();\n    }\n\n    /**\n     * To create a ZooKeeper client object, the application needs to pass a\n     * connection string containing a comma separated list of host:port pairs,\n     * each corresponding to a ZooKeeper server.\n     * <p>\n     * Session establishment is asynchronous. This constructor will initiate\n     * connection to the server and return immediately - potentially (usually)\n     * before the session is fully established. The watcher argument specifies\n     * the watcher that will be notified of any changes in state. This\n     * notification can come at any point before or after the constructor call\n     * has returned.\n     * <p>\n     * The instantiated ZooKeeper client object will pick an arbitrary server\n     * from the connectString and attempt to connect to it. If establishment of\n     * the connection fails, another server in the connect string will be tried\n     * (the order is non-deterministic, as we random shuffle the list), until a\n     * connection is established. The client will continue attempts until the\n     * session is explicitly closed (or the session is expired by the server).\n     * <p>\n     * Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the\n     * connection string. This will run the client commands while interpreting\n     * all paths relative to this root (similar to the unix chroot command).\n     * <p>\n     * Use {@link #getSessionId} and {@link #getSessionPasswd} on an established\n     * client connection, these values must be passed as sessionId and\n     * sessionPasswd respectively if reconnecting. Otherwise, if not\n     * reconnecting, use the other constructor which does not require these\n     * parameters.\n     *\n     * @param connectString\n     *            comma separated host:port pairs, each corresponding to a zk\n     *            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"\n     *            If the optional chroot suffix is used the example would look\n     *            like: \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\"\n     *            where the client would be rooted at \"/app/a\" and all paths\n     *            would be relative to this root - ie getting/setting/etc...\n     *            \"/foo/bar\" would result in operations being run on\n     *            \"/app/a/foo/bar\" (from the server perspective).\n     * @param sessionTimeout\n     *            session timeout in milliseconds\n     * @param watcher\n     *            a watcher object which will be notified of state changes, may\n     *            also be notified for node events\n     * @param sessionId\n     *            specific session id to use if reconnecting\n     * @param sessionPasswd\n     *            password for this session\n     *\n     * @throws IOException in cases of network failure\n     * @throws IllegalArgumentException if an invalid chroot path is specified\n     * @throws IllegalArgumentException for an invalid list of ZooKeeper hosts\n     */\n    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,\n            long sessionId, byte[] sessionPasswd)\n        throws IOException\n    {\n        this(connectString, sessionTimeout, watcher, sessionId, sessionPasswd, false);\n    }\n\n    /**\n     * To create a ZooKeeper client object, the application needs to pass a\n     * connection string containing a comma separated list of host:port pairs,\n     * each corresponding to a ZooKeeper server.\n     * <p>\n     * Session establishment is asynchronous. This constructor will initiate\n     * connection to the server and return immediately - potentially (usually)\n     * before the session is fully established. The watcher argument specifies\n     * the watcher that will be notified of any changes in state. This\n     * notification can come at any point before or after the constructor call\n     * has returned.\n     * <p>\n     * The instantiated ZooKeeper client object will pick an arbitrary server\n     * from the connectString and attempt to connect to it. If establishment of\n     * the connection fails, another server in the connect string will be tried\n     * (the order is non-deterministic, as we random shuffle the list), until a\n     * connection is established. The client will continue attempts until the\n     * session is explicitly closed (or the session is expired by the server).\n     * <p>\n     * Added in 3.2.0: An optional \"chroot\" suffix may also be appended to the\n     * connection string. This will run the client commands while interpreting\n     * all paths relative to this root (similar to the unix chroot command).\n     * <p>\n     * Use {@link #getSessionId} and {@link #getSessionPasswd} on an established\n     * client connection, these values must be passed as sessionId and\n     * sessionPasswd respectively if reconnecting. Otherwise, if not\n     * reconnecting, use the other constructor which does not require these\n     * parameters.\n     *\n     * @param connectString\n     *            comma separated host:port pairs, each corresponding to a zk\n     *            server. e.g. \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002\"\n     *            If the optional chroot suffix is used the example would look\n     *            like: \"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a\"\n     *            where the client would be rooted at \"/app/a\" and all paths\n     *            would be relative to this root - ie getting/setting/etc...\n     *            \"/foo/bar\" would result in operations being run on\n     *            \"/app/a/foo/bar\" (from the server perspective).\n     * @param sessionTimeout\n     *            session timeout in milliseconds\n     * @param watcher\n     *            a watcher object which will be notified of state changes, may\n     *            also be notified for node events\n     * @param sessionId\n     *            specific session id to use if reconnecting\n     * @param sessionPasswd\n     *            password for this session\n     * @param canBeReadOnly\n     *            (added in 3.4) whether the created client is allowed to go to\n     *            read-only mode in case of partitioning. Read-only mode\n     *            basically means that if the client can't find any majority\n     *            servers but there's partitioned server it could reach, it\n     *            connects to one in read-only mode, i.e. read requests are\n     *            allowed while write requests are not. It continues seeking for\n     *            majority in the background.\n     *\n     * @throws IOException in cases of network failure\n     * @throws IllegalArgumentException if an invalid chroot path is specified\n     */\n    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,\n            long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)\n        throws IOException\n    {\n        LOG.info(\"Initiating client connection, connectString=\" + connectString\n                + \" sessionTimeout=\" + sessionTimeout\n                + \" watcher=\" + watcher\n                + \" sessionId=\" + Long.toHexString(sessionId)\n                + \" sessionPasswd=\"\n                + (sessionPasswd == null ? \"<null>\" : \"<hidden>\"));\n\n        watchManager.defaultWatcher = watcher;\n\n        ConnectStringParser connectStringParser = new ConnectStringParser(\n                connectString);\n        HostProvider hostProvider = new StaticHostProvider(\n                connectStringParser.getServerAddresses());\n        cnxn = new ClientCnxn(connectStringParser.getChrootPath(),\n                hostProvider, sessionTimeout, this, watchManager,\n                getClientCnxnSocket(), sessionId, sessionPasswd, canBeReadOnly);\n        cnxn.seenRwServerBefore = true; // since user has provided sessionId\n        cnxn.start();\n    }\n\n    /**\n     * The session id for this ZooKeeper client instance. The value returned is\n     * not valid until the client connects to a server and may change after a\n     * re-connect.\n     *\n     * This method is NOT thread safe\n     *\n     * @return current session id\n     */\n    public long getSessionId() {\n        return cnxn.getSessionId();\n    }\n\n    /**\n     * The session password for this ZooKeeper client instance. The value\n     * returned is not valid until the client connects to a server and may\n     * change after a re-connect.\n     *\n     * This method is NOT thread safe\n     *\n     * @return current session password\n     */\n    public byte[] getSessionPasswd() {\n        return cnxn.getSessionPasswd();\n    }\n\n    /**\n     * The negotiated session timeout for this ZooKeeper client instance. The\n     * value returned is not valid until the client connects to a server and\n     * may change after a re-connect.\n     *\n     * This method is NOT thread safe\n     *\n     * @return current session timeout\n     */\n    public int getSessionTimeout() {\n        return cnxn.getSessionTimeout();\n    }\n\n    /**\n     * Add the specified scheme:auth information to this connection.\n     *\n     * This method is NOT thread safe\n     *\n     * @param scheme\n     * @param auth\n     */\n    public void addAuthInfo(String scheme, byte auth[]) {\n        cnxn.addAuthInfo(scheme, auth);\n    }\n\n    /**\n     * Specify the default watcher for the connection (overrides the one\n     * specified during construction).\n     *\n     * @param watcher\n     */\n    public synchronized void register(Watcher watcher) {\n        watchManager.defaultWatcher = watcher;\n    }\n\n    /**\n     * Close this client object. Once the client is closed, its session becomes\n     * invalid. All the ephemeral nodes in the ZooKeeper server associated with\n     * the session will be removed. The watches left on those nodes (and on\n     * their parents) will be triggered.\n     *\n     * @throws InterruptedException\n     */\n    public synchronized void close() throws InterruptedException {\n        if (!cnxn.getState().isAlive()) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Close called on already closed client\");\n            }\n            return;\n        }\n\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Closing session: 0x\" + Long.toHexString(getSessionId()));\n        }\n\n        try {\n            cnxn.close();\n        } catch (IOException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Ignoring unexpected exception during close\", e);\n            }\n        }\n\n        LOG.info(\"Session: 0x\" + Long.toHexString(getSessionId()) + \" closed\");\n    }\n\n    /**\n     * Prepend the chroot to the client path (if present). The expectation of\n     * this function is that the client path has been validated before this\n     * function is called\n     * @param clientPath path to the node\n     * @return server view of the path (chroot prepended to client path)\n     */\n    private String prependChroot(String clientPath) {\n        if (cnxn.chrootPath != null) {\n            // handle clientPath = \"/\"\n            if (clientPath.length() == 1) {\n                return cnxn.chrootPath;\n            }\n            return cnxn.chrootPath + clientPath;\n        } else {\n            return clientPath;\n        }\n    }\n\n    /**\n     * Create a node with the given path. The node data will be the given data,\n     * and node acl will be the given acl.\n     * <p>\n     * The flags argument specifies whether the created node will be ephemeral\n     * or not.\n     * <p>\n     * An ephemeral node will be removed by the ZooKeeper automatically when the\n     * session associated with the creation of the node expires.\n     * <p>\n     * The flags argument can also specify to create a sequential node. The\n     * actual path name of a sequential node will be the given path plus a\n     * suffix \"i\" where i is the current sequential number of the node. The sequence\n     * number is always fixed length of 10 digits, 0 padded. Once\n     * such a node is created, the sequential number will be incremented by one.\n     * <p>\n     * If a node with the same actual path already exists in the ZooKeeper, a\n     * KeeperException with error code KeeperException.NodeExists will be\n     * thrown. Note that since a different actual path is used for each\n     * invocation of creating sequential node with the same path argument, the\n     * call will never throw \"file exists\" KeeperException.\n     * <p>\n     * If the parent node does not exist in the ZooKeeper, a KeeperException\n     * with error code KeeperException.NoNode will be thrown.\n     * <p>\n     * An ephemeral node cannot have children. If the parent node of the given\n     * path is ephemeral, a KeeperException with error code\n     * KeeperException.NoChildrenForEphemerals will be thrown.\n     * <p>\n     * This operation, if successful, will trigger all the watches left on the\n     * node of the given path by exists and getData API calls, and the watches\n     * left on the parent node by getChildren API calls.\n     * <p>\n     * If a node is created successfully, the ZooKeeper server will trigger the\n     * watches on the path left by exists calls, and the watches on the parent\n     * of the node by getChildren calls.\n     * <p>\n     * The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n     * Arrays larger than this will cause a KeeperExecption to be thrown.\n     *\n     * @param path\n     *                the path for the node\n     * @param data\n     *                the initial data for the node\n     * @param acl\n     *                the acl for the node\n     * @param createMode\n     *                specifying whether the node to be created is ephemeral\n     *                and/or sequential\n     * @return the actual path of the created node\n     * @throws KeeperException if the server returns a non-zero error code\n     * @throws KeeperException.InvalidACLException if the ACL is invalid, null, or empty\n     * @throws InterruptedException if the transaction is interrupted\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public String create(final String path, byte data[], List<ACL> acl,\n            CreateMode createMode)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath, createMode.isSequential());\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.create);\n        CreateRequest request = new CreateRequest();\n        CreateResponse response = new CreateResponse();\n        request.setData(data);\n        request.setFlags(createMode.toFlag());\n        request.setPath(serverPath);\n        if (acl != null && acl.size() == 0) {\n            throw new KeeperException.InvalidACLException();\n        }\n        request.setAcl(acl);\n        ReplyHeader r = cnxn.submitRequest(h, request, response, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        if (cnxn.chrootPath == null) {\n            return response.getPath();\n        } else {\n            return response.getPath().substring(cnxn.chrootPath.length());\n        }\n    }\n\n    /**\n     * The asynchronous version of create.\n     *\n     * @see #create(String, byte[], List, CreateMode)\n     */\n\n    public void create(final String path, byte data[], List<ACL> acl,\n            CreateMode createMode,  StringCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath, createMode.isSequential());\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.create);\n        CreateRequest request = new CreateRequest();\n        CreateResponse response = new CreateResponse();\n        ReplyHeader r = new ReplyHeader();\n        request.setData(data);\n        request.setFlags(createMode.toFlag());\n        request.setPath(serverPath);\n        request.setAcl(acl);\n        cnxn.queuePacket(h, r, request, response, cb, clientPath,\n                serverPath, ctx, null);\n    }\n\n    /**\n     * Delete the node with the given path. The call will succeed if such a node\n     * exists, and the given version matches the node's version (if the given\n     * version is -1, it matches any node's versions).\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if the nodes does not exist.\n     * <p>\n     * A KeeperException with error code KeeperException.BadVersion will be\n     * thrown if the given version does not match the node's version.\n     * <p>\n     * A KeeperException with error code KeeperException.NotEmpty will be thrown\n     * if the node has children.\n     * <p>\n     * This operation, if successful, will trigger all the watches on the node\n     * of the given path left by exists API calls, and the watches on the parent\n     * node left by getChildren API calls.\n     *\n     * @param path\n     *                the path of the node to be deleted.\n     * @param version\n     *                the expected node version.\n     * @throws InterruptedException IF the server transaction is interrupted\n     * @throws KeeperException If the server signals an error with a non-zero\n     *   return code.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public void delete(final String path, int version)\n        throws InterruptedException, KeeperException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath;\n\n        // maintain semantics even in chroot case\n        // specifically - root cannot be deleted\n        // I think this makes sense even in chroot case.\n        if (clientPath.equals(\"/\")) {\n            // a bit of a hack, but delete(/) will never succeed and ensures\n            // that the same semantics are maintained\n            serverPath = clientPath;\n        } else {\n            serverPath = prependChroot(clientPath);\n        }\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.delete);\n        DeleteRequest request = new DeleteRequest();\n        request.setPath(serverPath);\n        request.setVersion(version);\n        ReplyHeader r = cnxn.submitRequest(h, request, null, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n    }\n\n    /**\n     * Executes multiple ZooKeeper operations or none of them.\n     * <p>\n     * On success, a list of results is returned.\n     * On failure, an exception is raised which contains partial results and\n     * error details, see {@link KeeperException#getResults}\n     * <p>\n     * Note: The maximum allowable size of all of the data arrays in all of\n     * the setData operations in this single request is typically 1 MB\n     * (1,048,576 bytes). This limit is specified on the server via\n     * <a href=\"http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#Unsafe+Options\">jute.maxbuffer</a>.\n     * Requests larger than this will cause a KeeperException to be\n     * thrown.\n     *\n     * @param ops An iterable that contains the operations to be done.\n     * These should be created using the factory methods on {@link Op}.\n     * @return A list of results, one for each input Op, the order of\n     * which exactly matches the order of the <code>ops</code> input\n     * operations.\n     * @throws InterruptedException If the operation was interrupted.\n     * The operation may or may not have succeeded, but will not have\n     * partially succeeded if this exception is thrown.\n     * @throws KeeperException If the operation could not be completed\n     * due to some error in doing one of the specified ops.\n     * @throws IllegalArgumentException if an invalid path is specified\n     *\n     * @since 3.4.0\n     */\n    public List<OpResult> multi(Iterable<Op> ops) throws InterruptedException, KeeperException {\n        for (Op op : ops) {\n            op.validate();\n        }\n        return multiInternal(generateMultiTransaction(ops));\n    }\n\n    /**\n     * The asynchronous version of multi.\n     *\n     * @see #multi(Iterable)\n     * @since 3.4.7\n     */\n    public void multi(Iterable<Op> ops, MultiCallback cb, Object ctx) {\n        List<OpResult> results = validatePath(ops);\n        if (results.size() > 0) {\n            cb.processResult(KeeperException.Code.BADARGUMENTS.intValue(),\n                             null, ctx, results);\n            return;\n        }\n        multiInternal(generateMultiTransaction(ops), cb, ctx);\n    }\n\n    private List<OpResult> validatePath(Iterable<Op> ops) {\n        List<OpResult> results = new ArrayList<OpResult>();\n        boolean error = false;\n        for (Op op : ops) {\n            try {\n                op.validate();\n            } catch (IllegalArgumentException iae) {\n                LOG.error(\"IllegalArgumentException: \" + iae.getMessage());\n                ErrorResult err = new ErrorResult(\n                        KeeperException.Code.BADARGUMENTS.intValue());\n                results.add(err);\n                error = true;\n                continue;\n            } catch (KeeperException ke) {\n                LOG.error(\"KeeperException: \" + ke.getMessage());\n                ErrorResult err = new ErrorResult(ke.code().intValue());\n                results.add(err);\n                error = true;\n                continue;\n            }\n            ErrorResult err = new ErrorResult(\n                    KeeperException.Code.RUNTIMEINCONSISTENCY.intValue());\n            results.add(err);\n        }\n        if (false == error) {\n            results.clear();\n        }\n        return results;\n    }\n\n    private MultiTransactionRecord generateMultiTransaction(Iterable<Op> ops) {\n        List<Op> transaction = new ArrayList<Op>();\n\n        for (Op op : ops) {\n            transaction.add(withRootPrefix(op));\n        }\n        return new MultiTransactionRecord(transaction);\n    }\n\n    private Op withRootPrefix(Op op) {\n        if (null != op.getPath()) {\n            final String serverPath = prependChroot(op.getPath());\n            if (!op.getPath().equals(serverPath)) {\n                return op.withChroot(serverPath);\n            }\n        }\n        return op;\n    }\n\n    protected void multiInternal(MultiTransactionRecord request, MultiCallback cb, Object ctx) {\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.multi);\n        MultiResponse response = new MultiResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, null, null, ctx, null);\n    }\n\n    protected List<OpResult> multiInternal(MultiTransactionRecord request)\n        throws InterruptedException, KeeperException {\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.multi);\n        MultiResponse response = new MultiResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()));\n        }\n\n        List<OpResult> results = response.getResultList();\n        \n        ErrorResult fatalError = null;\n        for (OpResult result : results) {\n            if (result instanceof ErrorResult && ((ErrorResult)result).getErr() != KeeperException.Code.OK.intValue()) {\n                fatalError = (ErrorResult) result;\n                break;\n            }\n        }\n\n        if (fatalError != null) {\n            KeeperException ex = KeeperException.create(KeeperException.Code.get(fatalError.getErr()));\n            ex.setMultiResults(results);\n            throw ex;\n        }\n\n        return results;\n    }\n\n    /**\n     * A Transaction is a thin wrapper on the {@link #multi} method\n     * which provides a builder object that can be used to construct\n     * and commit an atomic set of operations.\n     *\n     * @since 3.4.0\n     *\n     * @return a Transaction builder object\n     */\n    public Transaction transaction() {\n        return new Transaction(this);\n    }\n\n    /**\n     * The asynchronous version of delete.\n     *\n     * @see #delete(String, int)\n     */\n    public void delete(final String path, int version, VoidCallback cb,\n            Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath;\n\n        // maintain semantics even in chroot case\n        // specifically - root cannot be deleted\n        // I think this makes sense even in chroot case.\n        if (clientPath.equals(\"/\")) {\n            // a bit of a hack, but delete(/) will never succeed and ensures\n            // that the same semantics are maintained\n            serverPath = clientPath;\n        } else {\n            serverPath = prependChroot(clientPath);\n        }\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.delete);\n        DeleteRequest request = new DeleteRequest();\n        request.setPath(serverPath);\n        request.setVersion(version);\n        cnxn.queuePacket(h, new ReplyHeader(), request, null, cb, clientPath,\n                serverPath, ctx, null);\n    }\n\n    /**\n     * Return the stat of the node of the given path. Return null if no such a\n     * node exists.\n     * <p>\n     * If the watch is non-null and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch will be\n     * triggered by a successful operation that creates/delete the node or sets\n     * the data on the node.\n     *\n     * @param path the node path\n     * @param watcher explicit watcher\n     * @return the stat of the node of the given path; return null if no such a\n     *         node exists.\n     * @throws KeeperException If the server signals an error\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public Stat exists(final String path, Watcher watcher)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ExistsWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.exists);\n        ExistsRequest request = new ExistsRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        SetDataResponse response = new SetDataResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);\n        if (r.getErr() != 0) {\n            if (r.getErr() == KeeperException.Code.NONODE.intValue()) {\n                return null;\n            }\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n\n        return response.getStat().getCzxid() == -1 ? null : response.getStat();\n    }\n\n    /**\n     * Return the stat of the node of the given path. Return null if no such a\n     * node exists.\n     * <p>\n     * If the watch is true and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch will be\n     * triggered by a successful operation that creates/delete the node or sets\n     * the data on the node.\n     *\n     * @param path\n     *                the node path\n     * @param watch\n     *                whether need to watch this node\n     * @return the stat of the node of the given path; return null if no such a\n     *         node exists.\n     * @throws KeeperException If the server signals an error\n     * @throws InterruptedException If the server transaction is interrupted.\n     */\n    public Stat exists(String path, boolean watch) throws KeeperException,\n        InterruptedException\n    {\n        return exists(path, watch ? watchManager.defaultWatcher : null);\n    }\n\n    /**\n     * The asynchronous version of exists.\n     *\n     * @see #exists(String, Watcher)\n     */\n    public void exists(final String path, Watcher watcher,\n            StatCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ExistsWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.exists);\n        ExistsRequest request = new ExistsRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        SetDataResponse response = new SetDataResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, wcb);\n    }\n\n    /**\n     * The asynchronous version of exists.\n     *\n     * @see #exists(String, boolean)\n     */\n    public void exists(String path, boolean watch, StatCallback cb, Object ctx) {\n        exists(path, watch ? watchManager.defaultWatcher : null, cb, ctx);\n    }\n\n    /**\n     * Return the data and the stat of the node of the given path.\n     * <p>\n     * If the watch is non-null and the call is successful (no exception is\n     * thrown), a watch will be left on the node with the given path. The watch\n     * will be triggered by a successful operation that sets data on the node, or\n     * deletes the node.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @param path the given path\n     * @param watcher explicit watcher\n     * @param stat the stat of the node\n     * @return the data of the node\n     * @throws KeeperException If the server signals an error with a non-zero error code\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public byte[] getData(final String path, Watcher watcher, Stat stat)\n        throws KeeperException, InterruptedException\n     {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new DataWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getData);\n        GetDataRequest request = new GetDataRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetDataResponse response = new GetDataResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        if (stat != null) {\n            DataTree.copyStat(response.getStat(), stat);\n        }\n        return response.getData();\n    }\n\n    /**\n     * Return the data and the stat of the node of the given path.\n     * <p>\n     * If the watch is true and the call is successful (no exception is\n     * thrown), a watch will be left on the node with the given path. The watch\n     * will be triggered by a successful operation that sets data on the node, or\n     * deletes the node.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @param path the given path\n     * @param watch whether need to watch this node\n     * @param stat the stat of the node\n     * @return the data of the node\n     * @throws KeeperException If the server signals an error with a non-zero error code\n     * @throws InterruptedException If the server transaction is interrupted.\n     */\n    public byte[] getData(String path, boolean watch, Stat stat)\n            throws KeeperException, InterruptedException {\n        return getData(path, watch ? watchManager.defaultWatcher : null, stat);\n    }\n\n    /**\n     * The asynchronous version of getData.\n     *\n     * @see #getData(String, Watcher, Stat)\n     */\n    public void getData(final String path, Watcher watcher,\n            DataCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new DataWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getData);\n        GetDataRequest request = new GetDataRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetDataResponse response = new GetDataResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, wcb);\n    }\n\n    /**\n     * The asynchronous version of getData.\n     *\n     * @see #getData(String, boolean, Stat)\n     */\n    public void getData(String path, boolean watch, DataCallback cb, Object ctx) {\n        getData(path, watch ? watchManager.defaultWatcher : null, cb, ctx);\n    }\n\n    /**\n     * Set the data for the node of the given path if such a node exists and the\n     * given version matches the version of the node (if the given version is\n     * -1, it matches any node's versions). Return the stat of the node.\n     * <p>\n     * This operation, if successful, will trigger all the watches on the node\n     * of the given path left by getData calls.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     * <p>\n     * A KeeperException with error code KeeperException.BadVersion will be\n     * thrown if the given version does not match the node's version.\n     * <p>\n     * The maximum allowable size of the data array is 1 MB (1,048,576 bytes).\n     * Arrays larger than this will cause a KeeperException to be thrown.\n     *\n     * @param path\n     *                the path of the node\n     * @param data\n     *                the data to set\n     * @param version\n     *                the expected matching version\n     * @return the state of the node\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public Stat setData(final String path, byte data[], int version)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.setData);\n        SetDataRequest request = new SetDataRequest();\n        request.setPath(serverPath);\n        request.setData(data);\n        request.setVersion(version);\n        SetDataResponse response = new SetDataResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        return response.getStat();\n    }\n\n    /**\n     * The asynchronous version of setData.\n     *\n     * @see #setData(String, byte[], int)\n     */\n    public void setData(final String path, byte data[], int version,\n            StatCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.setData);\n        SetDataRequest request = new SetDataRequest();\n        request.setPath(serverPath);\n        request.setData(data);\n        request.setVersion(version);\n        SetDataResponse response = new SetDataResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, null);\n    }\n\n    /**\n     * Return the ACL and stat of the node of the given path.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @param path\n     *                the given path for the node\n     * @param stat\n     *                the stat of the node will be copied to this parameter if\n     *                not null.\n     * @return the ACL array of the given node.\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public List<ACL> getACL(final String path, Stat stat)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getACL);\n        GetACLRequest request = new GetACLRequest();\n        request.setPath(serverPath);\n        GetACLResponse response = new GetACLResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        if (stat != null) {\n            DataTree.copyStat(response.getStat(), stat);\n        }\n        return response.getAcl();\n    }\n\n    /**\n     * The asynchronous version of getACL.\n     *\n     * @see #getACL(String, Stat)\n     */\n    public void getACL(final String path, Stat stat, ACLCallback cb,\n            Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getACL);\n        GetACLRequest request = new GetACLRequest();\n        request.setPath(serverPath);\n        GetACLResponse response = new GetACLResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, null);\n    }\n\n    /**\n     * Set the ACL for the node of the given path if such a node exists and the\n     * given aclVersion matches the acl version of the node. Return the stat of the\n     * node.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     * <p>\n     * A KeeperException with error code KeeperException.BadVersion will be\n     * thrown if the given aclVersion does not match the node's aclVersion.\n     *\n     * @param path the given path for the node\n     * @param acl the given acl for the node\n     * @param aclVersion the given acl version of the node\n     * @return the stat of the node.\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     * @throws org.apache.zookeeper.KeeperException.InvalidACLException If the acl is invalide.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public Stat setACL(final String path, List<ACL> acl, int aclVersion)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.setACL);\n        SetACLRequest request = new SetACLRequest();\n        request.setPath(serverPath);\n        if (acl != null && acl.size() == 0) {\n            throw new KeeperException.InvalidACLException(clientPath);\n        }\n        request.setAcl(acl);\n        request.setVersion(aclVersion);\n        SetACLResponse response = new SetACLResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, null);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        return response.getStat();\n    }\n\n    /**\n     * The asynchronous version of setACL.\n     *\n     * @see #setACL(String, List, int)\n     */\n    public void setACL(final String path, List<ACL> acl, int version,\n            StatCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.setACL);\n        SetACLRequest request = new SetACLRequest();\n        request.setPath(serverPath);\n        request.setAcl(acl);\n        request.setVersion(version);\n        SetACLResponse response = new SetACLResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, null);\n    }\n\n    /**\n     * Return the list of the children of the node of the given path.\n     * <p>\n     * If the watch is non-null and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch willbe\n     * triggered by a successful operation that deletes the node of the given\n     * path or creates/delete a child under the node.\n     * <p>\n     * The list of children returned is not sorted and no guarantee is provided\n     * as to its natural or lexical order.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @param path\n     * @param watcher explicit watcher\n     * @return an unordered array of children of the node with the given path\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public List<String> getChildren(final String path, Watcher watcher)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ChildWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getChildren);\n        GetChildrenRequest request = new GetChildrenRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetChildrenResponse response = new GetChildrenResponse();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        return response.getChildren();\n    }\n\n    /**\n     * Return the list of the children of the node of the given path.\n     * <p>\n     * If the watch is true and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch willbe\n     * triggered by a successful operation that deletes the node of the given\n     * path or creates/delete a child under the node.\n     * <p>\n     * The list of children returned is not sorted and no guarantee is provided\n     * as to its natural or lexical order.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @param path\n     * @param watch\n     * @return an unordered array of children of the node with the given path\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     */\n    public List<String> getChildren(String path, boolean watch)\n            throws KeeperException, InterruptedException {\n        return getChildren(path, watch ? watchManager.defaultWatcher : null);\n    }\n\n    /**\n     * The asynchronous version of getChildren.\n     *\n     * @see #getChildren(String, Watcher)\n     */\n    public void getChildren(final String path, Watcher watcher,\n            ChildrenCallback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ChildWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getChildren);\n        GetChildrenRequest request = new GetChildrenRequest();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetChildrenResponse response = new GetChildrenResponse();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, wcb);\n    }\n\n    /**\n     * The asynchronous version of getChildren.\n     *\n     * @see #getChildren(String, boolean)\n     */\n    public void getChildren(String path, boolean watch, ChildrenCallback cb,\n            Object ctx)\n    {\n        getChildren(path, watch ? watchManager.defaultWatcher : null, cb, ctx);\n    }\n\n    /**\n     * For the given znode path return the stat and children list.\n     * <p>\n     * If the watch is non-null and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch willbe\n     * triggered by a successful operation that deletes the node of the given\n     * path or creates/delete a child under the node.\n     * <p>\n     * The list of children returned is not sorted and no guarantee is provided\n     * as to its natural or lexical order.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @since 3.3.0\n     * \n     * @param path\n     * @param watcher explicit watcher\n     * @param stat stat of the znode designated by path\n     * @return an unordered array of children of the node with the given path\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero error code.\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public List<String> getChildren(final String path, Watcher watcher,\n            Stat stat)\n        throws KeeperException, InterruptedException\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ChildWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getChildren2);\n        GetChildren2Request request = new GetChildren2Request();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetChildren2Response response = new GetChildren2Response();\n        ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);\n        if (r.getErr() != 0) {\n            throw KeeperException.create(KeeperException.Code.get(r.getErr()),\n                    clientPath);\n        }\n        if (stat != null) {\n            DataTree.copyStat(response.getStat(), stat);\n        }\n        return response.getChildren();\n    }\n\n    /**\n     * For the given znode path return the stat and children list.\n     * <p>\n     * If the watch is true and the call is successful (no exception is thrown),\n     * a watch will be left on the node with the given path. The watch willbe\n     * triggered by a successful operation that deletes the node of the given\n     * path or creates/delete a child under the node.\n     * <p>\n     * The list of children returned is not sorted and no guarantee is provided\n     * as to its natural or lexical order.\n     * <p>\n     * A KeeperException with error code KeeperException.NoNode will be thrown\n     * if no node with the given path exists.\n     *\n     * @since 3.3.0\n     * \n     * @param path\n     * @param watch\n     * @param stat stat of the znode designated by path\n     * @return an unordered array of children of the node with the given path\n     * @throws InterruptedException If the server transaction is interrupted.\n     * @throws KeeperException If the server signals an error with a non-zero\n     *  error code.\n     */\n    public List<String> getChildren(String path, boolean watch, Stat stat)\n            throws KeeperException, InterruptedException {\n        return getChildren(path, watch ? watchManager.defaultWatcher : null,\n                stat);\n    }\n\n    /**\n     * The asynchronous version of getChildren.\n     *\n     * @since 3.3.0\n     * \n     * @see #getChildren(String, Watcher, Stat)\n     */\n    public void getChildren(final String path, Watcher watcher,\n            Children2Callback cb, Object ctx)\n    {\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        // the watch contains the un-chroot path\n        WatchRegistration wcb = null;\n        if (watcher != null) {\n            wcb = new ChildWatchRegistration(watcher, clientPath);\n        }\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.getChildren2);\n        GetChildren2Request request = new GetChildren2Request();\n        request.setPath(serverPath);\n        request.setWatch(watcher != null);\n        GetChildren2Response response = new GetChildren2Response();\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, wcb);\n    }\n\n    /**\n     * The asynchronous version of getChildren.\n     *\n     * @since 3.3.0\n     * \n     * @see #getChildren(String, boolean, Stat)\n     */\n    public void getChildren(String path, boolean watch, Children2Callback cb,\n            Object ctx)\n    {\n        getChildren(path, watch ? watchManager.defaultWatcher : null, cb, ctx);\n    }\n\n    /**\n     * Asynchronous sync. Flushes channel between process and leader.\n     * @param path\n     * @param cb a handler for the callback\n     * @param ctx context to be provided to the callback\n     * @throws IllegalArgumentException if an invalid path is specified\n     */\n    public void sync(final String path, VoidCallback cb, Object ctx){\n        final String clientPath = path;\n        PathUtils.validatePath(clientPath);\n\n        final String serverPath = prependChroot(clientPath);\n\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.sync);\n        SyncRequest request = new SyncRequest();\n        SyncResponse response = new SyncResponse();\n        request.setPath(serverPath);\n        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,\n                clientPath, serverPath, ctx, null);\n    }\n\n    public States getState() {\n        return cnxn.getState();\n    }\n\n    /**\n     * String representation of this ZooKeeper client. Suitable for things\n     * like logging.\n     * \n     * Do NOT count on the format of this string, it may change without\n     * warning.\n     * \n     * @since 3.3.0\n     */\n    @Override\n    public String toString() {\n        States state = getState();\n        return (\"State:\" + state.toString()\n                + (state.isConnected() ?\n                        \" Timeout:\" + getSessionTimeout() + \" \" :\n                        \" \")\n                + cnxn);\n    }\n\n    /*\n     * Methods to aid in testing follow.\n     * \n     * THESE METHODS ARE EXPECTED TO BE USED FOR TESTING ONLY!!!\n     */\n\n    /**\n     * Wait up to wait milliseconds for the underlying threads to shutdown.\n     * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!!\n     * \n     * @since 3.3.0\n     * \n     * @param wait max wait in milliseconds\n     * @return true iff all threads are shutdown, otw false\n     */\n    protected boolean testableWaitForShutdown(int wait)\n        throws InterruptedException\n    {\n        cnxn.sendThread.join(wait);\n        if (cnxn.sendThread.isAlive()) return false;\n        cnxn.eventThread.join(wait);\n        if (cnxn.eventThread.isAlive()) return false;\n        return true;\n    }\n\n    /**\n     * Returns the address to which the socket is connected. Useful for testing\n     * against an ensemble - test client may need to know which server\n     * to shutdown if interested in verifying that the code handles\n     * disconnection/reconnection correctly.\n     * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!!\n     *\n     * @since 3.3.0\n     * \n     * @return ip address of the remote side of the connection or null if\n     *         not connected\n     */\n    protected SocketAddress testableRemoteSocketAddress() {\n        return cnxn.sendThread.getClientCnxnSocket().getRemoteSocketAddress();\n    }\n\n    /** \n     * Returns the local address to which the socket is bound.\n     * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!!\n     *\n     * @since 3.3.0\n     * \n     * @return ip address of the remote side of the connection or null if\n     *         not connected\n     */\n    protected SocketAddress testableLocalSocketAddress() {\n        return cnxn.sendThread.getClientCnxnSocket().getLocalSocketAddress();\n    }\n\n    private static ClientCnxnSocket getClientCnxnSocket() throws IOException {\n        String clientCnxnSocketName = System\n                .getProperty(ZOOKEEPER_CLIENT_CNXN_SOCKET);\n        if (clientCnxnSocketName == null) {\n            clientCnxnSocketName = ClientCnxnSocketNIO.class.getName();\n        }\n        try {\n            return (ClientCnxnSocket) Class.forName(clientCnxnSocketName).getDeclaredConstructor()\n                    .newInstance();\n        } catch (Exception e) {\n            IOException ioe = new IOException(\"Couldn't instantiate \"\n                    + clientCnxnSocketName);\n            ioe.initCause(e);\n            throw ioe;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/ZooKeeperMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.data.Stat;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * The command line client to ZooKeeper.\n *\n */\n@InterfaceAudience.Public\npublic class ZooKeeperMain {\n    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperMain.class);\n    static final Map<String,String> commandMap = new HashMap<String,String>( );\n\n    protected MyCommandOptions cl = new MyCommandOptions();\n    protected HashMap<Integer,String> history = new HashMap<Integer,String>( );\n    protected int commandCount = 0;\n    protected boolean printWatches = true;\n\n    protected ZooKeeper zk;\n    protected String host = \"\";\n\n    public boolean getPrintWatches( ) {\n        return printWatches;\n    }\n\n    static {\n        commandMap.put(\"connect\", \"host:port\");\n        commandMap.put(\"close\",\"\");\n        commandMap.put(\"create\", \"[-s] [-e] path data acl\");\n        commandMap.put(\"delete\",\"path [version]\");\n        commandMap.put(\"rmr\",\"path\");\n        commandMap.put(\"set\",\"path data [version]\");\n        commandMap.put(\"get\",\"path [watch]\");\n        commandMap.put(\"ls\",\"path [watch]\");\n        commandMap.put(\"ls2\",\"path [watch]\");\n        commandMap.put(\"getAcl\",\"path\");\n        commandMap.put(\"setAcl\",\"path acl\");\n        commandMap.put(\"stat\",\"path [watch]\");\n        commandMap.put(\"sync\",\"path\");\n        commandMap.put(\"setquota\",\"-n|-b val path\");\n        commandMap.put(\"listquota\",\"path\");\n        commandMap.put(\"delquota\",\"[-n|-b] path\");\n        commandMap.put(\"history\",\"\");\n        commandMap.put(\"redo\",\"cmdno\");\n        commandMap.put(\"printwatches\", \"on|off\");\n        commandMap.put(\"quit\",\"\");\n        commandMap.put(\"addauth\", \"scheme auth\");\n    }\n\n    static void usage() {\n        System.err.println(\"ZooKeeper -server host:port cmd args\");\n        for (Map.Entry<String, String> entry : commandMap.entrySet()) {\n            System.err.println(\"\\t\" + entry.getKey() + \" \" + entry.getValue());\n        }\n    }\n\n    private class MyWatcher implements Watcher {\n        public void process(WatchedEvent event) {\n            if (getPrintWatches()) {\n                ZooKeeperMain.printMessage(\"WATCHER::\");\n                ZooKeeperMain.printMessage(event.toString());\n            }\n        }\n    }\n\n    static private int getPermFromString(String permString) {\n        int perm = 0;\n        for (int i = 0; i < permString.length(); i++) {\n            switch (permString.charAt(i)) {\n            case 'r':\n                perm |= ZooDefs.Perms.READ;\n                break;\n            case 'w':\n                perm |= ZooDefs.Perms.WRITE;\n                break;\n            case 'c':\n                perm |= ZooDefs.Perms.CREATE;\n                break;\n            case 'd':\n                perm |= ZooDefs.Perms.DELETE;\n                break;\n            case 'a':\n                perm |= ZooDefs.Perms.ADMIN;\n                break;\n            default:\n                System.err\n                .println(\"Unknown perm type: \" + permString.charAt(i));\n            }\n        }\n        return perm;\n    }\n\n    private static void printStat(Stat stat) {\n        System.err.println(\"cZxid = 0x\" + Long.toHexString(stat.getCzxid()));\n        System.err.println(\"ctime = \" + new Date(stat.getCtime()).toString());\n        System.err.println(\"mZxid = 0x\" + Long.toHexString(stat.getMzxid()));\n        System.err.println(\"mtime = \" + new Date(stat.getMtime()).toString());\n        System.err.println(\"pZxid = 0x\" + Long.toHexString(stat.getPzxid()));\n        System.err.println(\"cversion = \" + stat.getCversion());\n        System.err.println(\"dataVersion = \" + stat.getVersion());\n        System.err.println(\"aclVersion = \" + stat.getAversion());\n        System.err.println(\"ephemeralOwner = 0x\"\n        \t\t+ Long.toHexString(stat.getEphemeralOwner()));\n        System.err.println(\"dataLength = \" + stat.getDataLength());\n        System.err.println(\"numChildren = \" + stat.getNumChildren());\n    }\n\n    /**\n     * A storage class for both command line options and shell commands.\n     *\n     */\n    static class MyCommandOptions {\n\n        private Map<String,String> options = new HashMap<String,String>();\n        private List<String> cmdArgs = null;\n        private String command = null;\n        public static final Pattern ARGS_PATTERN = Pattern.compile(\"\\\\s*([^\\\"\\']\\\\S*|\\\"[^\\\"]*\\\"|'[^']*')\\\\s*\");\n        public static final Pattern QUOTED_PATTERN = Pattern.compile(\"^([\\'\\\"])(.*)(\\\\1)$\");\n\n        public MyCommandOptions() {\n          options.put(\"server\", \"localhost:2181\");\n          options.put(\"timeout\", \"30000\");\n        }\n\n        public String getOption(String opt) {\n            return options.get(opt);\n        }\n\n        public String getCommand( ) {\n            return command;\n        }\n\n        public String getCmdArgument( int index ) {\n            return cmdArgs.get(index);\n        }\n\n        public int getNumArguments( ) {\n            return cmdArgs.size();\n        }\n\n        public String[] getArgArray() {\n            return cmdArgs.toArray(new String[0]);\n        }\n\n        /**\n         * Parses a command line that may contain one or more flags\n         * before an optional command string\n         * @param args command line arguments\n         * @return true if parsing succeeded, false otherwise.\n         */\n        public boolean parseOptions(String[] args) {\n            List<String> argList = Arrays.asList(args);\n            Iterator<String> it = argList.iterator();\n\n            while (it.hasNext()) {\n                String opt = it.next();\n                try {\n                    if (opt.equals(\"-server\")) {\n                        options.put(\"server\", it.next());\n                    } else if (opt.equals(\"-timeout\")) {\n                        options.put(\"timeout\", it.next());\n                    } else if (opt.equals(\"-r\")) {\n                        options.put(\"readonly\", \"true\");\n                    }\n                } catch (NoSuchElementException e){\n                    System.err.println(\"Error: no argument found for option \"\n                            + opt);\n                    return false;\n                }\n\n                if (!opt.startsWith(\"-\")) {\n                    command = opt;\n                    cmdArgs = new ArrayList<String>( );\n                    cmdArgs.add( command );\n                    while (it.hasNext()) {\n                        cmdArgs.add(it.next());\n                    }\n                    return true;\n                }\n            }\n            return true;\n        }\n\n        /**\n         * Breaks a string into command + arguments.\n         * @param cmdstring string of form \"cmd arg1 arg2..etc\"\n         * @return true if parsing succeeded.\n         */\n        public boolean parseCommand( String cmdstring ) {\n            Matcher matcher = ARGS_PATTERN.matcher(cmdstring);\n\n            List<String> args = new LinkedList<String>();\n            while (matcher.find()) {\n                String value = matcher.group(1);\n                if (QUOTED_PATTERN.matcher(value).matches()) {\n                    // Strip off the surrounding quotes\n                    value = value.substring(1, value.length() - 1);\n                }\n                args.add(value);\n            }\n            if (args.isEmpty()){\n                return false;\n            }\n            command = args.get(0);\n            cmdArgs = args;\n            return true;\n        }\n    }\n\n\n    /**\n     * Makes a list of possible completions, either for commands\n     * or for zk nodes if the token to complete begins with /\n     *\n     */\n\n\n    protected void addToHistory(int i,String cmd) {\n        history.put(i, cmd);\n    }\n\n    public static List<String> getCommands() {\n        return new LinkedList<String>(commandMap.keySet());\n    }\n\n    protected String getPrompt() {       \n        return \"[zk: \" + host + \"(\"+zk.getState()+\")\" + \" \" + commandCount + \"] \";\n    }\n\n    public static void printMessage(String msg) {\n        System.out.println(\"\\n\"+msg);\n    }\n\n    protected void connectToZK(String newHost) throws InterruptedException, IOException {\n        if (zk != null && zk.getState().isAlive()) {\n            zk.close();\n        }\n        host = newHost;\n        boolean readOnly = cl.getOption(\"readonly\") != null;\n        zk = new ZooKeeper(host,\n                 Integer.parseInt(cl.getOption(\"timeout\")),\n                 new MyWatcher(), readOnly);\n    }\n    \n    public static void main(String args[])\n        throws KeeperException, IOException, InterruptedException\n    {\n        ZooKeeperMain main = new ZooKeeperMain(args);\n        main.run();\n    }\n\n    public ZooKeeperMain(String args[]) throws IOException, InterruptedException {\n        cl.parseOptions(args);\n        System.out.println(\"Connecting to \" + cl.getOption(\"server\"));\n        connectToZK(cl.getOption(\"server\"));\n        //zk = new ZooKeeper(cl.getOption(\"server\"),\n//                Integer.parseInt(cl.getOption(\"timeout\")), new MyWatcher());\n    }\n\n    public ZooKeeperMain(ZooKeeper zk) {\n      this.zk = zk;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    void run() throws KeeperException, IOException, InterruptedException {\n        if (cl.getCommand() == null) {\n            System.out.println(\"Welcome to ZooKeeper!\");\n\n            boolean jlinemissing = false;\n            // only use jline if it's in the classpath\n            try {\n                Class<?> consoleC = Class.forName(\"jline.ConsoleReader\");\n                Class<?> completorC =\n                    Class.forName(\"org.apache.zookeeper.JLineZNodeCompletor\");\n\n                System.out.println(\"JLine support is enabled\");\n\n                Object console =\n                    consoleC.getConstructor().newInstance();\n\n                Object completor =\n                    completorC.getConstructor(ZooKeeper.class).newInstance(zk);\n                Method addCompletor = consoleC.getMethod(\"addCompletor\",\n                        Class.forName(\"jline.Completor\"));\n                addCompletor.invoke(console, completor);\n\n                String line;\n                Method readLine = consoleC.getMethod(\"readLine\", String.class);\n                while ((line = (String)readLine.invoke(console, getPrompt())) != null) {\n                    executeLine(line);\n                }\n            } catch (ClassNotFoundException e) {\n                LOG.debug(\"Unable to start jline\", e);\n                jlinemissing = true;\n            } catch (NoSuchMethodException e) {\n                LOG.debug(\"Unable to start jline\", e);\n                jlinemissing = true;\n            } catch (InvocationTargetException e) {\n                LOG.debug(\"Unable to start jline\", e);\n                jlinemissing = true;\n            } catch (IllegalAccessException e) {\n                LOG.debug(\"Unable to start jline\", e);\n                jlinemissing = true;\n            } catch (InstantiationException e) {\n                LOG.debug(\"Unable to start jline\", e);\n                jlinemissing = true;\n            }\n\n            if (jlinemissing) {\n                System.out.println(\"JLine support is disabled\");\n                BufferedReader br =\n                    new BufferedReader(new InputStreamReader(System.in));\n\n                String line;\n                while ((line = br.readLine()) != null) {\n                    executeLine(line);\n                }\n            }\n        } else {\n            // Command line args non-null.  Run what was passed.\n            processCmd(cl);\n        }\n    }\n\n    public void executeLine(String line)\n    throws InterruptedException, IOException, KeeperException {\n      if (!line.equals(\"\")) {\n        cl.parseCommand(line);\n        addToHistory(commandCount,line);\n        processCmd(cl);\n        commandCount++;\n      }\n    }\n\n    private static DataCallback dataCallback = new DataCallback() {\n\n        public void processResult(int rc, String path, Object ctx, byte[] data,\n                Stat stat) {\n            System.out.println(\"rc = \" + rc + \" path = \" + path + \" data = \"\n                    + (data == null ? \"null\" : new String(data)) + \" stat = \");\n            printStat(stat);\n        }\n\n    };\n\n    /**\n     * trim the quota tree to recover unwanted tree elements\n     * in the quota's tree\n     * @param zk the zookeeper client\n     * @param path the path to start from and go up and see if their\n     * is any unwanted parent in the path.\n     * @return true if sucessful\n     * @throws KeeperException\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    private static boolean trimProcQuotas(ZooKeeper zk, String path)\n        throws KeeperException, IOException, InterruptedException\n    {\n        if (Quotas.quotaZookeeper.equals(path)) {\n            return true;\n        }\n        List<String> children = zk.getChildren(path, false);\n        if (children.size() == 0) {\n            zk.delete(path, -1);\n            String parent = path.substring(0, path.lastIndexOf('/'));\n            return trimProcQuotas(zk, parent);\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * this method deletes quota for a node.\n     * @param zk the zookeeper client\n     * @param path the path to delete quota for\n     * @param bytes true if number of bytes needs to\n     * be unset\n     * @param numNodes true if number of nodes needs\n     * to be unset\n     * @return true if quota deletion is successful\n     * @throws KeeperException\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    public static boolean delQuota(ZooKeeper zk, String path,\n            boolean bytes, boolean numNodes)\n        throws KeeperException, IOException, InterruptedException\n    {\n        String parentPath = Quotas.quotaZookeeper + path;\n        String quotaPath = Quotas.quotaZookeeper + path + \"/\" + Quotas.limitNode;\n        if (zk.exists(quotaPath, false) == null) {\n            System.out.println(\"Quota does not exist for \" + path);\n            return true;\n        }\n        byte[] data = null;\n        try {\n            data = zk.getData(quotaPath, false, new Stat());\n        } catch(KeeperException.NoNodeException ne) {\n            System.err.println(\"quota does not exist for \" + path);\n            return true;\n        }\n        StatsTrack strack = new StatsTrack(new String(data));\n        if (bytes && !numNodes) {\n            strack.setBytes(-1L);\n            zk.setData(quotaPath, strack.toString().getBytes(), -1);\n        } else if (!bytes && numNodes) {\n            strack.setCount(-1);\n            zk.setData(quotaPath, strack.toString().getBytes(), -1);\n        } else if (bytes && numNodes) {\n            // delete till you can find a node with more than\n            // one child\n            List<String> children = zk.getChildren(parentPath, false);\n            /// delete the direct children first\n            for (String child: children) {\n                zk.delete(parentPath + \"/\" + child, -1);\n            }\n            // cut the tree till their is more than one child\n            trimProcQuotas(zk, parentPath);\n        }\n        return true;\n    }\n\n    private static void checkIfParentQuota(ZooKeeper zk, String path)\n        throws InterruptedException, KeeperException\n    {\n        final String[] splits = path.split(\"/\");\n        String quotaPath = Quotas.quotaZookeeper;\n        for (String str: splits) {\n            if (str.length() == 0) {\n                // this should only be for the beginning of the path\n                // i.e. \"/...\" - split(path)[0] is empty string before first '/'\n                continue;\n            }\n            quotaPath += \"/\" + str;\n            List<String> children =  null;\n            try {\n                children = zk.getChildren(quotaPath, false);\n            } catch(KeeperException.NoNodeException ne) {\n                LOG.debug(\"child removed during quota check\", ne);\n                return;\n            }\n            if (children.size() == 0) {\n                return;\n            }\n            for (String child: children) {\n                if (Quotas.limitNode.equals(child)) {\n                    throw new IllegalArgumentException(path + \" has a parent \"\n                            + quotaPath + \" which has a quota\");\n                }\n            }\n        }\n    }\n\n    /**\n     * this method creates a quota node for the path\n     * @param zk the ZooKeeper client\n     * @param path the path for which quota needs to be created\n     * @param bytes the limit of bytes on this path\n     * @param numNodes the limit of number of nodes on this path\n     * @return true if its successful and false if not.\n     */\n    public static boolean createQuota(ZooKeeper zk, String path,\n            long bytes, int numNodes)\n        throws KeeperException, IOException, InterruptedException\n    {\n        // check if the path exists. We cannot create\n        // quota for a path that already exists in zookeeper\n        // for now.\n        Stat initStat = zk.exists(path, false);\n        if (initStat == null) {\n            throw new IllegalArgumentException(path + \" does not exist.\");\n        }\n        // now check if their is already existing\n        // parent or child that has quota\n\n        String quotaPath = Quotas.quotaZookeeper;\n        // check for more than 2 children --\n        // if zookeeper_stats and zookeeper_qutoas\n        // are not the children then this path\n        // is an ancestor of some path that\n        // already has quota\n        String realPath = Quotas.quotaZookeeper + path;\n        try {\n            List<String> children = zk.getChildren(realPath, false);\n            for (String child: children) {\n                if (!child.startsWith(\"zookeeper_\")) {\n                    throw new IllegalArgumentException(path + \" has child \" +\n                            child + \" which has a quota\");\n                }\n            }\n        } catch(KeeperException.NoNodeException ne) {\n            // this is fine\n        }\n\n        //check for any parent that has been quota\n        checkIfParentQuota(zk, path);\n\n        // this is valid node for quota\n        // start creating all the parents\n        if (zk.exists(quotaPath, false) == null) {\n            try {\n                zk.create(Quotas.procZookeeper, null, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n                zk.create(Quotas.quotaZookeeper, null, Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            } catch(KeeperException.NodeExistsException ne) {\n                // do nothing\n            }\n        }\n\n        // now create the direct children\n        // and the stat and quota nodes\n        String[] splits = path.split(\"/\");\n        StringBuilder sb = new StringBuilder();\n        sb.append(quotaPath);\n        for (int i=1; i<splits.length; i++) {\n            sb.append(\"/\" + splits[i]);\n            quotaPath = sb.toString();\n            try {\n                zk.create(quotaPath, null, Ids.OPEN_ACL_UNSAFE ,\n                        CreateMode.PERSISTENT);\n            } catch(KeeperException.NodeExistsException ne) {\n                //do nothing\n            }\n        }\n        String statPath = quotaPath + \"/\" + Quotas.statNode;\n        quotaPath = quotaPath + \"/\" + Quotas.limitNode;\n        StatsTrack strack = new StatsTrack(null);\n        strack.setBytes(bytes);\n        strack.setCount(numNodes);\n        try {\n            zk.create(quotaPath, strack.toString().getBytes(),\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            StatsTrack stats = new StatsTrack(null);\n            stats.setBytes(0L);\n            stats.setCount(0);\n            zk.create(statPath, stats.toString().getBytes(),\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(KeeperException.NodeExistsException ne) {\n            byte[] data = zk.getData(quotaPath, false , new Stat());\n            StatsTrack strackC = new StatsTrack(new String(data));\n            if (bytes != -1L) {\n                strackC.setBytes(bytes);\n            }\n            if (numNodes != -1) {\n                strackC.setCount(numNodes);\n            }\n            zk.setData(quotaPath, strackC.toString().getBytes(), -1);\n        }\n        return true;\n    }\n\n    protected boolean processCmd(MyCommandOptions co)\n        throws KeeperException, IOException, InterruptedException\n    {\n        try {\n            return processZKCmd(co);\n        } catch (IllegalArgumentException e) {\n            System.err.println(\"Command failed: \" + e);\n        } catch (KeeperException.NoNodeException e) {\n            System.err.println(\"Node does not exist: \" + e.getPath());\n        } catch (KeeperException.NoChildrenForEphemeralsException e) {\n            System.err.println(\"Ephemerals cannot have children: \"\n                    + e.getPath());\n        } catch (KeeperException.NodeExistsException e) {\n            System.err.println(\"Node already exists: \" + e.getPath());\n        } catch (KeeperException.NotEmptyException e) {\n            System.err.println(\"Node not empty: \" + e.getPath());\n        } catch (KeeperException.NotReadOnlyException e) {\n            System.err.println(\"Not a read-only call: \" + e.getPath());\n        }catch (KeeperException.InvalidACLException  e) {\n            System.err.println(\"Acl is not valid : \"+e.getPath());\n        }catch (KeeperException.NoAuthException  e) {\n            System.err.println(\"Authentication is not valid : \"+e.getPath());\n        }catch (KeeperException.BadArgumentsException   e) {\n            System.err.println(\"Arguments are not valid : \"+e.getPath());\n        }catch (KeeperException.BadVersionException e) {\n            System.err.println(\"version No is not valid : \"+e.getPath());\n        }\n        return false;\n    }\n\n    protected boolean processZKCmd(MyCommandOptions co)\n        throws KeeperException, IOException, InterruptedException\n    {\n        Stat stat = new Stat();\n        String[] args = co.getArgArray();\n        String cmd = co.getCommand();\n        if (args.length < 1) {\n            usage();\n            return false;\n        }\n\n        if (!commandMap.containsKey(cmd)) {\n            usage();\n            return false;\n        }\n        \n        boolean watch = args.length > 2;\n        String path = null;\n        List<ACL> acl = Ids.OPEN_ACL_UNSAFE;\n        LOG.debug(\"Processing \" + cmd);\n\n        if (cmd.equals(\"quit\")) {\n            System.out.println(\"Quitting...\");\n            zk.close();\n            System.exit(0);\n        } else if (cmd.equals(\"redo\") && args.length >= 2) {\n            Integer i = Integer.decode(args[1]);\n            if (commandCount <= i || i < 0){ // don't allow redoing this redo\n                System.out.println(\"Command index out of range\");\n                return false;\n            }\n            cl.parseCommand(history.get(i));\n            if (cl.getCommand().equals( \"redo\" )){\n                System.out.println(\"No redoing redos\");\n                return false;\n            }\n            history.put(commandCount, history.get(i));\n            processCmd( cl);\n        } else if (cmd.equals(\"history\")) {\n            for (int i=commandCount - 10;i<=commandCount;++i) {\n                if (i < 0) continue;\n                System.out.println(i + \" - \" + history.get(i));\n            }\n        } else if (cmd.equals(\"printwatches\")) {\n            if (args.length == 1) {\n                System.out.println(\"printwatches is \" + (printWatches ? \"on\" : \"off\"));\n            } else {\n                printWatches = args[1].equals(\"on\");\n            }\n        } else if (cmd.equals(\"connect\")) {\n            if (args.length >=2) {\n                connectToZK(args[1]);\n            } else {\n                connectToZK(host);\n            }\n        }\n        \n        // Below commands all need a live connection\n        if (zk == null || !zk.getState().isAlive()) {\n            System.out.println(\"Not connected\");\n            return false;\n        }\n        \n        if (cmd.equals(\"create\") && args.length >= 3) {\n            int first = 0;\n            CreateMode flags = CreateMode.PERSISTENT;\n            if ((args[1].equals(\"-e\") && args[2].equals(\"-s\"))\n                    || (args[1]).equals(\"-s\") && (args[2].equals(\"-e\"))) {\n                first+=2;\n                flags = CreateMode.EPHEMERAL_SEQUENTIAL;\n            } else if (args[1].equals(\"-e\")) {\n                first++;\n                flags = CreateMode.EPHEMERAL;\n            } else if (args[1].equals(\"-s\")) {\n                first++;\n                flags = CreateMode.PERSISTENT_SEQUENTIAL;\n            }\n            if (args.length == first + 4) {\n                acl = parseACLs(args[first+3]);\n            }\n            path = args[first + 1];\n            String newPath = zk.create(path, args[first+2].getBytes(), acl,\n                    flags);\n            System.err.println(\"Created \" + newPath);\n        } else if (cmd.equals(\"delete\") && args.length >= 2) {\n            path = args[1];\n            zk.delete(path, watch ? Integer.parseInt(args[2]) : -1);\n        } else if (cmd.equals(\"rmr\") && args.length >= 2) {\n            path = args[1];\n            ZKUtil.deleteRecursive(zk, path);\n        } else if (cmd.equals(\"set\") && args.length >= 3) {\n            path = args[1];\n            stat = zk.setData(path, args[2].getBytes(),\n                    args.length > 3 ? Integer.parseInt(args[3]) : -1);\n            printStat(stat);\n        } else if (cmd.equals(\"aget\") && args.length >= 2) {\n            path = args[1];\n            zk.getData(path, watch, dataCallback, path);\n        } else if (cmd.equals(\"get\") && args.length >= 2) {\n            path = args[1];\n            byte data[] = zk.getData(path, watch, stat);\n            data = (data == null)? \"null\".getBytes() : data;\n            System.out.println(new String(data));\n            printStat(stat);\n        } else if (cmd.equals(\"ls\") && args.length >= 2) {\n            path = args[1];\n            List<String> children = zk.getChildren(path, watch);\n            System.out.println(children);\n        } else if (cmd.equals(\"ls2\") && args.length >= 2) {\n            path = args[1];\n            List<String> children = zk.getChildren(path, watch, stat);\n            System.out.println(children);\n            printStat(stat);\n        } else if (cmd.equals(\"getAcl\") && args.length >= 2) {\n            path = args[1];\n            acl = zk.getACL(path, stat);\n            for (ACL a : acl) {\n                System.out.println(a.getId() + \": \"\n                        + getPermString(a.getPerms()));\n            }\n        } else if (cmd.equals(\"setAcl\") && args.length >= 3) {\n            path = args[1];\n            stat = zk.setACL(path, parseACLs(args[2]),\n                    args.length > 4 ? Integer.parseInt(args[3]) : -1);\n            printStat(stat);\n        } else if (cmd.equals(\"stat\") && args.length >= 2) {\n            path = args[1];\n            stat = zk.exists(path, watch);\n            if (stat == null) {\n              throw new KeeperException.NoNodeException(path);\n            }\n            printStat(stat);\n        } else if (cmd.equals(\"listquota\") && args.length >= 2) {\n            path = args[1];\n            String absolutePath = Quotas.quotaZookeeper + path + \"/\" + Quotas.limitNode;\n            byte[] data =  null;\n            try {\n                System.err.println(\"absolute path is \" + absolutePath);\n                data = zk.getData(absolutePath, false, stat);\n                StatsTrack st = new StatsTrack(new String(data));\n                System.out.println(\"Output quota for \" + path + \" \"\n                        + st.toString());\n\n                data = zk.getData(Quotas.quotaZookeeper + path + \"/\" +\n                        Quotas.statNode, false, stat);\n                System.out.println(\"Output stat for \" + path + \" \" +\n                        new StatsTrack(new String(data)).toString());\n            } catch(KeeperException.NoNodeException ne) {\n                System.err.println(\"quota for \" + path + \" does not exist.\");\n            }\n        } else if (cmd.equals(\"setquota\") && args.length >= 4) {\n            String option = args[1];\n            String val = args[2];\n            path = args[3];\n            System.err.println(\"Comment: the parts are \" +\n                               \"option \" + option +\n                               \" val \" + val +\n                               \" path \" + path);\n            if (\"-b\".equals(option)) {\n                // we are setting the bytes quota\n                createQuota(zk, path, Long.parseLong(val), -1);\n            } else if (\"-n\".equals(option)) {\n                // we are setting the num quota\n                createQuota(zk, path, -1L, Integer.parseInt(val));\n            } else {\n                usage();\n            }\n\n        } else if (cmd.equals(\"delquota\") && args.length >= 2) {\n            //if neither option -n or -b is specified, we delete\n            // the quota node for thsi node.\n            if (args.length == 3) {\n                //this time we have an option\n                String option = args[1];\n                path = args[2];\n                if (\"-b\".equals(option)) {\n                    delQuota(zk, path, true, false);\n                } else if (\"-n\".equals(option)) {\n                    delQuota(zk, path, false, true);\n                }\n            } else if (args.length == 2) {\n                path = args[1];\n                // we dont have an option specified.\n                // just delete whole quota node\n                delQuota(zk, path, true, true);\n            } else if (cmd.equals(\"help\")) {\n                usage();\n            }\n        } else if (cmd.equals(\"close\")) {\n                zk.close();\n        } else if (cmd.equals(\"sync\") && args.length >= 2) {\n            path = args[1];\n            zk.sync(path, new AsyncCallback.VoidCallback() { public void processResult(int rc, String path, Object ctx) { System.out.println(\"Sync returned \" + rc); } }, null );\n        } else if (cmd.equals(\"addauth\") && args.length >=2 ) {\n            byte[] b = null;\n            if (args.length >= 3)\n                b = args[2].getBytes();\n\n            zk.addAuthInfo(args[1], b);\n        } else if (!commandMap.containsKey(cmd)) {\n            usage();\n        }\n        return watch;\n    }\n\n    private static String getPermString(int perms) {\n        StringBuilder p = new StringBuilder();\n        if ((perms & ZooDefs.Perms.CREATE) != 0) {\n            p.append('c');\n        }\n        if ((perms & ZooDefs.Perms.DELETE) != 0) {\n            p.append('d');\n        }\n        if ((perms & ZooDefs.Perms.READ) != 0) {\n            p.append('r');\n        }\n        if ((perms & ZooDefs.Perms.WRITE) != 0) {\n            p.append('w');\n        }\n        if ((perms & ZooDefs.Perms.ADMIN) != 0) {\n            p.append('a');\n        }\n        return p.toString();\n    }\n\n    private static List<ACL> parseACLs(String aclString) {\n        List<ACL> acl;\n        String acls[] = aclString.split(\",\");\n        acl = new ArrayList<ACL>();\n        for (String a : acls) {\n            int firstColon = a.indexOf(':');\n            int lastColon = a.lastIndexOf(':');\n            if (firstColon == -1 || lastColon == -1 || firstColon == lastColon) {\n                System.err\n                .println(a + \" does not have the form scheme:id:perm\");\n                continue;\n            }\n            ACL newAcl = new ACL();\n            newAcl.setId(new Id(a.substring(0, firstColon), a.substring(\n                    firstColon + 1, lastColon)));\n            newAcl.setPerms(getPermFromString(a.substring(lastColon + 1)));\n            acl.add(newAcl);\n        }\n        return acl;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/client/ConnectStringParser.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.client;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\n\nimport org.apache.zookeeper.common.PathUtils;\n\n/**\n * A parser for ZooKeeper Client connect strings.\n * \n * This class is not meant to be seen or used outside of ZooKeeper itself.\n * \n * The chrootPath member should be replaced by a Path object in issue\n * ZOOKEEPER-849.\n * \n * @see org.apache.zookeeper.ZooKeeper\n */\npublic final class ConnectStringParser {\n    private static final int DEFAULT_PORT = 2181;\n\n    private final String chrootPath;\n\n    private final ArrayList<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>();\n\n    /**\n     * \n     * @throws IllegalArgumentException\n     *             for an invalid chroot path.\n     */\n    public ConnectStringParser(String connectString) {\n        // parse out chroot, if any\n        int off = connectString.indexOf('/');\n        if (off >= 0) {\n            String chrootPath = connectString.substring(off);\n            // ignore \"/\" chroot spec, same as null\n            if (chrootPath.length() == 1) {\n                this.chrootPath = null;\n            } else {\n                PathUtils.validatePath(chrootPath);\n                this.chrootPath = chrootPath;\n            }\n            connectString = connectString.substring(0, off);\n        } else {\n            this.chrootPath = null;\n        }\n\n        String hostsList[] = connectString.split(\",\");\n        for (String host : hostsList) {\n            int port = DEFAULT_PORT;\n            int pidx = host.lastIndexOf(':');\n            if (pidx >= 0) {\n                // otherwise : is at the end of the string, ignore\n                if (pidx < host.length() - 1) {\n                    port = Integer.parseInt(host.substring(pidx + 1));\n                }\n                host = host.substring(0, pidx);\n            }\n            serverAddresses.add(InetSocketAddress.createUnresolved(host, port));\n        }\n    }\n\n    public String getChrootPath() {\n        return chrootPath;\n    }\n\n    public ArrayList<InetSocketAddress> getServerAddresses() {\n        return serverAddresses;\n    }\n}"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/client/FourLetterWordMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.client;\n\nimport org.apache.log4j.Logger;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\n\nimport org.apache.yetus.audience.InterfaceAudience;\n\n@InterfaceAudience.Public\npublic class FourLetterWordMain {\n    //in milliseconds, socket should connect/read within this period otherwise SocketTimeoutException\n    private static final int DEFAULT_SOCKET_TIMEOUT = 5000;\n    protected static final Logger LOG = Logger.getLogger(FourLetterWordMain.class);\n\n    /**\n     * Send the 4letterword\n     * @param host the destination host\n     * @param port the destination port\n     * @param cmd the 4letterword\n     * @return server response\n     * @throws java.io.IOException\n     */\n    public static String send4LetterWord(String host, int port, String cmd)\n            throws IOException\n    {\n        return send4LetterWord(host, port, cmd, DEFAULT_SOCKET_TIMEOUT);\n    }\n    /**\n     * Send the 4letterword\n     * @param host the destination host\n     * @param port the destination port\n     * @param cmd the 4letterword\n     * @param timeout in milliseconds, maximum time to wait while connecting/reading data\n     * @return server response\n     * @throws java.io.IOException\n     */\n    public static String send4LetterWord(String host, int port, String cmd, int timeout)\n            throws IOException\n    {\n        LOG.info(\"connecting to \" + host + \" \" + port);\n        Socket sock = new Socket();\n        InetSocketAddress hostaddress= host != null ? new InetSocketAddress(host, port) :\n            new InetSocketAddress(InetAddress.getByName(null), port);\n        BufferedReader reader = null;\n        try {\n            sock.setSoTimeout(timeout);\n            sock.connect(hostaddress, timeout);\n            OutputStream outstream = sock.getOutputStream();\n            outstream.write(cmd.getBytes());\n            outstream.flush();\n            // this replicates NC - close the output stream before reading\n            sock.shutdownOutput();\n\n            reader =\n                    new BufferedReader(\n                            new InputStreamReader(sock.getInputStream()));\n            StringBuilder sb = new StringBuilder();\n            String line;\n            while((line = reader.readLine()) != null) {\n                sb.append(line + \"\\n\");\n            }\n            return sb.toString();\n        } catch (SocketTimeoutException e) {\n            throw new IOException(\"Exception while executing four letter word: \" + cmd, e);\n        } finally {\n            sock.close();\n            if (reader != null) {\n                reader.close();\n            }\n        }\n    }\n    \n    public static void main(String[] args)\n            throws IOException\n    {\n        if (args.length != 3) {\n            System.out.println(\"Usage: FourLetterWordMain <host> <port> <cmd>\");\n        } else {\n            System.out.println(send4LetterWord(args[0], Integer.parseInt(args[1]), args[2]));\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/client/HostProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.client;\n\nimport org.apache.yetus.audience.InterfaceAudience;\n\nimport java.net.InetSocketAddress;\n\n/**\n * A set of hosts a ZooKeeper client should connect to.\n * \n * Classes implementing this interface must guarantee the following:\n * \n * * Every call to next() returns an InetSocketAddress. So the iterator never\n * ends.\n * \n * * The size() of a HostProvider may never be zero.\n * \n * A HostProvider must return resolved InetSocketAddress instances on next(),\n * but it's up to the HostProvider, when it wants to do the resolving.\n * \n * Different HostProvider could be imagined:\n * \n * * A HostProvider that loads the list of Hosts from an URL or from DNS \n * * A HostProvider that re-resolves the InetSocketAddress after a timeout. \n * * A HostProvider that prefers nearby hosts.\n */\n@InterfaceAudience.Public\npublic interface HostProvider {\n    public int size();\n\n    /**\n     * The next host to try to connect to.\n     * \n     * For a spinDelay of 0 there should be no wait.\n     * \n     * @param spinDelay\n     *            Milliseconds to wait if all hosts have been tried once.\n     */\n    public InetSocketAddress next(long spinDelay);\n\n    /**\n     * Notify the HostProvider of a successful connection.\n     * \n     * The HostProvider may use this notification to reset it's inner state.\n     */\n    public void onConnected();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/client/StaticHostProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.client;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * Most simple HostProvider, resolves only on instantiation.\n * \n */\n@InterfaceAudience.Public\npublic final class StaticHostProvider implements HostProvider {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(StaticHostProvider.class);\n\n    private final List<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>(\n            5);\n\n    private int lastIndex = -1;\n\n    private int currentIndex = -1;\n\n    /**\n     * Constructs a SimpleHostSet.\n     * \n     * @param serverAddresses\n     *            possibly unresolved ZooKeeper server addresses\n     * @throws IllegalArgumentException\n     *             if serverAddresses is empty or resolves to an empty list\n     */\n    public StaticHostProvider(Collection<InetSocketAddress> serverAddresses) {\n        for (InetSocketAddress address : serverAddresses) {\n            try {\n                InetAddress ia = address.getAddress();\n                InetAddress resolvedAddresses[] = InetAddress.getAllByName((ia != null) ? ia.getHostAddress() :\n                        address.getHostName());\n                for (InetAddress resolvedAddress : resolvedAddresses) {\n                    // If hostName is null but the address is not, we can tell that\n                    // the hostName is an literal IP address. Then we can set the host string as the hostname\n                    // safely to avoid reverse DNS lookup.\n                    // As far as i know, the only way to check if the hostName is null is use toString().\n                    // Both the two implementations of InetAddress are final class, so we can trust the return value of\n                    // the toString() method.\n                    if (resolvedAddress.toString().startsWith(\"/\")\n                            && resolvedAddress.getAddress() != null) {\n                        this.serverAddresses.add(\n                                new InetSocketAddress(InetAddress.getByAddress(\n                                        address.getHostName(),\n                                        resolvedAddress.getAddress()),\n                                        address.getPort()));\n                    } else {\n                        this.serverAddresses.add(new InetSocketAddress(resolvedAddress.getHostAddress(), address.getPort()));\n                    }\n                }\n            } catch (UnknownHostException e) {\n                LOG.error(\"Unable to connect to server: {}\", address, e);\n            }\n        }\n        \n        if (this.serverAddresses.isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"A HostProvider may not be empty!\");\n        }\n        Collections.shuffle(this.serverAddresses);\n    }\n\n    public int size() {\n        return serverAddresses.size();\n    }\n\n    public InetSocketAddress next(long spinDelay) {\n        ++currentIndex;\n        if (currentIndex == serverAddresses.size()) {\n            currentIndex = 0;\n        }\n        if (currentIndex == lastIndex && spinDelay > 0) {\n            try {\n                Thread.sleep(spinDelay);\n            } catch (InterruptedException e) {\n                LOG.warn(\"Unexpected exception\", e);\n            }\n        } else if (lastIndex == -1) {\n            // We don't want to sleep on the first ever connect attempt.\n            lastIndex = 0;\n        }\n\n        return serverAddresses.get(currentIndex);\n    }\n\n    public void onConnected() {\n        lastIndex = currentIndex;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/client/ZooKeeperSaslClient.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.client;\n\nimport java.io.IOException;\nimport java.security.PrivilegedActionException;\nimport java.security.PrivilegedExceptionAction;\n\nimport javax.security.auth.Subject;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginException;\nimport javax.security.sasl.SaslClient;\nimport javax.security.sasl.SaslException;\n\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.ClientCnxn;\nimport org.apache.zookeeper.Environment;\nimport org.apache.zookeeper.Login;\nimport org.apache.zookeeper.SaslClientCallbackHandler;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.proto.GetSASLRequest;\nimport org.apache.zookeeper.proto.SetSASLResponse;\nimport org.apache.zookeeper.util.SecurityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class manages SASL authentication for the client. It\n * allows ClientCnxn to authenticate using SASL with a Zookeeper server.\n */\npublic class ZooKeeperSaslClient {\n    public static final String LOGIN_CONTEXT_NAME_KEY = \"zookeeper.sasl.clientconfig\";\n    public static final String ENABLE_CLIENT_SASL_KEY = \"zookeeper.sasl.client\";\n    public static final String ENABLE_CLIENT_SASL_DEFAULT = \"true\";\n    private static volatile boolean initializedLogin = false; \n\n    /**\n     * Returns true if the SASL client is enabled. By default, the client\n     * is enabled but can be disabled by setting the system property\n     * <code>zookeeper.sasl.client</code> to <code>false</code>. See\n     * ZOOKEEPER-1657 for more information.\n     *\n     * @return If the SASL client is enabled.\n     */\n    public static boolean isEnabled() {\n        return Boolean.valueOf(System.getProperty(ENABLE_CLIENT_SASL_KEY, ENABLE_CLIENT_SASL_DEFAULT));\n    }\n\n    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperSaslClient.class);\n    private static Login login = null;\n    private SaslClient saslClient;\n    private boolean isSASLConfigured = true;\n\n    private byte[] saslToken = new byte[0];\n\n    public enum SaslState {\n        INITIAL,INTERMEDIATE,COMPLETE,FAILED\n    }\n\n    private SaslState saslState = SaslState.INITIAL;\n\n    private boolean gotLastPacket = false;\n    /** informational message indicating the current configuration status */\n    private final String configStatus;\n\n    public SaslState getSaslState() {\n        return saslState;\n    }\n\n    public String getLoginContext() {\n        if (login != null)\n            return login.getLoginContextName();\n        return null;\n    }\n\n    public ZooKeeperSaslClient(final String serverPrincipal)\n            throws LoginException {\n        /**\n         * ZOOKEEPER-1373: allow system property to specify the JAAS\n         * configuration section that the zookeeper client should use.\n         * Default to \"Client\".\n         */\n        String clientSection = System.getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"Client\");\n        // Note that 'Configuration' here refers to javax.security.auth.login.Configuration.\n        AppConfigurationEntry entries[] = null;\n        RuntimeException runtimeException = null;\n        try {\n            entries = Configuration.getConfiguration().getAppConfigurationEntry(clientSection);\n        } catch (SecurityException e) {\n            // handle below: might be harmless if the user doesn't intend to use JAAS authentication.\n            runtimeException = e;\n        } catch (IllegalArgumentException e) {\n            // third party customized getAppConfigurationEntry could throw IllegalArgumentException when JAAS\n            // configuration isn't set. We can reevaluate whether to catch RuntimeException instead when more \n            // different types of RuntimeException found\n            runtimeException = e;\n        }\n        if (entries != null) {\n            this.configStatus = \"Will attempt to SASL-authenticate using Login Context section '\" + clientSection + \"'\";\n            this.saslClient = createSaslClient(serverPrincipal, clientSection);\n        } else {\n            // Handle situation of clientSection's being null: it might simply because the client does not intend to \n            // use SASL, so not necessarily an error.\n            saslState = SaslState.FAILED;\n            String explicitClientSection = System.getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY);\n            if (explicitClientSection != null) {\n                // If the user explicitly overrides the default Login Context, they probably expected SASL to\n                // succeed. But if we got here, SASL failed.\n                if (runtimeException != null) {\n                    throw new LoginException(\"Zookeeper client cannot authenticate using the \" + explicitClientSection +\n                            \" section of the supplied JAAS configuration: '\" +\n                            System.getProperty(Environment.JAAS_CONF_KEY) + \"' because of a \" +\n                            \"RuntimeException: \" + runtimeException);\n                } else {\n                    throw new LoginException(\"Client cannot SASL-authenticate because the specified JAAS configuration \" +\n                            \"section '\" + explicitClientSection + \"' could not be found.\");\n                }\n            } else {\n                // The user did not override the default context. It might be that they just don't intend to use SASL,\n                // so log at INFO, not WARN, since they don't expect any SASL-related information.\n                String msg = \"Will not attempt to authenticate using SASL \";\n                if (runtimeException != null) {\n                    msg += \"(\" + runtimeException + \")\";\n                } else {\n                    msg += \"(unknown error)\";\n                }\n                this.configStatus = msg;\n                this.isSASLConfigured = false;\n            }\n            if (System.getProperty(Environment.JAAS_CONF_KEY)  != null) {\n                // Again, the user explicitly set something SASL-related, so they probably expected SASL to succeed.\n                if (runtimeException != null) {\n                    throw new LoginException(\"Zookeeper client cannot authenticate using the '\" +\n                            System.getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"Client\") +\n                            \"' section of the supplied JAAS configuration: '\" +\n                            System.getProperty(Environment.JAAS_CONF_KEY) + \"' because of a \" +\n                            \"RuntimeException: \" + runtimeException);\n                } else {\n                    throw new LoginException(\"No JAAS configuration section named '\" +\n                            System.getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"Client\") +\n                            \"' was found in specified JAAS configuration file: '\" +\n                            System.getProperty(Environment.JAAS_CONF_KEY) + \"'.\");\n                }\n            }\n        }\n    }\n    \n    /**\n     * @return informational message indicating the current configuration status.\n     */\n    public String getConfigStatus() {\n        return configStatus;\n    }\n\n    public boolean isComplete() {\n        return (saslState == SaslState.COMPLETE);\n    }\n\n    public boolean isFailed() {\n        return (saslState == SaslState.FAILED);\n    }\n\n    public static class ServerSaslResponseCallback implements AsyncCallback.DataCallback {\n        public void processResult(int rc, String path, Object ctx, byte data[], Stat stat) {\n            // processResult() is used by ClientCnxn's sendThread to respond to\n            // data[] contains the Zookeeper Server's SASL token.\n            // ctx is the ZooKeeperSaslClient object. We use this object's respondToServer() method\n            // to reply to the Zookeeper Server's SASL token\n            ZooKeeperSaslClient client = ((ClientCnxn)ctx).zooKeeperSaslClient;\n            if (client == null) {\n                LOG.warn(\"sasl client was unexpectedly null: cannot respond to Zookeeper server.\");\n                return;\n            }\n            byte[] usedata = data;\n            if (data != null) {\n                LOG.debug(\"ServerSaslResponseCallback(): saslToken server response: (length=\"+usedata.length+\")\");\n            }\n            else {\n                usedata = new byte[0];\n                LOG.debug(\"ServerSaslResponseCallback(): using empty data[] as server response (length=\"+usedata.length+\")\");\n            }\n            client.respondToServer(usedata, (ClientCnxn)ctx);\n        }\n    }\n\n    private SaslClient createSaslClient(final String servicePrincipal,\n                                                     final String loginContext) throws LoginException {\n        try {\n            if (!initializedLogin) {\n                synchronized (ZooKeeperSaslClient.class) {\n                    if (login == null) {\n                        if (LOG.isDebugEnabled()) {\n                            LOG.debug(\"JAAS loginContext is: \" + loginContext);\n                        }\n                        // note that the login object is static: it's shared amongst all zookeeper-related connections.\n                        // in order to ensure the login is initialized only once, it must be synchronized the code snippet.\n                        login = new Login(loginContext, new SaslClientCallbackHandler(null, \"Client\"));\n                        login.startThreadIfNeeded();\n                        initializedLogin = true;\n                    }\n                }\n            }\n            return SecurityUtils.createSaslClient(login.getSubject(),\n                    servicePrincipal, \"zookeeper\", \"zk-sasl-md5\", LOG, \"Client\");\n        } catch (LoginException e) {\n            // We throw LoginExceptions...\n            throw e;\n        } catch (Exception e) {\n            // ..but consume (with a log message) all other types of exceptions.\n            LOG.error(\"Exception while trying to create SASL client: \" + e);\n            return null;\n        }\n    }\n\n    public void respondToServer(byte[] serverToken, ClientCnxn cnxn) {\n        if (saslClient == null) {\n            LOG.error(\"saslClient is unexpectedly null. Cannot respond to server's SASL message; ignoring.\");\n            return;\n        }\n\n        if (!(saslClient.isComplete())) {\n            try {\n                saslToken = createSaslToken(serverToken);\n                if (saslToken != null) {\n                    sendSaslPacket(saslToken, cnxn);\n                }\n            } catch (SaslException e) {\n                LOG.error(\"SASL authentication failed using login context '\" +\n                        this.getLoginContext() + \"' with exception: {}\", e);\n                saslState = SaslState.FAILED;\n                gotLastPacket = true;\n            }\n        }\n\n        if (saslClient.isComplete()) {\n            // GSSAPI: server sends a final packet after authentication succeeds\n            // or fails.\n            if ((serverToken == null) && (saslClient.getMechanismName().equals(\"GSSAPI\")))\n                gotLastPacket = true;\n            // non-GSSAPI: no final packet from server.\n            if (!saslClient.getMechanismName().equals(\"GSSAPI\")) {\n                gotLastPacket = true;\n            }\n            // SASL authentication is completed, successfully or not:\n            // enable the socket's writable flag so that any packets waiting for authentication to complete in\n            // the outgoing queue will be sent to the Zookeeper server.\n            cnxn.enableWrite();\n        }\n    }\n\n    private byte[] createSaslToken() throws SaslException {\n        saslState = SaslState.INTERMEDIATE;\n        return createSaslToken(saslToken);\n    }\n\n    private byte[] createSaslToken(final byte[] saslToken) throws SaslException {\n        if (saslToken == null) {\n            // TODO: introspect about runtime environment (such as jaas.conf)\n            saslState = SaslState.FAILED;\n            throw new SaslException(\"Error in authenticating with a Zookeeper Quorum member: the quorum member's saslToken is null.\");\n        }\n\n        Subject subject = login.getSubject();\n        if (subject != null) {\n            synchronized(login) {\n                try {\n                    final byte[] retval =\n                        Subject.doAs(subject, new PrivilegedExceptionAction<byte[]>() {\n                                public byte[] run() throws SaslException {\n                                    LOG.debug(\"saslClient.evaluateChallenge(len=\"+saslToken.length+\")\");\n                                    return saslClient.evaluateChallenge(saslToken);\n                                }\n                            });\n                    return retval;\n                }\n                catch (PrivilegedActionException e) {\n                    String error = \"An error: (\" + e + \") occurred when evaluating Zookeeper Quorum Member's \" +\n                      \" received SASL token.\";\n                    // Try to provide hints to use about what went wrong so they can fix their configuration.\n                    // TODO: introspect about e: look for GSS information.\n                    final String UNKNOWN_SERVER_ERROR_TEXT =\n                      \"(Mechanism level: Server not found in Kerberos database (7) - UNKNOWN_SERVER)\";\n                    if (e.toString().indexOf(UNKNOWN_SERVER_ERROR_TEXT) > -1) {\n                        error += \" This may be caused by Java's being unable to resolve the Zookeeper Quorum Member's\" +\n                          \" hostname correctly. You may want to try to adding\" +\n                          \" '-Dsun.net.spi.nameservice.provider.1=dns,sun' to your client's JVMFLAGS environment.\";\n                    }\n                    error += \" Zookeeper Client will go to AUTH_FAILED state.\";\n                    LOG.error(error);\n                    saslState = SaslState.FAILED;\n                    throw new SaslException(error);\n                }\n            }\n        }\n        else {\n            throw new SaslException(\"Cannot make SASL token without subject defined. \" +\n              \"For diagnosis, please look for WARNs and ERRORs in your log related to the Login class.\");\n        }\n    }\n\n    private void sendSaslPacket(byte[] saslToken, ClientCnxn cnxn)\n      throws SaslException{\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"ClientCnxn:sendSaslPacket:length=\"+saslToken.length);\n        }\n\n        GetSASLRequest request = new GetSASLRequest();\n        request.setToken(saslToken);\n        SetSASLResponse response = new SetSASLResponse();\n        ServerSaslResponseCallback cb = new ServerSaslResponseCallback();\n\n        try {\n            cnxn.sendPacket(request,response,cb, ZooDefs.OpCode.sasl);\n        } catch (IOException e) {\n            throw new SaslException(\"Failed to send SASL packet to server.\",\n                e);\n        }\n    }\n\n    private void sendSaslPacket(ClientCnxn cnxn) throws SaslException {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"ClientCnxn:sendSaslPacket:length=\"+saslToken.length);\n        }\n        GetSASLRequest request = new GetSASLRequest();\n        request.setToken(createSaslToken());\n        SetSASLResponse response = new SetSASLResponse();\n        ServerSaslResponseCallback cb = new ServerSaslResponseCallback();\n        try {\n            cnxn.sendPacket(request,response,cb, ZooDefs.OpCode.sasl);\n        } catch (IOException e) {\n            throw new SaslException(\"Failed to send SASL packet to server due \" +\n              \"to IOException:\", e);\n        }\n    }\n\n    // used by ClientCnxn to know whether to emit a SASL-related event: either AuthFailed or SaslAuthenticated,\n    // or none, if not ready yet. Sets saslState to COMPLETE as a side-effect.\n    public KeeperState getKeeperState() {\n        if (saslClient != null) {\n            if (saslState == SaslState.FAILED) {\n              return KeeperState.AuthFailed;\n            }\n            if (saslClient.isComplete()) {\n                if (saslState == SaslState.INTERMEDIATE) {\n                    saslState = SaslState.COMPLETE;\n                    return KeeperState.SaslAuthenticated;\n                }\n            }\n        }\n        // No event ready to emit yet.\n        return null;\n    }\n\n    // Initialize the client's communications with the Zookeeper server by sending the server the first\n    // authentication packet.\n    public void initialize(ClientCnxn cnxn) throws SaslException {\n        if (saslClient == null) {\n            saslState = SaslState.FAILED;\n            throw new SaslException(\"saslClient failed to initialize properly: it's null.\");\n        }\n        if (saslState == SaslState.INITIAL) {\n            if (saslClient.hasInitialResponse()) {\n                sendSaslPacket(cnxn);\n            }\n            else {\n                byte[] emptyToken = new byte[0];\n                sendSaslPacket(emptyToken, cnxn);\n            }\n            saslState = SaslState.INTERMEDIATE;\n        }\n    }\n\n    public boolean clientTunneledAuthenticationInProgress() {\n    \tif (!isSASLConfigured) {\n    \t    return false;\n        } \n        // TODO: Rather than checking a disjunction here, should be a single member\n        // variable or method in this class to determine whether the client is\n        // configured to use SASL. (see also ZOOKEEPER-1455).\n        try {\n  \t    if ((System.getProperty(Environment.JAAS_CONF_KEY) != null) ||\n              ((javax.security.auth.login.Configuration.getConfiguration() != null) &&\n                  (javax.security.auth.login.Configuration.getConfiguration().\n                       getAppConfigurationEntry(System.\n                       getProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,\"Client\")) \n                           != null))) {\n                // Client is configured to use a valid login Configuration, so\n                // authentication is either in progress, successful, or failed.\n\n                // 1. Authentication hasn't finished yet: we must wait for it to do so.\n                if ((isComplete() == false) &&\n                    (isFailed() == false)) {\n                    return true;\n                }\n\n                // 2. SASL authentication has succeeded or failed..\n                if (isComplete() || isFailed()) {\n                    if (gotLastPacket == false) {\n                        // ..but still in progress, because there is a final SASL\n                        // message from server which must be received.\n                    return true;\n                    }\n                }\n            }\n            // Either client is not configured to use a tunnelled authentication\n            // scheme, or tunnelled authentication has completed (successfully or\n            // not), and all server SASL messages have been received.\n            return false;\n        } catch (SecurityException e) {\n            // Thrown if the caller does not have permission to retrieve the Configuration.\n            // In this case, simply returning false is correct.\n            if (LOG.isDebugEnabled() == true) {\n                LOG.debug(\"Could not retrieve login configuration: \" + e);\n            }\n            return false;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/common/AtomicFileOutputStream.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.common;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/*\n * This code is originally from HDFS, see the similarly named files there\n * in case of bug fixing, history, etc...\n */\n\n/**\n * A FileOutputStream that has the property that it will only show up at its\n * destination once it has been entirely written and flushed to disk. While\n * being written, it will use a .tmp suffix.\n *\n * When the output stream is closed, it is flushed, fsynced, and will be moved\n * into place, overwriting any file that already exists at that location.\n *\n * <b>NOTE</b>: on Windows platforms, it will not atomically replace the target\n * file - instead the target file is deleted before this one is moved into\n * place.\n */\npublic class AtomicFileOutputStream extends FilterOutputStream {\n    private static final String TMP_EXTENSION = \".tmp\";\n\n    private final static Logger LOG = LoggerFactory\n            .getLogger(AtomicFileOutputStream.class);\n\n    private final File origFile;\n    private final File tmpFile;\n\n    public AtomicFileOutputStream(File f) throws FileNotFoundException {\n        // Code unfortunately must be duplicated below since we can't assign\n        // anything\n        // before calling super\n        super(new FileOutputStream(new File(f.getParentFile(), f.getName()\n                + TMP_EXTENSION)));\n        origFile = f.getAbsoluteFile();\n        tmpFile = new File(f.getParentFile(), f.getName() + TMP_EXTENSION)\n                .getAbsoluteFile();\n    }\n\n    /**\n     * The default write method in FilterOutputStream does not call the write\n     * method of its underlying input stream with the same arguments. Instead\n     * it writes the data byte by byte, override it here to make it more\n     * efficient.\n     */\n    @Override\n    public void write(byte b[], int off, int len) throws IOException {\n        out.write(b, off, len);\n    }\n\n    @Override\n    public void close() throws IOException {\n        boolean triedToClose = false, success = false;\n        try {\n            flush();\n            ((FileOutputStream) out).getChannel().force(true);\n\n            triedToClose = true;\n            super.close();\n            success = true;\n        } finally {\n            if (success) {\n                boolean renamed = tmpFile.renameTo(origFile);\n                if (!renamed) {\n                    // On windows, renameTo does not replace.\n                    if (!origFile.delete() || !tmpFile.renameTo(origFile)) {\n                        throw new IOException(\n                                \"Could not rename temporary file \" + tmpFile\n                                        + \" to \" + origFile);\n                    }\n                }\n            } else {\n                if (!triedToClose) {\n                    // If we failed when flushing, try to close it to not leak\n                    // an FD\n                    IOUtils.closeStream(out);\n                }\n                // close wasn't successful, try to delete the tmp file\n                if (!tmpFile.delete()) {\n                    LOG.warn(\"Unable to delete tmp file \" + tmpFile);\n                }\n            }\n        }\n    }\n\n    /**\n     * Close the atomic file, but do not \"commit\" the temporary file on top of\n     * the destination. This should be used if there is a failure in writing.\n     */\n    public void abort() {\n        try {\n            super.close();\n        } catch (IOException ioe) {\n            LOG.warn(\"Unable to abort file \" + tmpFile, ioe);\n        }\n        if (!tmpFile.delete()) {\n            LOG.warn(\"Unable to delete tmp file during abort \" + tmpFile);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/common/IOUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.common;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\n\nimport org.slf4j.Logger;\n\n/*\n * This code is originally from HDFS, see the similarly named files there\n * in case of bug fixing, history, etc...\n */\n\npublic class IOUtils {\n    /**\n     * Closes the stream ignoring {@link IOException}. Must only be called in\n     * cleaning up from exception handlers.\n     * \n     * @param stream\n     *            the Stream to close\n     */\n    public static void closeStream(Closeable stream) {\n        cleanup(null, stream);\n    }\n\n    /**\n     * Close the Closeable objects and <b>ignore</b> any {@link IOException} or\n     * null pointers. Must only be used for cleanup in exception handlers.\n     * \n     * @param log\n     *            the log to record problems to at debug level. Can be null.\n     * @param closeables\n     *            the objects to close\n     */\n    public static void cleanup(Logger log, Closeable... closeables) {\n        for (Closeable c : closeables) {\n            if (c != null) {\n                try {\n                    c.close();\n                } catch (IOException e) {\n                    if (log != null) {\n                        log.warn(\"Exception in closing \" + c, e);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Copies from one stream to another.\n     * \n     * @param in\n     *            InputStrem to read from\n     * @param out\n     *            OutputStream to write to\n     * @param buffSize\n     *            the size of the buffer\n     * @param close\n     *            whether or not close the InputStream and OutputStream at the\n     *            end. The streams are closed in the finally clause.\n     */\n    public static void copyBytes(InputStream in, OutputStream out,\n            int buffSize, boolean close) throws IOException {\n        try {\n            copyBytes(in, out, buffSize);\n            if (close) {\n                out.close();\n                out = null;\n                in.close();\n                in = null;\n            }\n        } finally {\n            if (close) {\n                closeStream(out);\n                closeStream(in);\n            }\n        }\n    }\n\n    /**\n     * Copies from one stream to another.\n     * \n     * @param in\n     *            InputStrem to read from\n     * @param out\n     *            OutputStream to write to\n     * @param buffSize\n     *            the size of the buffer\n     */\n    public static void copyBytes(InputStream in, OutputStream out, int buffSize)\n            throws IOException {\n        PrintStream ps = out instanceof PrintStream ? (PrintStream) out : null;\n        byte buf[] = new byte[buffSize];\n        int bytesRead = in.read(buf);\n        while (bytesRead >= 0) {\n            out.write(buf, 0, bytesRead);\n            if ((ps != null) && ps.checkError()) {\n                throw new IOException(\"Unable to write to output stream.\");\n            }\n            bytesRead = in.read(buf);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/common/PathTrie.java",
    "content": " /**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.common;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * a class that implements prefix matching for \n * components of a filesystem path. the trie\n * looks like a tree with edges mapping to \n * the component of a path.\n * example /ab/bc/cf would map to a trie\n *           /\n *        ab/\n *        (ab)\n *      bc/\n *       / \n *      (bc)\n *   cf/\n *   (cf)\n */    \npublic class PathTrie {\n    /**\n     * the logger for this class\n     */\n    private static final Logger LOG = LoggerFactory.getLogger(PathTrie.class);\n    \n    /**\n     * the root node of PathTrie\n     */\n    private final TrieNode rootNode ;\n    \n    static class TrieNode {\n        boolean property = false;\n        final HashMap<String, TrieNode> children;\n        TrieNode parent = null;\n        /**\n         * create a trienode with parent\n         * as parameter\n         * @param parent the parent of this trienode\n         */\n        private TrieNode(TrieNode parent) {\n            children = new HashMap<String, TrieNode>();\n            this.parent = parent;\n        }\n        \n        /**\n         * get the parent of this node\n         * @return the parent node\n         */\n        TrieNode getParent() {\n            return this.parent;\n        }\n        \n        /**\n         * set the parent of this node\n         * @param parent the parent to set to\n         */\n        void setParent(TrieNode parent) {\n            this.parent = parent;\n        }\n        \n        /**\n         * a property that is set \n         * for a node - making it \n         * special.\n         */\n        void setProperty(boolean prop) {\n            this.property = prop;\n        }\n        \n        /** the property of this\n         * node \n         * @return the property for this\n         * node\n         */\n        boolean getProperty() {\n            return this.property;\n        }\n        /**\n         * add a child to the existing node\n         * @param childName the string name of the child\n         * @param node the node that is the child\n         */\n        void addChild(String childName, TrieNode node) {\n            synchronized(children) {\n                if (children.containsKey(childName)) {\n                    return;\n                }\n                children.put(childName, node);\n            }\n        }\n     \n        /**\n         * delete child from this node\n         * @param childName the string name of the child to \n         * be deleted\n         */\n        void deleteChild(String childName) {\n            synchronized(children) {\n                if (!children.containsKey(childName)) {\n                    return;\n                }\n                TrieNode childNode = children.get(childName);\n                // this is the only child node.\n                if (childNode.getChildren().length == 1) { \n                    childNode.setParent(null);\n                    children.remove(childName);\n                }\n                else {\n                    // their are more child nodes\n                    // so just reset property.\n                    childNode.setProperty(false);\n                }\n            }\n        }\n        \n        /**\n         * return the child of a node mapping\n         * to the input childname\n         * @param childName the name of the child\n         * @return the child of a node\n         */\n        TrieNode getChild(String childName) {\n            synchronized(children) {\n               if (!children.containsKey(childName)) {\n                   return null;\n               }\n               else {\n                   return children.get(childName);\n               }\n            }\n        }\n\n        /**\n         * get the list of children of this \n         * trienode.\n         * @param node to get its children\n         * @return the string list of its children\n         */\n        String[] getChildren() {\n           synchronized(children) {\n               return children.keySet().toArray(new String[0]);\n           }\n        }\n        \n        /**\n         * get the string representation\n         * for this node\n         */\n        public String toString() {\n            StringBuilder sb = new StringBuilder();\n            sb.append(\"Children of trienode: \");\n            synchronized(children) {\n                for (String str: children.keySet()) {\n                    sb.append(\" \" + str);\n                }\n            }\n            return sb.toString();\n        }\n    }\n    \n    /**\n     * construct a new PathTrie with\n     * a root node of /\n     */\n    public PathTrie() {\n        this.rootNode = new TrieNode(null);\n    }\n    \n    /**\n     * add a path to the path trie \n     * @param path\n     */\n    public void addPath(String path) {\n        if (path == null) {\n            return;\n        }\n        String[] pathComponents = path.split(\"/\");\n        TrieNode parent = rootNode;\n        String part = null;\n        if (pathComponents.length <= 1) {\n            throw new IllegalArgumentException(\"Invalid path \" + path);\n        }\n        for (int i=1; i<pathComponents.length; i++) {\n            part = pathComponents[i];\n            if (parent.getChild(part) == null) {\n                parent.addChild(part, new TrieNode(parent));\n            }\n            parent = parent.getChild(part);\n        }\n        parent.setProperty(true);\n    }\n    \n    /**\n     * delete a path from the trie\n     * @param path the path to be deleted\n     */\n    public void deletePath(String path) {\n        if (path == null) {\n            return;\n        }\n        String[] pathComponents = path.split(\"/\");\n        TrieNode parent = rootNode;\n        String part = null;\n        if (pathComponents.length <= 1) { \n            throw new IllegalArgumentException(\"Invalid path \" + path);\n        }\n        for (int i=1; i<pathComponents.length; i++) {\n            part = pathComponents[i];\n            if (parent.getChild(part) == null) {\n                //the path does not exist \n                return;\n            }\n            parent = parent.getChild(part);\n            LOG.info(\"{}\",parent);\n        }\n        TrieNode realParent  = parent.getParent();\n        realParent.deleteChild(part);\n    }\n    \n    /**\n     * return the largest prefix for the input path.\n     * @param path the input path\n     * @return the largest prefix for the input path.\n     */\n    public String findMaxPrefix(String path) {\n        if (path == null) {\n            return null;\n        }\n        if (\"/\".equals(path)) {\n            return path;\n        }\n        String[] pathComponents = path.split(\"/\");\n        TrieNode parent = rootNode;\n        List<String> components = new ArrayList<String>();\n        if (pathComponents.length <= 1) {\n            throw new IllegalArgumentException(\"Invalid path \" + path);\n        }\n        int i = 1;\n        String part = null;\n        StringBuilder sb = new StringBuilder();\n        int lastindex = -1;\n        while((i < pathComponents.length)) {\n            if (parent.getChild(pathComponents[i]) != null) {\n                part = pathComponents[i];\n                parent = parent.getChild(part);\n                components.add(part);\n                if (parent.getProperty()) {\n                    lastindex = i-1;\n                }\n            }\n            else {\n                break;\n            }\n            i++;\n        }\n        for (int j=0; j< (lastindex+1); j++) {\n            sb.append(\"/\" + components.get(j));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * clear all nodes\n     */\n    public void clear() {\n        for(String child : rootNode.getChildren()) {\n            rootNode.deleteChild(child);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/common/PathUtils.java",
    "content": " /**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.common;\n\n\n/**\n * Path related utilities\n */    \npublic class PathUtils {\n\t\n\t/** validate the provided znode path string\n\t * @param path znode path string\n\t * @param isSequential if the path is being created\n\t * with a sequential flag\n\t * @throws IllegalArgumentException if the path is invalid\n\t */\n\tpublic static void validatePath(String path, boolean isSequential) \n\t\tthrows IllegalArgumentException {\n\t\tvalidatePath(isSequential? path + \"1\": path);\n\t}\n\t\n    /**\n     * Validate the provided znode path string\n     * @param path znode path string\n     * @throws IllegalArgumentException if the path is invalid\n     */\n    public static void validatePath(String path) throws IllegalArgumentException {\n        if (path == null) {\n            throw new IllegalArgumentException(\"Path cannot be null\");\n        }\n        if (path.length() == 0) {\n            throw new IllegalArgumentException(\"Path length must be > 0\");\n        }\n        if (path.charAt(0) != '/') {\n            throw new IllegalArgumentException(\n                         \"Path must start with / character\");\n        }\n        if (path.length() == 1) { // done checking - it's the root\n            return;\n        }\n        if (path.charAt(path.length() - 1) == '/') {\n            throw new IllegalArgumentException(\n                         \"Path must not end with / character\");\n        }\n\n        String reason = null;\n        char lastc = '/';\n        char chars[] = path.toCharArray();\n        char c;\n        for (int i = 1; i < chars.length; lastc = chars[i], i++) {\n            c = chars[i];\n\n            if (c == 0) {\n                reason = \"null character not allowed @\" + i;\n                break;\n            } else if (c == '/' && lastc == '/') {\n                reason = \"empty node name specified @\" + i;\n                break;\n            } else if (c == '.' && lastc == '.') {\n                if (chars[i-2] == '/' &&\n                        ((i + 1 == chars.length)\n                                || chars[i+1] == '/')) {\n                    reason = \"relative paths not allowed @\" + i;\n                    break;\n                }\n            } else if (c == '.') {\n                if (chars[i-1] == '/' &&\n                        ((i + 1 == chars.length)\n                                || chars[i+1] == '/')) {\n                    reason = \"relative paths not allowed @\" + i;\n                    break;\n                }\n            } else if (c > '\\u0000' && c < '\\u001f'\n                    || c > '\\u007f' && c < '\\u009F'\n                    || c > '\\ud800' && c < '\\uf8ff'\n                    || c > '\\ufff0' && c < '\\uffff') {\n                reason = \"invalid charater @\" + i;\n                break;\n            }\n        }\n\n        if (reason != null) {\n            throw new IllegalArgumentException(\n                    \"Invalid path string \\\"\" + path + \"\\\" caused by \" + reason);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/common/Time.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.common;\n\nimport java.util.Date;\n\npublic class Time {\n    /**\n     * Returns time in milliseconds as does System.currentTimeMillis(),\n     * but uses elapsed time from an arbitrary epoch more like System.nanoTime().\n     * The difference is that if somebody changes the system clock,\n     * Time.currentElapsedTime will change but nanoTime won't. On the other hand,\n     * all of ZK assumes that time is measured in milliseconds.\n     * @return  The time in milliseconds from some arbitrary point in time.\n     */\n    public static long currentElapsedTime() {\n        return System.nanoTime() / 1000000;\n    }\n\n    /**\n     * Explicitly returns system dependent current wall time.\n     * @return Current time in msec.\n     */\n    public static long currentWallTime() {\n        return System.currentTimeMillis();\n    }\n\n    /**\n     * This is to convert the elapsedTime to a Date.\n     * @return A date object indicated by the elapsedTime.\n     */\n    public static Date elapsedTimeToDate(long elapsedTime) {\n        long wallTime = currentWallTime() + elapsedTime - currentElapsedTime();\n        return new Date(wallTime);\n    }\n}"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/jmx/CommonNames.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.jmx;\n\n/**\n * A bunch of constants.\n * TODO: will get rid of it eventually.\n */\npublic class CommonNames {\n    public static final String DOMAIN=\"org.apache.ZooKeeperService\";\n    public static final String DATA_TREE_KEY=\"DataTree\";\n    public static final String STANDALONE_SERVER_KEY=\"StandaloneServer\";\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/jmx/MBeanRegistry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.jmx;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax.management.JMException;\nimport javax.management.MBeanServer;\nimport javax.management.MBeanServerFactory;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class provides a unified interface for registering/unregistering of\n * zookeeper MBeans with the platform MBean server. It builds a hierarchy of MBeans\n * where each MBean represented by a filesystem-like path. Eventually, this hierarchy\n * will be stored in the zookeeper data tree instance as a virtual data tree.\n */\npublic class MBeanRegistry {\n    private static final Logger LOG = LoggerFactory.getLogger(MBeanRegistry.class);\n    \n    private static volatile MBeanRegistry instance = new MBeanRegistry();\n    \n    private Map<ZKMBeanInfo, String> mapBean2Path =\n        new ConcurrentHashMap<ZKMBeanInfo, String>();\n    \n    private Map<String, ZKMBeanInfo> mapName2Bean =\n        new ConcurrentHashMap<String, ZKMBeanInfo>();\n\n    private MBeanServer mBeanServer;\n\n    public static void setInstance(MBeanRegistry instance) {\n        MBeanRegistry.instance = instance;\n    }\n\n    public static MBeanRegistry getInstance() {\n        return instance;\n    }\n\n    public MBeanRegistry () {\n        try {\n            mBeanServer = ManagementFactory.getPlatformMBeanServer();        \n        } catch (Error e) {\n            // Account for running within IKVM and create a new MBeanServer\n            // if the PlatformMBeanServer does not exist.\n            mBeanServer =  MBeanServerFactory.createMBeanServer();\n        }\n    }\n\n    /**\n     * Return the underlying MBeanServer that is being\n     * used to register MBean's. The returned MBeanServer\n     * may be a new empty MBeanServer if running through IKVM.\n     */\n    public MBeanServer getPlatformMBeanServer() {\n        return mBeanServer;\n    }\n\n    /**\n     * Registers a new MBean with the platform MBean server. \n     * @param bean the bean being registered\n     * @param parent if not null, the new bean will be registered as a child\n     * node of this parent.\n     */\n    public void register(ZKMBeanInfo bean, ZKMBeanInfo parent)\n        throws JMException\n    {\n        assert bean != null;\n        String path = null;\n        if (parent != null) {\n            path = mapBean2Path.get(parent);\n            assert path != null;\n        }\n        path = makeFullPath(path, parent);\n        if(bean.isHidden())\n            return;\n        ObjectName oname = makeObjectName(path, bean);\n        try {\n            mBeanServer.registerMBean(bean, oname);\n            mapBean2Path.put(bean, path);\n            mapName2Bean.put(bean.getName(), bean);\n        } catch (JMException e) {\n            LOG.warn(\"Failed to register MBean \" + bean.getName());\n            throw e;\n        }\n    }\n\n    /**\n     * Unregister the MBean identified by the path.\n     * @param path\n     * @param bean\n     */\n    private void unregister(String path,ZKMBeanInfo bean) throws JMException {\n        if(path==null)\n            return;\n        if (!bean.isHidden()) {\n            try {\n                mBeanServer.unregisterMBean(makeObjectName(path, bean));\n            } catch (JMException e) {\n                LOG.warn(\"Failed to unregister MBean \" + bean.getName());\n                throw e;\n            }\n        }        \n    }\n    \n    /**\n     * Unregister MBean.\n     * @param bean\n     */\n    public void unregister(ZKMBeanInfo bean) {\n        if(bean==null)\n            return;\n        String path=mapBean2Path.get(bean);\n        try {\n            unregister(path,bean);\n        } catch (JMException e) {\n            LOG.warn(\"Error during unregister\", e);\n        }\n        mapBean2Path.remove(bean);\n        mapName2Bean.remove(bean.getName());\n    }\n    /**\n     * Unregister all currently registered MBeans\n     */\n    public void unregisterAll() {\n        for(Map.Entry<ZKMBeanInfo,String> e: mapBean2Path.entrySet()) {\n            try {\n                unregister(e.getValue(), e.getKey());\n            } catch (JMException e1) {\n                LOG.warn(\"Error during unregister\", e1);\n            }\n        }\n        mapBean2Path.clear();\n        mapName2Bean.clear();\n    }\n    /**\n     * Generate a filesystem-like path.\n     * @param prefix path prefix\n     * @param name path elements\n     * @return absolute path\n     */\n    public String makeFullPath(String prefix, String... name) {\n        StringBuilder sb=new StringBuilder(prefix == null ? \"/\" : (prefix.equals(\"/\")?prefix:prefix+\"/\"));\n        boolean first=true;\n        for (String s : name) {\n            if(s==null) continue;\n            if(!first){\n                sb.append(\"/\");\n            }else\n                first=false;\n            sb.append(s);\n        }\n        return sb.toString();\n    }\n    \n    protected String makeFullPath(String prefix, ZKMBeanInfo bean) {\n        return makeFullPath(prefix, bean == null ? null : bean.getName());\n    }\n\n    /**\n     * This takes a path, such as /a/b/c, and converts it to \n     * name0=a,name1=b,name2=c\n     */\n    private int tokenize(StringBuilder sb, String path, int index){\n        String[] tokens = path.split(\"/\");\n        for (String s: tokens) {\n            if (s.length()==0)\n                continue;\n            sb.append(\"name\").append(index++)\n                    .append(\"=\").append(s).append(\",\");\n        }\n        return index;\n    }\n    /**\n     * Builds an MBean path and creates an ObjectName instance using the path. \n     * @param path MBean path\n     * @param bean the MBean instance\n     * @return ObjectName to be registered with the platform MBean server\n     */\n    protected ObjectName makeObjectName(String path, ZKMBeanInfo bean)\n        throws MalformedObjectNameException\n    {\n        if(path==null)\n            return null;\n        StringBuilder beanName = new StringBuilder(CommonNames.DOMAIN + \":\");\n        int counter=0;\n        counter=tokenize(beanName,path,counter);\n        tokenize(beanName,bean.getName(),counter);\n        beanName.deleteCharAt(beanName.length()-1);\n        try {\n            return new ObjectName(beanName.toString());\n        } catch (MalformedObjectNameException e) {\n            LOG.warn(\"Invalid name \\\"\" + beanName.toString() + \"\\\" for class \"\n                    + bean.getClass().toString());\n            throw e;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/jmx/ManagedUtil.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.jmx;\n\nimport java.util.Enumeration;\n\nimport javax.management.JMException;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport org.apache.log4j.LogManager;\nimport org.apache.log4j.Logger;\nimport org.apache.log4j.jmx.HierarchyDynamicMBean;\nimport org.apache.log4j.spi.LoggerRepository;\n\n/**\n * Shared utilities\n */\npublic class ManagedUtil {\n    /**\n     * Register the log4j JMX mbeans. Set environment variable\n     * \"zookeeper.jmx.log4j.disable\" to true to disable registration.\n     * @see http://logging.apache.org/log4j/1.2/apidocs/index.html?org/apache/log4j/jmx/package-summary.html\n     * @throws JMException if registration fails\n     */\n    @SuppressWarnings(\"rawtypes\")\n    public static void registerLog4jMBeans() throws JMException {\n        if (Boolean.getBoolean(\"zookeeper.jmx.log4j.disable\") == true) {\n            return;\n        }\n        \n        MBeanServer mbs = MBeanRegistry.getInstance().getPlatformMBeanServer();\n\n        // Create and Register the top level Log4J MBean\n        HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();\n\n        ObjectName mbo = new ObjectName(\"log4j:hiearchy=default\");\n        mbs.registerMBean(hdm, mbo);\n\n        // Add the root logger to the Hierarchy MBean\n        Logger rootLogger = Logger.getRootLogger();\n        hdm.addLoggerMBean(rootLogger.getName());\n\n        // Get each logger from the Log4J Repository and add it to\n        // the Hierarchy MBean created above.\n        LoggerRepository r = LogManager.getLoggerRepository();\n        Enumeration enumer = r.getCurrentLoggers();\n        Logger logger = null;\n\n        while (enumer.hasMoreElements()) {\n           logger = (Logger) enumer.nextElement();\n           hdm.addLoggerMBean(logger.getName());\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/jmx/ZKMBeanInfo.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.jmx;\n\n/**\n * Zookeeper MBean info interface. MBeanRegistry uses the interface to generate\n * JMX object name.\n */\npublic interface ZKMBeanInfo {\n    /**\n     * @return a string identifying the MBean \n     */\n    public String getName();\n    /**\n     * If isHidden returns true, the MBean won't be registered with MBean server,\n     * and thus won't be available for management tools. Used for grouping MBeans.\n     * @return true if the MBean is hidden.\n     */\n    public boolean isHidden();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ByteBufferInputStream.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.Record;\n\npublic class ByteBufferInputStream extends InputStream {\n    ByteBuffer bb;\n\n    public ByteBufferInputStream(ByteBuffer bb) {\n        this.bb = bb;\n    }\n\n    @Override\n    public int read() throws IOException {\n        if (bb.remaining() == 0) {\n            return -1;\n        }\n        return bb.get() & 0xff;\n    }\n\n    @Override\n    public int available() throws IOException {\n        return bb.remaining();\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) throws IOException {\n        if (bb.remaining() == 0) {\n            return -1;\n        }\n        if (len > bb.remaining()) {\n            len = bb.remaining();\n        }\n        bb.get(b, off, len);\n        return len;\n    }\n\n    @Override\n    public int read(byte[] b) throws IOException {\n        return read(b, 0, b.length);\n    }\n\n    @Override\n    public long skip(long n) throws IOException {\n        long newPos = bb.position() + n;\n        if (newPos > bb.remaining()) {\n            n = bb.remaining();\n        }\n        bb.position(bb.position() + (int) n);\n        return n;\n    }\n\n    static public void byteBuffer2Record(ByteBuffer bb, Record record)\n            throws IOException {\n        BinaryInputArchive ia;\n        ia = BinaryInputArchive.getArchive(new ByteBufferInputStream(bb));\n        record.deserialize(ia, \"request\");\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ByteBufferOutputStream.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\n\npublic class ByteBufferOutputStream extends OutputStream {\n    ByteBuffer bb;\n    public ByteBufferOutputStream(ByteBuffer bb) {\n        this.bb = bb;\n    }\n    @Override\n    public void write(int b) throws IOException {\n        bb.put((byte)b);\n    }\n    @Override\n    public void write(byte[] b) throws IOException {\n        bb.put(b);\n    }\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        bb.put(b, off, len);\n    }\n    static public void record2ByteBuffer(Record record, ByteBuffer bb)\n    throws IOException {\n        BinaryOutputArchive oa;\n        oa = BinaryOutputArchive.getArchive(new ByteBufferOutputStream(bb));\n        record.serialize(oa, \"request\");\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ConnectionBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.net.Inet6Address;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\n\nimport javax.management.ObjectName;\n\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\n\n/**\n * Implementation of connection MBean interface.\n */\npublic class ConnectionBean implements ConnectionMXBean, ZKMBeanInfo {\n    private static final Logger LOG = LoggerFactory.getLogger(ConnectionBean.class);\n\n    private final ServerCnxn connection;\n    private final Stats stats;\n\n    private final ZooKeeperServer zk;\n    \n    private final String remoteIP;\n    private final long sessionId;\n\n    public ConnectionBean(ServerCnxn connection,ZooKeeperServer zk){\n        this.connection = connection;\n        this.stats = connection;\n        this.zk = zk;\n        \n        InetSocketAddress sockAddr = connection.getRemoteSocketAddress();\n        if (sockAddr == null) {\n            remoteIP = \"Unknown\";\n        } else {\n            InetAddress addr = sockAddr.getAddress();\n            if (addr instanceof Inet6Address) {\n                remoteIP = ObjectName.quote(addr.getHostAddress());\n            } else {\n                remoteIP = addr.getHostAddress();\n            }\n        }\n        sessionId = connection.getSessionId();\n    }\n    \n    public String getSessionId() {\n        return \"0x\" + Long.toHexString(sessionId);\n    }\n\n    public String getSourceIP() {\n        InetSocketAddress sockAddr = connection.getRemoteSocketAddress();\n        if (sockAddr == null) {\n            return null;\n        }\n        return sockAddr.getAddress().getHostAddress()\n            + \":\" + sockAddr.getPort();\n    }\n\n    public String getName() {\n        return MBeanRegistry.getInstance().makeFullPath(\"Connections\", remoteIP,\n                getSessionId());\n    }\n    \n    public boolean isHidden() {\n        return false;\n    }\n    \n    public String[] getEphemeralNodes() {\n        if(zk.getZKDatabase()  !=null){\n            String[] res = zk.getZKDatabase().getEphemerals(sessionId)\n                .toArray(new String[0]);\n            Arrays.sort(res);\n            return res;\n        }\n        return null;\n    }\n    \n    public String getStartedTime() {\n        return stats.getEstablished().toString();\n    }\n    \n    public void terminateSession() {\n        try {\n            zk.closeSession(sessionId);\n        } catch (Exception e) {\n            LOG.warn(\"Unable to closeSession() for session: 0x\" \n                    + getSessionId(), e);\n        }\n    }\n    \n    public void terminateConnection() {\n        connection.sendCloseSession();\n    }\n\n    public void resetCounters() {\n        stats.resetStats();\n    }\n\n    @Override\n    public String toString() {\n        return \"ConnectionBean{ClientIP=\" + ObjectName.quote(getSourceIP())\n            + \",SessionId=0x\" + getSessionId() + \"}\";\n    }\n    \n    public long getOutstandingRequests() {\n        return stats.getOutstandingRequests();\n    }\n    \n    public long getPacketsReceived() {\n        return stats.getPacketsReceived();\n    }\n    \n    public long getPacketsSent() {\n        return stats.getPacketsSent();\n    }\n    \n    public int getSessionTimeout() {\n        return connection.getSessionTimeout();\n    }\n\n    public long getMinLatency() {\n        return stats.getMinLatency();\n    }\n\n    public long getAvgLatency() {\n        return stats.getAvgLatency();\n    }\n\n    public long getMaxLatency() {\n        return stats.getMaxLatency();\n    }\n    \n    public String getLastOperation() {\n        return stats.getLastOperation();\n    }\n\n    public String getLastCxid() {\n        return \"0x\" + Long.toHexString(stats.getLastCxid());\n    }\n\n    public String getLastZxid() {\n        return \"0x\" + Long.toHexString(stats.getLastZxid());\n    }\n\n    public String getLastResponseTime() {\n        return Time.elapsedTimeToDate(stats.getLastResponseTime()).toString();\n    }\n\n    public long getLastLatency() {\n        return stats.getLastLatency();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ConnectionMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\n/**\n * This MBean represents a client connection.\n */\npublic interface ConnectionMXBean {\n    /**\n     * @return source (client) IP address\n     */\n    public String getSourceIP();\n    /**\n     * @return client's session id\n     */\n    public String getSessionId();\n    /**\n     * @return time the connection was started\n     */\n    public String getStartedTime();\n    /**\n     * @return number of ephemeral nodes owned by this connection\n     */\n    public String[] getEphemeralNodes();\n    /**\n     * @return packets received from this client\n     */\n    public long getPacketsReceived();\n    /**\n     * @return number of packets sent to this client\n     */\n    public long getPacketsSent();\n    /**\n     * @return number of requets being processed\n     */\n    public long getOutstandingRequests();\n    /**\n     * @return session timeout in ms\n     */\n    public int getSessionTimeout();\n    \n    /**\n     * Terminate this client session. The client will reconnect with a different\n     * session id.\n     */\n    public void terminateSession();\n    /**\n     * Terminate thei client connection. The client will immediately attempt to \n     * reconnect with the same session id.\n     */\n    public void terminateConnection();\n\n\n    /** Min latency in ms\n     * @since 3.3.0 */\n    long getMinLatency();\n    /** Average latency in ms\n     * @since 3.3.0 */\n    long getAvgLatency();\n    /** Max latency in ms\n     * @since 3.3.0 */\n    long getMaxLatency();\n    /** Last operation performed by this connection\n     * @since 3.3.0 */\n    String getLastOperation();\n    /** Last cxid of this connection\n     * @since 3.3.0 */\n    String getLastCxid();\n    /** Last zxid of this connection\n     * @since 3.3.0 */\n    String getLastZxid();\n    /** Last time server sent a response to client on this connection\n     * @since 3.3.0 */\n    String getLastResponseTime();\n    /** Latency of last response to client on this connection in ms\n     * @since 3.3.0 */\n    long getLastLatency();\n\n    /** Reset counters\n     * @since 3.3.0 */\n    void resetCounters();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/DataNode.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.Collections;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.data.StatPersisted;\n\n/**\n * This class contains the data for a node in the data tree.\n * <p>\n * A data node contains a reference to its parent, a byte array as its data, an\n * array of ACLs, a stat object, and a set of its children's paths.\n * \n */\npublic class DataNode implements Record {\n    /** the parent of this datanode */\n    DataNode parent;\n\n    /** the data for this datanode */\n    byte data[];\n\n    /**\n     * the acl map long for this datanode. the datatree has the map\n     */\n    Long acl;\n\n    /**\n     * the stat for this node that is persisted to disk.\n     */\n    public StatPersisted stat;\n\n    /**\n     * the list of children for this node. note that the list of children string\n     * does not contain the parent path -- just the last part of the path. This\n     * should be synchronized on except deserializing (for speed up issues).\n     */\n    private Set<String> children = null;\n\n    private static final Set<String> EMPTY_SET = Collections.emptySet();\n\n    /**\n     * default constructor for the datanode\n     */\n    DataNode() {\n        // default constructor\n    }\n\n    /**\n     * create a DataNode with parent, data, acls and stat\n     * \n     * @param parent\n     *            the parent of this DataNode\n     * @param data\n     *            the data to be set\n     * @param acl\n     *            the acls for this node\n     * @param stat\n     *            the stat for this node.\n     */\n    public DataNode(DataNode parent, byte data[], Long acl, StatPersisted stat) {\n        this.parent = parent;\n        this.data = data;\n        this.acl = acl;\n        this.stat = stat;\n    }\n\n    /**\n     * Method that inserts a child into the children set\n     * \n     * @param child\n     *            to be inserted\n     * @return true if this set did not already contain the specified element\n     */\n    public synchronized boolean addChild(String child) {\n        if (children == null) {\n            // let's be conservative on the typical number of children\n            children = new HashSet<String>(8);\n        }\n        return children.add(child);\n    }\n\n    /**\n     * Method that removes a child from the children set\n     * \n     * @param child\n     * @return true if this set contained the specified element\n     */\n    public synchronized boolean removeChild(String child) {\n        if (children == null) {\n            return false;\n        }\n        return children.remove(child);\n    }\n\n    /**\n     * convenience method for setting the children for this datanode\n     * \n     * @param children\n     */\n    public synchronized void setChildren(HashSet<String> children) {\n        this.children = children;\n    }\n\n    /**\n     * convenience methods to get the children\n     * \n     * @return the children of this datanode\n     */\n    public synchronized Set<String> getChildren() {\n        if (children == null) {\n            return EMPTY_SET;\n        }\n\n        return Collections.unmodifiableSet(children);\n    }\n\n    synchronized public void copyStat(Stat to) {\n        to.setAversion(stat.getAversion());\n        to.setCtime(stat.getCtime());\n        to.setCzxid(stat.getCzxid());\n        to.setMtime(stat.getMtime());\n        to.setMzxid(stat.getMzxid());\n        to.setPzxid(stat.getPzxid());\n        to.setVersion(stat.getVersion());\n        to.setEphemeralOwner(stat.getEphemeralOwner());\n        to.setDataLength(data == null ? 0 : data.length);\n        int numChildren = 0;\n        if (this.children != null) {\n            numChildren = children.size();\n        }\n        // when we do the Cversion we need to translate from the count of the creates\n        // to the count of the changes (v3 semantics)\n        // for every create there is a delete except for the children still present\n        to.setCversion(stat.getCversion()*2 - numChildren);\n        to.setNumChildren(numChildren);\n    }\n\n    synchronized public void deserialize(InputArchive archive, String tag)\n            throws IOException {\n        archive.startRecord(\"node\");\n        data = archive.readBuffer(\"data\");\n        acl = archive.readLong(\"acl\");\n        stat = new StatPersisted();\n        stat.deserialize(archive, \"statpersisted\");\n        archive.endRecord(\"node\");\n    }\n\n    synchronized public void serialize(OutputArchive archive, String tag)\n            throws IOException {\n        archive.startRecord(this, \"node\");\n        archive.writeBuffer(data, \"data\");\n        archive.writeLong(acl, \"acl\");\n        stat.serialize(archive, \"statpersisted\");\n        archive.endRecord(this, \"node\");\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/DataTree.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.Quotas;\nimport org.apache.zookeeper.StatsTrack;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.common.PathTrie;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.data.StatPersisted;\nimport org.apache.zookeeper.server.upgrade.DataNodeV1;\nimport org.apache.zookeeper.txn.CheckVersionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.MultiTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.Txn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class maintains the tree data structure. It doesn't have any networking\n * or client connection code in it so that it can be tested in a stand alone\n * way.\n * <p>\n * The tree maintains two parallel data structures: a hashtable that maps from\n * full paths to DataNodes and a tree of DataNodes. All accesses to a path is\n * through the hashtable. The tree is traversed only when serializing to disk.\n */\npublic class DataTree {\n    private static final Logger LOG = LoggerFactory.getLogger(DataTree.class);\n\n    /**\n     * This hashtable provides a fast lookup to the datanodes. The tree is the\n     * source of truth and is where all the locking occurs\n     */\n    private final ConcurrentHashMap<String, DataNode> nodes =\n        new ConcurrentHashMap<String, DataNode>();\n\n    private final WatchManager dataWatches = new WatchManager();\n\n    private final WatchManager childWatches = new WatchManager();\n\n    /** the root of zookeeper tree */\n    private static final String rootZookeeper = \"/\";\n\n    /** the zookeeper nodes that acts as the management and status node **/\n    private static final String procZookeeper = Quotas.procZookeeper;\n\n    /** this will be the string thats stored as a child of root */\n    private static final String procChildZookeeper = procZookeeper.substring(1);\n\n    /**\n     * the zookeeper quota node that acts as the quota management node for\n     * zookeeper\n     */\n    private static final String quotaZookeeper = Quotas.quotaZookeeper;\n\n    /** this will be the string thats stored as a child of /zookeeper */\n    private static final String quotaChildZookeeper = quotaZookeeper\n            .substring(procZookeeper.length() + 1);\n\n    /**\n     * the path trie that keeps track fo the quota nodes in this datatree\n     */\n    private final PathTrie pTrie = new PathTrie();\n\n    /**\n     * This hashtable lists the paths of the ephemeral nodes of a session.\n     */\n    private final Map<Long, HashSet<String>> ephemerals =\n        new ConcurrentHashMap<Long, HashSet<String>>();\n\n    private final ReferenceCountedACLCache aclCache = new ReferenceCountedACLCache();\n\n    @SuppressWarnings(\"unchecked\")\n    public HashSet<String> getEphemerals(long sessionId) {\n        HashSet<String> retv = ephemerals.get(sessionId);\n        if (retv == null) {\n            return new HashSet<String>();\n        }\n        HashSet<String> cloned = null;\n        synchronized (retv) {\n            cloned = (HashSet<String>) retv.clone();\n        }\n        return cloned;\n    }\n\n    public Map<Long, HashSet<String>> getEphemeralsMap() {\n        return ephemerals;\n    }\n\n\n    public Collection<Long> getSessions() {\n        return ephemerals.keySet();\n    }\n\n    /**\n     * just an accessor method to allow raw creation of datatree's from a bunch\n     * of datanodes\n     *\n     * @param path\n     *            the path of the datanode\n     * @param node\n     *            the datanode corresponding to this path\n     */\n    public void addDataNode(String path, DataNode node) {\n        nodes.put(path, node);\n    }\n\n    public DataNode getNode(String path) {\n        return nodes.get(path);\n    }\n\n    public int getNodeCount() {\n        return nodes.size();\n    }\n\n    public int getWatchCount() {\n        return dataWatches.size() + childWatches.size();\n    }\n\n    public int getEphemeralsCount() {\n        Map<Long, HashSet<String>> map = this.getEphemeralsMap();\n        int result = 0;\n        for (HashSet<String> set : map.values()) {\n            result += set.size();\n        }\n        return result;\n    }\n\n    /**\n     * Get the size of the nodes based on path and data length.\n     *\n     * @return size of the data\n     */\n    public long approximateDataSize() {\n        long result = 0;\n        for (Map.Entry<String, DataNode> entry : nodes.entrySet()) {\n            DataNode value = entry.getValue();\n            synchronized (value) {\n                result += entry.getKey().length();\n                result += (value.data == null ? 0\n                        : value.data.length);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * This is a pointer to the root of the DataTree. It is the source of truth,\n     * but we usually use the nodes hashmap to find nodes in the tree.\n     */\n    private DataNode root = new DataNode(null, new byte[0], -1L,\n            new StatPersisted());\n\n    /**\n     * create a /zookeeper filesystem that is the proc filesystem of zookeeper\n     */\n    private DataNode procDataNode = new DataNode(root, new byte[0], -1L,\n            new StatPersisted());\n\n    /**\n     * create a /zookeeper/quota node for maintaining quota properties for\n     * zookeeper\n     */\n    private DataNode quotaDataNode = new DataNode(procDataNode, new byte[0],\n            -1L, new StatPersisted());\n\n    public DataTree() {\n        /* Rather than fight it, let root have an alias */\n        nodes.put(\"\", root);\n        nodes.put(rootZookeeper, root);\n\n        /** add the proc node and quota node */\n        root.addChild(procChildZookeeper);\n        nodes.put(procZookeeper, procDataNode);\n\n        procDataNode.addChild(quotaChildZookeeper);\n        nodes.put(quotaZookeeper, quotaDataNode);\n    }\n\n    /**\n     * is the path one of the special paths owned by zookeeper.\n     *\n     * @param path\n     *            the path to be checked\n     * @return true if a special path. false if not.\n     */\n    boolean isSpecialPath(String path) {\n        if (rootZookeeper.equals(path) || procZookeeper.equals(path)\n                || quotaZookeeper.equals(path)) {\n            return true;\n        }\n        return false;\n    }\n\n    static public void copyStatPersisted(StatPersisted from, StatPersisted to) {\n        to.setAversion(from.getAversion());\n        to.setCtime(from.getCtime());\n        to.setCversion(from.getCversion());\n        to.setCzxid(from.getCzxid());\n        to.setMtime(from.getMtime());\n        to.setMzxid(from.getMzxid());\n        to.setPzxid(from.getPzxid());\n        to.setVersion(from.getVersion());\n        to.setEphemeralOwner(from.getEphemeralOwner());\n    }\n\n    static public void copyStat(Stat from, Stat to) {\n        to.setAversion(from.getAversion());\n        to.setCtime(from.getCtime());\n        to.setCversion(from.getCversion());\n        to.setCzxid(from.getCzxid());\n        to.setMtime(from.getMtime());\n        to.setMzxid(from.getMzxid());\n        to.setPzxid(from.getPzxid());\n        to.setVersion(from.getVersion());\n        to.setEphemeralOwner(from.getEphemeralOwner());\n        to.setDataLength(from.getDataLength());\n        to.setNumChildren(from.getNumChildren());\n    }\n\n    /**\n     * update the count of this stat datanode\n     *\n     * @param lastPrefix\n     *            the path of the node that is quotaed.\n     * @param diff\n     *            the diff to be added to the count\n     */\n    public void updateCount(String lastPrefix, int diff) {\n        String statNode = Quotas.statPath(lastPrefix);\n        DataNode node = nodes.get(statNode);\n        StatsTrack updatedStat = null;\n        if (node == null) {\n            // should not happen\n            LOG.error(\"Missing count node for stat \" + statNode);\n            return;\n        }\n        synchronized (node) {\n            updatedStat = new StatsTrack(new String(node.data));\n            updatedStat.setCount(updatedStat.getCount() + diff);\n            node.data = updatedStat.toString().getBytes();\n        }\n        // now check if the counts match the quota\n        String quotaNode = Quotas.quotaPath(lastPrefix);\n        node = nodes.get(quotaNode);\n        StatsTrack thisStats = null;\n        if (node == null) {\n            // should not happen\n            LOG.error(\"Missing count node for quota \" + quotaNode);\n            return;\n        }\n        synchronized (node) {\n            thisStats = new StatsTrack(new String(node.data));\n        }\n        if (thisStats.getCount() > -1 && (thisStats.getCount() < updatedStat.getCount())) {\n            LOG\n            .warn(\"Quota exceeded: \" + lastPrefix + \" count=\"\n                    + updatedStat.getCount() + \" limit=\"\n                    + thisStats.getCount());\n        }\n    }\n\n    /**\n     * update the count of bytes of this stat datanode\n     *\n     * @param lastPrefix\n     *            the path of the node that is quotaed\n     * @param diff\n     *            the diff to added to number of bytes\n     * @throws IOException\n     *             if path is not found\n     */\n    public void updateBytes(String lastPrefix, long diff) {\n        String statNode = Quotas.statPath(lastPrefix);\n        DataNode node = nodes.get(statNode);\n        if (node == null) {\n            // should never be null but just to make\n            // findbugs happy\n            LOG.error(\"Missing stat node for bytes \" + statNode);\n            return;\n        }\n        StatsTrack updatedStat = null;\n        synchronized (node) {\n            updatedStat = new StatsTrack(new String(node.data));\n            updatedStat.setBytes(updatedStat.getBytes() + diff);\n            node.data = updatedStat.toString().getBytes();\n        }\n        // now check if the bytes match the quota\n        String quotaNode = Quotas.quotaPath(lastPrefix);\n        node = nodes.get(quotaNode);\n        if (node == null) {\n            // should never be null but just to make\n            // findbugs happy\n            LOG.error(\"Missing quota node for bytes \" + quotaNode);\n            return;\n        }\n        StatsTrack thisStats = null;\n        synchronized (node) {\n            thisStats = new StatsTrack(new String(node.data));\n        }\n        if (thisStats.getBytes() > -1 && (thisStats.getBytes() < updatedStat.getBytes())) {\n            LOG\n            .warn(\"Quota exceeded: \" + lastPrefix + \" bytes=\"\n                    + updatedStat.getBytes() + \" limit=\"\n                    + thisStats.getBytes());\n        }\n    }\n\n    /**\n     * @param path\n     * @param data\n     * @param acl\n     * @param ephemeralOwner\n     *            the session id that owns this node. -1 indicates this is not\n     *            an ephemeral node.\n     * @param zxid\n     * @param time\n     * @return the patch of the created node\n     * @throws KeeperException\n     */\n    public String createNode(String path, byte data[], List<ACL> acl,\n            long ephemeralOwner, int parentCVersion, long zxid, long time)\n            throws KeeperException.NoNodeException,\n            KeeperException.NodeExistsException {\n        int lastSlash = path.lastIndexOf('/');\n        String parentName = path.substring(0, lastSlash);\n        String childName = path.substring(lastSlash + 1);\n        StatPersisted stat = new StatPersisted();\n        stat.setCtime(time);\n        stat.setMtime(time);\n        stat.setCzxid(zxid);\n        stat.setMzxid(zxid);\n        stat.setPzxid(zxid);\n        stat.setVersion(0);\n        stat.setAversion(0);\n        stat.setEphemeralOwner(ephemeralOwner);\n        DataNode parent = nodes.get(parentName);\n        if (parent == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (parent) {\n            Set<String> children = parent.getChildren();\n            if (children.contains(childName)) {\n                throw new KeeperException.NodeExistsException();\n            }\n            \n            if (parentCVersion == -1) {\n                parentCVersion = parent.stat.getCversion();\n                parentCVersion++;\n            }    \n            parent.stat.setCversion(parentCVersion);\n            parent.stat.setPzxid(zxid);\n            Long longval = aclCache.convertAcls(acl);\n            DataNode child = new DataNode(parent, data, longval, stat);\n            parent.addChild(childName);\n            nodes.put(path, child);\n            if (ephemeralOwner != 0) {\n                HashSet<String> list = ephemerals.get(ephemeralOwner);\n                if (list == null) {\n                    list = new HashSet<String>();\n                    ephemerals.put(ephemeralOwner, list);\n                }\n                synchronized (list) {\n                    list.add(path);\n                }\n            }\n        }\n        // now check if its one of the zookeeper node child\n        if (parentName.startsWith(quotaZookeeper)) {\n            // now check if its the limit node\n            if (Quotas.limitNode.equals(childName)) {\n                // this is the limit node\n                // get the parent and add it to the trie\n                pTrie.addPath(parentName.substring(quotaZookeeper.length()));\n            }\n            if (Quotas.statNode.equals(childName)) {\n                updateQuotaForPath(parentName\n                        .substring(quotaZookeeper.length()));\n            }\n        }\n        // also check to update the quotas for this node\n        String lastPrefix;\n        if((lastPrefix = getMaxPrefixWithQuota(path)) != null) {\n            // ok we have some match and need to update\n            updateCount(lastPrefix, 1);\n            updateBytes(lastPrefix, data == null ? 0 : data.length);\n        }\n        dataWatches.triggerWatch(path, Event.EventType.NodeCreated);\n        childWatches.triggerWatch(parentName.equals(\"\") ? \"/\" : parentName,\n                Event.EventType.NodeChildrenChanged);\n        return path;\n    }\n\n    /**\n     * remove the path from the datatree\n     *\n     * @param path\n     *            the path to of the node to be deleted\n     * @param zxid\n     *            the current zxid\n     * @throws KeeperException.NoNodeException\n     */\n    public void deleteNode(String path, long zxid)\n            throws KeeperException.NoNodeException {\n        int lastSlash = path.lastIndexOf('/');\n        String parentName = path.substring(0, lastSlash);\n        String childName = path.substring(lastSlash + 1);\n        DataNode node = nodes.get(path);\n        if (node == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        nodes.remove(path);\n        synchronized (node) {\n            aclCache.removeUsage(node.acl);\n        }\n        DataNode parent = nodes.get(parentName);\n        if (parent == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (parent) {\n            parent.removeChild(childName);\n            parent.stat.setPzxid(zxid);\n            long eowner = node.stat.getEphemeralOwner();\n            if (eowner != 0) {\n                HashSet<String> nodes = ephemerals.get(eowner);\n                if (nodes != null) {\n                    synchronized (nodes) {\n                        nodes.remove(path);\n                    }\n                }\n            }\n            node.parent = null;\n        }\n        if (parentName.startsWith(procZookeeper)) {\n            // delete the node in the trie.\n            if (Quotas.limitNode.equals(childName)) {\n                // we need to update the trie\n                // as well\n                pTrie.deletePath(parentName.substring(quotaZookeeper.length()));\n            }\n        }\n\n        // also check to update the quotas for this node\n        String lastPrefix;\n        if((lastPrefix = getMaxPrefixWithQuota(path)) != null) {\n            // ok we have some match and need to update\n            updateCount(lastPrefix, -1);\n            int bytes = 0;\n            synchronized (node) {\n                bytes = (node.data == null ? 0 : -(node.data.length));\n            }\n            updateBytes(lastPrefix, bytes);\n        }\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,\n                    \"dataWatches.triggerWatch \" + path);\n            ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,\n                    \"childWatches.triggerWatch \" + parentName);\n        }\n        Set<Watcher> processed = dataWatches.triggerWatch(path,\n                EventType.NodeDeleted);\n        childWatches.triggerWatch(path, EventType.NodeDeleted, processed);\n        childWatches.triggerWatch(parentName.equals(\"\") ? \"/\" : parentName,\n                EventType.NodeChildrenChanged);\n    }\n\n    public Stat setData(String path, byte data[], int version, long zxid,\n            long time) throws KeeperException.NoNodeException {\n        Stat s = new Stat();\n        DataNode n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        byte lastdata[] = null;\n        synchronized (n) {\n            lastdata = n.data;\n            n.data = data;\n            n.stat.setMtime(time);\n            n.stat.setMzxid(zxid);\n            n.stat.setVersion(version);\n            n.copyStat(s);\n        }\n        // now update if the path is in a quota subtree.\n        String lastPrefix;\n        if((lastPrefix = getMaxPrefixWithQuota(path)) != null) {\n          this.updateBytes(lastPrefix, (data == null ? 0 : data.length)\n              - (lastdata == null ? 0 : lastdata.length));\n        }\n        dataWatches.triggerWatch(path, EventType.NodeDataChanged);\n        return s;\n    }\n\n    /**\n     * If there is a quota set, return the appropriate prefix for that quota\n     * Else return null\n     * @param path The ZK path to check for quota\n     * @return Max quota prefix, or null if none\n     */\n    public String getMaxPrefixWithQuota(String path) {\n        // do nothing for the root.\n        // we are not keeping a quota on the zookeeper\n        // root node for now.\n        String lastPrefix = pTrie.findMaxPrefix(path);\n\n        if (!rootZookeeper.equals(lastPrefix) && !(\"\".equals(lastPrefix))) {\n            return lastPrefix;\n        }\n        else {\n            return null;\n        }\n    }\n\n    public byte[] getData(String path, Stat stat, Watcher watcher)\n            throws KeeperException.NoNodeException {\n        DataNode n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            if (watcher != null) {\n                dataWatches.addWatch(path, watcher);\n            }\n            return n.data;\n        }\n    }\n\n    public Stat statNode(String path, Watcher watcher)\n            throws KeeperException.NoNodeException {\n        Stat stat = new Stat();\n        DataNode n = nodes.get(path);\n        if (watcher != null) {\n            dataWatches.addWatch(path, watcher);\n        }\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            return stat;\n        }\n    }\n\n    public List<String> getChildren(String path, Stat stat, Watcher watcher)\n            throws KeeperException.NoNodeException {\n        DataNode n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            if (stat != null) {\n                n.copyStat(stat);\n            }\n            List<String> children = new ArrayList<String>(n.getChildren());\n\n            if (watcher != null) {\n                childWatches.addWatch(path, watcher);\n            }\n            return children;\n        }\n    }\n\n    public Stat setACL(String path, List<ACL> acl, int version)\n            throws KeeperException.NoNodeException {\n        Stat stat = new Stat();\n        DataNode n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            aclCache.removeUsage(n.acl);\n            n.stat.setAversion(version);\n            n.acl = aclCache.convertAcls(acl);\n            n.copyStat(stat);\n            return stat;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List<ACL> getACL(String path, Stat stat)\n            throws KeeperException.NoNodeException {\n        DataNode n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            return new ArrayList<ACL>(aclCache.convertLong(n.acl));\n        }\n    }\n\n    public List<ACL> getACL(DataNode node) {\n        synchronized (node) {\n            return aclCache.convertLong(node.acl);\n        }\n    }\n\n    public Long getACL(DataNodeV1 oldDataNode) {\n        synchronized (oldDataNode) {\n            return aclCache.convertAcls(oldDataNode.acl);\n        }\n    }\n\n    public int aclCacheSize() {\n        return aclCache.size();\n    }\n\n    static public class ProcessTxnResult {\n        public long clientId;\n\n        public int cxid;\n\n        public long zxid;\n\n        public int err;\n\n        public int type;\n\n        public String path;\n\n        public Stat stat;\n\n        public List<ProcessTxnResult> multiResult;\n        \n        /**\n         * Equality is defined as the clientId and the cxid being the same. This\n         * allows us to use hash tables to track completion of transactions.\n         *\n         * @see java.lang.Object#equals(java.lang.Object)\n         */\n        @Override\n        public boolean equals(Object o) {\n            if (o instanceof ProcessTxnResult) {\n                ProcessTxnResult other = (ProcessTxnResult) o;\n                return other.clientId == clientId && other.cxid == cxid;\n            }\n            return false;\n        }\n\n        /**\n         * See equals() to find the rational for how this hashcode is generated.\n         *\n         * @see ProcessTxnResult#equals(Object)\n         * @see java.lang.Object#hashCode()\n         */\n        @Override\n        public int hashCode() {\n            return (int) ((clientId ^ cxid) % Integer.MAX_VALUE);\n        }\n\n    }\n\n    public volatile long lastProcessedZxid = 0;\n\n    public ProcessTxnResult processTxn(TxnHeader header, Record txn)\n    {\n        ProcessTxnResult rc = new ProcessTxnResult();\n\n        try {\n            rc.clientId = header.getClientId();\n            rc.cxid = header.getCxid();\n            rc.zxid = header.getZxid();\n            rc.type = header.getType();\n            rc.err = 0;\n            rc.multiResult = null;\n            switch (header.getType()) {\n                case OpCode.create:\n                    CreateTxn createTxn = (CreateTxn) txn;\n                    rc.path = createTxn.getPath();\n                    createNode(\n                            createTxn.getPath(),\n                            createTxn.getData(),\n                            createTxn.getAcl(),\n                            createTxn.getEphemeral() ? header.getClientId() : 0,\n                            createTxn.getParentCVersion(),\n                            header.getZxid(), header.getTime());\n                    break;\n                case OpCode.delete:\n                    DeleteTxn deleteTxn = (DeleteTxn) txn;\n                    rc.path = deleteTxn.getPath();\n                    deleteNode(deleteTxn.getPath(), header.getZxid());\n                    break;\n                case OpCode.setData:\n                    SetDataTxn setDataTxn = (SetDataTxn) txn;\n                    rc.path = setDataTxn.getPath();\n                    rc.stat = setData(setDataTxn.getPath(), setDataTxn\n                            .getData(), setDataTxn.getVersion(), header\n                            .getZxid(), header.getTime());\n                    break;\n                case OpCode.setACL:\n                    SetACLTxn setACLTxn = (SetACLTxn) txn;\n                    rc.path = setACLTxn.getPath();\n                    rc.stat = setACL(setACLTxn.getPath(), setACLTxn.getAcl(),\n                            setACLTxn.getVersion());\n                    break;\n                case OpCode.closeSession:\n                    killSession(header.getClientId(), header.getZxid());\n                    break;\n                case OpCode.error:\n                    ErrorTxn errTxn = (ErrorTxn) txn;\n                    rc.err = errTxn.getErr();\n                    break;\n                case OpCode.check:\n                    CheckVersionTxn checkTxn = (CheckVersionTxn) txn;\n                    rc.path = checkTxn.getPath();\n                    break;\n                case OpCode.multi:\n                    MultiTxn multiTxn = (MultiTxn) txn ;\n                    List<Txn> txns = multiTxn.getTxns();\n                    rc.multiResult = new ArrayList<ProcessTxnResult>();\n                    boolean failed = false;\n                    for (Txn subtxn : txns) {\n                        if (subtxn.getType() == OpCode.error) {\n                            failed = true;\n                            break;\n                        }\n                    }\n\n                    boolean post_failed = false;\n                    for (Txn subtxn : txns) {\n                        ByteBuffer bb = ByteBuffer.wrap(subtxn.getData());\n                        Record record = null;\n                        switch (subtxn.getType()) {\n                            case OpCode.create:\n                                record = new CreateTxn();\n                                break;\n                            case OpCode.delete:\n                                record = new DeleteTxn();\n                                break;\n                            case OpCode.setData:\n                                record = new SetDataTxn();\n                                break;\n                            case OpCode.error:\n                                record = new ErrorTxn();\n                                post_failed = true;\n                                break;\n                            case OpCode.check:\n                                record = new CheckVersionTxn();\n                                break;\n                            default:\n                                throw new IOException(\"Invalid type of op: \" + subtxn.getType());\n                        }\n                        assert(record != null);\n\n                        ByteBufferInputStream.byteBuffer2Record(bb, record);\n                       \n                        if (failed && subtxn.getType() != OpCode.error){\n                            int ec = post_failed ? Code.RUNTIMEINCONSISTENCY.intValue() \n                                                 : Code.OK.intValue();\n\n                            subtxn.setType(OpCode.error);\n                            record = new ErrorTxn(ec);\n                        }\n\n                        if (failed) {\n                            assert(subtxn.getType() == OpCode.error) ;\n                        }\n\n                        TxnHeader subHdr = new TxnHeader(header.getClientId(), header.getCxid(),\n                                                         header.getZxid(), header.getTime(), \n                                                         subtxn.getType());\n                        ProcessTxnResult subRc = processTxn(subHdr, record);\n                        rc.multiResult.add(subRc);\n                        if (subRc.err != 0 && rc.err == 0) {\n                            rc.err = subRc.err ;\n                        }\n                    }\n                    break;\n            }\n        } catch (KeeperException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Failed: \" + header + \":\" + txn, e);\n            }\n            rc.err = e.code().intValue();\n        } catch (IOException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Failed: \" + header + \":\" + txn, e);\n            }\n        }\n        /*\n         * A snapshot might be in progress while we are modifying the data\n         * tree. If we set lastProcessedZxid prior to making corresponding\n         * change to the tree, then the zxid associated with the snapshot\n         * file will be ahead of its contents. Thus, while restoring from\n         * the snapshot, the restore method will not apply the transaction\n         * for zxid associated with the snapshot file, since the restore\n         * method assumes that transaction to be present in the snapshot.\n         *\n         * To avoid this, we first apply the transaction and then modify\n         * lastProcessedZxid.  During restore, we correctly handle the\n         * case where the snapshot contains data ahead of the zxid associated\n         * with the file.\n         */\n        if (rc.zxid > lastProcessedZxid) {\n        \tlastProcessedZxid = rc.zxid;\n        }\n\n        /*\n         * Snapshots are taken lazily. It can happen that the child\n         * znodes of a parent are created after the parent\n         * is serialized. Therefore, while replaying logs during restore, a\n         * create might fail because the node was already\n         * created.\n         *\n         * After seeing this failure, we should increment\n         * the cversion of the parent znode since the parent was serialized\n         * before its children.\n         *\n         * Note, such failures on DT should be seen only during\n         * restore.\n         */\n        if (header.getType() == OpCode.create &&\n                rc.err == Code.NODEEXISTS.intValue()) {\n            LOG.debug(\"Adjusting parent cversion for Txn: \" + header.getType() +\n                    \" path:\" + rc.path + \" err: \" + rc.err);\n            int lastSlash = rc.path.lastIndexOf('/');\n            String parentName = rc.path.substring(0, lastSlash);\n            CreateTxn cTxn = (CreateTxn)txn;\n            try {\n                setCversionPzxid(parentName, cTxn.getParentCVersion(),\n                        header.getZxid());\n            } catch (KeeperException.NoNodeException e) {\n                LOG.error(\"Failed to set parent cversion for: \" +\n                      parentName, e);\n                rc.err = e.code().intValue();\n            }\n        } else if (rc.err != Code.OK.intValue()) {\n            LOG.debug(\"Ignoring processTxn failure hdr: \" + header.getType() +\n                  \" : error: \" + rc.err);\n        }\n        return rc;\n    }\n\n    void killSession(long session, long zxid) {\n        // the list is already removed from the ephemerals\n        // so we do not have to worry about synchronizing on\n        // the list. This is only called from FinalRequestProcessor\n        // so there is no need for synchronization. The list is not\n        // changed here. Only create and delete change the list which\n        // are again called from FinalRequestProcessor in sequence.\n        HashSet<String> list = ephemerals.remove(session);\n        if (list != null) {\n            for (String path : list) {\n                try {\n                    deleteNode(path, zxid);\n                    if (LOG.isDebugEnabled()) {\n                        LOG\n                                .debug(\"Deleting ephemeral node \" + path\n                                        + \" for session 0x\"\n                                        + Long.toHexString(session));\n                    }\n                } catch (NoNodeException e) {\n                    LOG.warn(\"Ignoring NoNodeException for path \" + path\n                            + \" while removing ephemeral for dead session 0x\"\n                            + Long.toHexString(session));\n                }\n            }\n        }\n    }\n\n    /**\n     * a encapsultaing class for return value\n     */\n    private static class Counts {\n        long bytes;\n        int count;\n    }\n\n    /**\n     * this method gets the count of nodes and the bytes under a subtree\n     *\n     * @param path\n     *            the path to be used\n     * @param counts\n     *            the int count\n     */\n    private void getCounts(String path, Counts counts) {\n        DataNode node = getNode(path);\n        if (node == null) {\n            return;\n        }\n        String[] children = null;\n        int len = 0;\n        synchronized (node) {\n            Set<String> childs = node.getChildren();\n            children = childs.toArray(new String[childs.size()]);\n            len = (node.data == null ? 0 : node.data.length);\n        }\n        // add itself\n        counts.count += 1;\n        counts.bytes += len;\n        for (String child : children) {\n            getCounts(path + \"/\" + child, counts);\n        }\n    }\n\n    /**\n     * update the quota for the given path\n     *\n     * @param path\n     *            the path to be used\n     */\n    private void updateQuotaForPath(String path) {\n        Counts c = new Counts();\n        getCounts(path, c);\n        StatsTrack strack = new StatsTrack();\n        strack.setBytes(c.bytes);\n        strack.setCount(c.count);\n        String statPath = Quotas.quotaZookeeper + path + \"/\" + Quotas.statNode;\n        DataNode node = getNode(statPath);\n        // it should exist\n        if (node == null) {\n            LOG.warn(\"Missing quota stat node \" + statPath);\n            return;\n        }\n        synchronized (node) {\n            node.data = strack.toString().getBytes();\n        }\n    }\n\n    /**\n     * this method traverses the quota path and update the path trie and sets\n     *\n     * @param path\n     */\n    private void traverseNode(String path) {\n        DataNode node = getNode(path);\n        String children[] = null;\n        synchronized (node) {\n            Set<String> childs = node.getChildren();\n            children = childs.toArray(new String[childs.size()]);\n        }\n        if (children.length == 0) {\n            // this node does not have a child\n            // is the leaf node\n            // check if its the leaf node\n            String endString = \"/\" + Quotas.limitNode;\n            if (path.endsWith(endString)) {\n                // ok this is the limit node\n                // get the real node and update\n                // the count and the bytes\n                String realPath = path.substring(Quotas.quotaZookeeper\n                        .length(), path.indexOf(endString));\n                updateQuotaForPath(realPath);\n                this.pTrie.addPath(realPath);\n            }\n            return;\n        }\n        for (String child : children) {\n            traverseNode(path + \"/\" + child);\n        }\n    }\n\n    /**\n     * this method sets up the path trie and sets up stats for quota nodes\n     */\n    private void setupQuota() {\n        String quotaPath = Quotas.quotaZookeeper;\n        DataNode node = getNode(quotaPath);\n        if (node == null) {\n            return;\n        }\n        traverseNode(quotaPath);\n    }\n\n    /**\n     * this method uses a stringbuilder to create a new path for children. This\n     * is faster than string appends ( str1 + str2).\n     *\n     * @param oa\n     *            OutputArchive to write to.\n     * @param path\n     *            a string builder.\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    void serializeNode(OutputArchive oa, StringBuilder path) throws IOException {\n        String pathString = path.toString();\n        DataNode node = getNode(pathString);\n        if (node == null) {\n            return;\n        }\n        String children[] = null;\n        DataNode nodeCopy;\n        synchronized (node) {\n            scount++;\n            StatPersisted statCopy = new StatPersisted();\n            copyStatPersisted(node.stat, statCopy);\n            //we do not need to make a copy of node.data because the contents\n            //are never changed\n            nodeCopy = new DataNode(node.parent, node.data, node.acl, statCopy);\n            Set<String> childs = node.getChildren();\n            children = childs.toArray(new String[childs.size()]);\n        }\n        oa.writeString(pathString, \"path\");\n        oa.writeRecord(nodeCopy, \"node\");\n        path.append('/');\n        int off = path.length();\n        for (String child : children) {\n            // since this is single buffer being resused\n            // we need\n            // to truncate the previous bytes of string.\n            path.delete(off, Integer.MAX_VALUE);\n            path.append(child);\n            serializeNode(oa, path);\n        }\n    }\n\n    int scount;\n\n    public boolean initialized = false;\n\n    public void serialize(OutputArchive oa, String tag) throws IOException {\n        scount = 0;\n        aclCache.serialize(oa);\n        serializeNode(oa, new StringBuilder(\"\"));\n        // / marks end of stream\n        // we need to check if clear had been called in between the snapshot.\n        if (root != null) {\n            oa.writeString(\"/\", \"path\");\n        }\n    }\n\n    public void deserialize(InputArchive ia, String tag) throws IOException {\n        aclCache.deserialize(ia);\n        nodes.clear();\n        pTrie.clear();\n        String path = ia.readString(\"path\");\n        while (!path.equals(\"/\")) {\n            DataNode node = new DataNode();\n            ia.readRecord(node, \"node\");\n            nodes.put(path, node);\n            synchronized (node) {\n                aclCache.addUsage(node.acl);\n            }\n            int lastSlash = path.lastIndexOf('/');\n            if (lastSlash == -1) {\n                root = node;\n            } else {\n                String parentPath = path.substring(0, lastSlash);\n                node.parent = nodes.get(parentPath);\n                if (node.parent == null) {\n                    throw new IOException(\"Invalid Datatree, unable to find \" +\n                            \"parent \" + parentPath + \" of path \" + path);\n                }\n                node.parent.addChild(path.substring(lastSlash + 1));\n                long eowner = node.stat.getEphemeralOwner();\n                if (eowner != 0) {\n                    HashSet<String> list = ephemerals.get(eowner);\n                    if (list == null) {\n                        list = new HashSet<String>();\n                        ephemerals.put(eowner, list);\n                    }\n                    list.add(path);\n                }\n            }\n            path = ia.readString(\"path\");\n        }\n        nodes.put(\"/\", root);\n        // we are done with deserializing the\n        // the datatree\n        // update the quotas - create path trie\n        // and also update the stat nodes\n        setupQuota();\n\n        aclCache.purgeUnused();\n    }\n\n    /**\n     * Summary of the watches on the datatree.\n     * @param pwriter the output to write to\n     */\n    public synchronized void dumpWatchesSummary(PrintWriter pwriter) {\n        pwriter.print(dataWatches.toString());\n    }\n\n    /**\n     * Write a text dump of all the watches on the datatree.\n     * Warning, this is expensive, use sparingly!\n     * @param pwriter the output to write to\n     */\n    public synchronized void dumpWatches(PrintWriter pwriter, boolean byPath) {\n        dataWatches.dumpWatches(pwriter, byPath);\n    }\n\n    /**\n     * Write a text dump of all the ephemerals in the datatree.\n     * @param pwriter the output to write to\n     */\n    public void dumpEphemerals(PrintWriter pwriter) {\n        Set<Map.Entry<Long, HashSet<String>>> entrySet = ephemerals.entrySet();\n        pwriter.println(\"Sessions with Ephemerals (\"\n                + entrySet.size() + \"):\");\n        for (Map.Entry<Long, HashSet<String>> entry : entrySet) {\n            pwriter.print(\"0x\" + Long.toHexString(entry.getKey()));\n            pwriter.println(\":\");\n            HashSet<String> tmp = entry.getValue();\n            if (tmp != null) {\n                synchronized (tmp) {\n                    for (String path : tmp) {\n                        pwriter.println(\"\\t\" + path);\n                    }\n                }\n            }\n        }\n    }\n\n    public void removeCnxn(Watcher watcher) {\n        dataWatches.removeWatcher(watcher);\n        childWatches.removeWatcher(watcher);\n    }\n\n    public void clear() {\n        root = null;\n        nodes.clear();\n        ephemerals.clear();\n    }\n\n    public void setWatches(long relativeZxid, List<String> dataWatches,\n            List<String> existWatches, List<String> childWatches,\n            Watcher watcher) {\n        for (String path : dataWatches) {\n            DataNode node = getNode(path);\n            if (node == null) {\n                watcher.process(new WatchedEvent(EventType.NodeDeleted,\n                            KeeperState.SyncConnected, path));\n            } else if (node.stat.getMzxid() > relativeZxid) {\n                watcher.process(new WatchedEvent(EventType.NodeDataChanged,\n                            KeeperState.SyncConnected, path));\n            } else {\n                this.dataWatches.addWatch(path, watcher);\n            }\n        }\n        for (String path : existWatches) {\n            DataNode node = getNode(path);\n            if (node != null) {\n                watcher.process(new WatchedEvent(EventType.NodeCreated,\n                            KeeperState.SyncConnected, path));\n            } else {\n                this.dataWatches.addWatch(path, watcher);\n            }\n        }\n        for (String path : childWatches) {\n            DataNode node = getNode(path);\n            if (node == null) {\n                watcher.process(new WatchedEvent(EventType.NodeDeleted,\n                            KeeperState.SyncConnected, path));\n            } else if (node.stat.getPzxid() > relativeZxid) {\n                watcher.process(new WatchedEvent(EventType.NodeChildrenChanged,\n                            KeeperState.SyncConnected, path));\n            } else {\n                this.childWatches.addWatch(path, watcher);\n            }\n        }\n    }\n\n     /**\n      * This method sets the Cversion and Pzxid for the specified node to the\n      * values passed as arguments. The values are modified only if newCversion\n      * is greater than the current Cversion. A NoNodeException is thrown if\n      * a znode for the specified path is not found.\n      *\n      * @param path\n      *     Full path to the znode whose Cversion needs to be modified.\n      *     A \"/\" at the end of the path is ignored.\n      * @param newCversion\n      *     Value to be assigned to Cversion\n      * @param zxid\n      *     Value to be assigned to Pzxid\n      * @throws KeeperException.NoNodeException\n      *     If znode not found.\n      **/\n    public void setCversionPzxid(String path, int newCversion, long zxid)\n        throws KeeperException.NoNodeException {\n        if (path.endsWith(\"/\")) {\n           path = path.substring(0, path.length() - 1);\n        }\n        DataNode node = nodes.get(path);\n        if (node == null) {\n            throw new KeeperException.NoNodeException(path);\n        }\n        synchronized (node) {\n            if(newCversion == -1) {\n                newCversion = node.stat.getCversion() + 1;\n            }\n            if (newCversion > node.stat.getCversion()) {\n                node.stat.setCversion(newCversion);\n                node.stat.setPzxid(zxid);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/DataTreeBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\n\n/**\n * This class implements the data tree MBean.\n */\npublic class DataTreeBean implements DataTreeMXBean, ZKMBeanInfo {\n    DataTree dataTree;\n    \n    public DataTreeBean(org.apache.zookeeper.server.DataTree dataTree){\n        this.dataTree = dataTree;\n    }\n    \n    public int getNodeCount() {\n        return dataTree.getNodeCount();\n    }\n\n    public long approximateDataSize() {\n        return dataTree.approximateDataSize();\n    }\n\n    public int countEphemerals() {\n        return dataTree.getEphemeralsCount();\n    }\n\n    public int getWatchCount() {\n        return dataTree.getWatchCount();\n    }\n\n    public String getName() {\n        return \"InMemoryDataTree\";\n    }\n\n    public boolean isHidden() {\n        return false;\n    }\n\n    public String getLastZxid() {\n        return \"0x\" + Long.toHexString(dataTree.lastProcessedZxid);\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/DataTreeMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\n/**\n * Zookeeper data tree MBean.\n */\npublic interface DataTreeMXBean {\n    /**\n     * @return number of znodes in the data tree.\n     */\n    public int getNodeCount();\n    /**\n     * @return the most recent zxid processed by the data tree.\n     */\n    public String getLastZxid();\n    /**\n     * @return number of watches set.\n     */\n    public int getWatchCount();\n    \n    /**\n     * @return data tree size in bytes. The size includes the znode path and \n     * its value.\n     */\n    public long approximateDataSize();\n    /**\n     * @return number of ephemeral nodes in the data tree\n     */\n    public int countEphemerals();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/DatadirCleanupManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.File;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class manages the cleanup of snapshots and corresponding transaction\n * logs by scheduling the auto purge task with the specified\n * 'autopurge.purgeInterval'. It keeps the most recent\n * 'autopurge.snapRetainCount' number of snapshots and corresponding transaction\n * logs.\n */\npublic class DatadirCleanupManager {\n\n    private static final Logger LOG = LoggerFactory.getLogger(DatadirCleanupManager.class);\n\n    /**\n     * Status of the dataDir purge task\n     */\n    public enum PurgeTaskStatus {\n        NOT_STARTED, STARTED, COMPLETED;\n    }\n\n    private PurgeTaskStatus purgeTaskStatus = PurgeTaskStatus.NOT_STARTED;\n\n    private final String snapDir;\n\n    private final String dataLogDir;\n\n    private final int snapRetainCount;\n\n    private final int purgeInterval;\n\n    private Timer timer;\n\n    /**\n     * Constructor of DatadirCleanupManager. It takes the parameters to schedule\n     * the purge task.\n     * \n     * @param snapDir\n     *            snapshot directory\n     * @param dataLogDir\n     *            transaction log directory\n     * @param snapRetainCount\n     *            number of snapshots to be retained after purge\n     * @param purgeInterval\n     *            purge interval in hours\n     */\n    public DatadirCleanupManager(String snapDir, String dataLogDir, int snapRetainCount,\n            int purgeInterval) {\n        this.snapDir = snapDir;\n        this.dataLogDir = dataLogDir;\n        this.snapRetainCount = snapRetainCount;\n        this.purgeInterval = purgeInterval;\n        LOG.info(\"autopurge.snapRetainCount set to \" + snapRetainCount);\n        LOG.info(\"autopurge.purgeInterval set to \" + purgeInterval);\n    }\n\n    /**\n     * Validates the purge configuration and schedules the purge task. Purge\n     * task keeps the most recent <code>snapRetainCount</code> number of\n     * snapshots and deletes the remaining for every <code>purgeInterval</code>\n     * hour(s).\n     * <p>\n     * <code>purgeInterval</code> of <code>0</code> or\n     * <code>negative integer</code> will not schedule the purge task.\n     * </p>\n     * \n     * @see PurgeTxnLog#purge(File, File, int)\n     */\n    public void start() {\n        if (PurgeTaskStatus.STARTED == purgeTaskStatus) {\n            LOG.warn(\"Purge task is already running.\");\n            return;\n        }\n        // Don't schedule the purge task with zero or negative purge interval.\n        if (purgeInterval <= 0) {\n            LOG.info(\"Purge task is not scheduled.\");\n            return;\n        }\n\n        timer = new Timer(\"PurgeTask\", true);\n        TimerTask task = new PurgeTask(dataLogDir, snapDir, snapRetainCount);\n        timer.scheduleAtFixedRate(task, 0, TimeUnit.HOURS.toMillis(purgeInterval));\n\n        purgeTaskStatus = PurgeTaskStatus.STARTED;\n    }\n\n    /**\n     * Shutdown the purge task.\n     */\n    public void shutdown() {\n        if (PurgeTaskStatus.STARTED == purgeTaskStatus) {\n            LOG.info(\"Shutting down purge task.\");\n            timer.cancel();\n            purgeTaskStatus = PurgeTaskStatus.COMPLETED;\n        } else {\n            LOG.warn(\"Purge task not started. Ignoring shutdown!\");\n        }\n    }\n\n    static class PurgeTask extends TimerTask {\n        private String logsDir;\n        private String snapsDir;\n        private int snapRetainCount;\n\n        public PurgeTask(String dataDir, String snapDir, int count) {\n            logsDir = dataDir;\n            snapsDir = snapDir;\n            snapRetainCount = count;\n        }\n\n        @Override\n        public void run() {\n            LOG.info(\"Purge task started.\");\n            try {\n                PurgeTxnLog.purge(new File(logsDir), new File(snapsDir), snapRetainCount);\n            } catch (Exception e) {\n                LOG.error(\"Error occurred while purging.\", e);\n            }\n            LOG.info(\"Purge task completed.\");\n        }\n    }\n\n    /**\n     * Returns the status of the purge task.\n     * \n     * @return the status of the purge task\n     */\n    public PurgeTaskStatus getPurgeTaskStatus() {\n        return purgeTaskStatus;\n    }\n\n    /**\n     * Returns the snapshot directory.\n     * \n     * @return the snapshot directory.\n     */\n    public String getSnapDir() {\n        return snapDir;\n    }\n\n    /**\n     * Returns transaction log directory.\n     * \n     * @return the transaction log directory.\n     */\n    public String getDataLogDir() {\n        return dataLogDir;\n    }\n\n    /**\n     * Returns purge interval in hours.\n     * \n     * @return the purge interval in hours.\n     */\n    public int getPurgeInterval() {\n        return purgeInterval;\n    }\n\n    /**\n     * Returns the number of snapshots to be retained after purge.\n     * \n     * @return the number of snapshots to be retained after purge.\n     */\n    public int getSnapRetainCount() {\n        return snapRetainCount;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ExitCode.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\n/**\n * Exit code used to exit server\n */\npublic class ExitCode {\n\n    /* Represents unexpected error */\n    public final static int UNEXPECTED_ERROR = 1;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.List;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.MultiResponse;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.KeeperException.SessionMovedException;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.proto.CreateResponse;\nimport org.apache.zookeeper.proto.ExistsRequest;\nimport org.apache.zookeeper.proto.ExistsResponse;\nimport org.apache.zookeeper.proto.GetACLRequest;\nimport org.apache.zookeeper.proto.GetACLResponse;\nimport org.apache.zookeeper.proto.GetChildren2Request;\nimport org.apache.zookeeper.proto.GetChildren2Response;\nimport org.apache.zookeeper.proto.GetChildrenRequest;\nimport org.apache.zookeeper.proto.GetChildrenResponse;\nimport org.apache.zookeeper.proto.GetDataRequest;\nimport org.apache.zookeeper.proto.GetDataResponse;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.SetACLResponse;\nimport org.apache.zookeeper.proto.SetDataResponse;\nimport org.apache.zookeeper.proto.SetWatches;\nimport org.apache.zookeeper.proto.SyncRequest;\nimport org.apache.zookeeper.proto.SyncResponse;\nimport org.apache.zookeeper.server.DataTree.ProcessTxnResult;\nimport org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\nimport org.apache.zookeeper.MultiTransactionRecord;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.OpResult;\nimport org.apache.zookeeper.OpResult.CheckResult;\nimport org.apache.zookeeper.OpResult.CreateResult;\nimport org.apache.zookeeper.OpResult.DeleteResult;\nimport org.apache.zookeeper.OpResult.SetDataResult;\nimport org.apache.zookeeper.OpResult.ErrorResult;\n\n/**\n * This Request processor actually applies any transaction associated with a\n * request and services any queries. It is always at the end of a\n * RequestProcessor chain (hence the name), so it does not have a nextProcessor\n * member.\n *\n * This RequestProcessor counts on ZooKeeperServer to populate the\n * outstandingRequests member of ZooKeeperServer.\n */\npublic class FinalRequestProcessor implements RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(FinalRequestProcessor.class);\n\n    ZooKeeperServer zks;\n\n    public FinalRequestProcessor(ZooKeeperServer zks) {\n        this.zks = zks;\n    }\n\n    public void processRequest(Request request) {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Processing request:: \" + request);\n        }\n        // request.addRQRec(\">final\");\n        long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;\n        if (request.type == OpCode.ping) {\n            traceMask = ZooTrace.SERVER_PING_TRACE_MASK;\n        }\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logRequest(LOG, traceMask, 'E', request, \"\");\n        }\n        ProcessTxnResult rc = null;\n        synchronized (zks.outstandingChanges) {\n            while (!zks.outstandingChanges.isEmpty()\n                    && zks.outstandingChanges.get(0).zxid <= request.zxid) {\n                ChangeRecord cr = zks.outstandingChanges.remove(0);\n                if (cr.zxid < request.zxid) {\n                    LOG.warn(\"Zxid outstanding \"\n                            + cr.zxid\n                            + \" is less than current \" + request.zxid);\n                }\n                if (zks.outstandingChangesForPath.get(cr.path) == cr) {\n                    zks.outstandingChangesForPath.remove(cr.path);\n                }\n            }\n            if (request.hdr != null) {\n               TxnHeader hdr = request.hdr;\n               Record txn = request.txn;\n\n               rc = zks.processTxn(hdr, txn);\n            }\n            // do not add non quorum packets to the queue.\n            if (Request.isQuorum(request.type)) {\n                zks.getZKDatabase().addCommittedProposal(request);\n            }\n        }\n\n        if (request.hdr != null && request.hdr.getType() == OpCode.closeSession) {\n            ServerCnxnFactory scxn = zks.getServerCnxnFactory();\n            // this might be possible since\n            // we might just be playing diffs from the leader\n            if (scxn != null && request.cnxn == null) {\n                // calling this if we have the cnxn results in the client's\n                // close session response being lost - we've already closed\n                // the session/socket here before we can send the closeSession\n                // in the switch block below\n                scxn.closeSession(request.sessionId);\n                return;\n            }\n        }\n\n        if (request.cnxn == null) {\n            return;\n        }\n        ServerCnxn cnxn = request.cnxn;\n\n        String lastOp = \"NA\";\n        zks.decInProcess();\n        Code err = Code.OK;\n        Record rsp = null;\n        boolean closeSession = false;\n        try {\n            if (request.hdr != null && request.hdr.getType() == OpCode.error) {\n                throw KeeperException.create(KeeperException.Code.get((\n                        (ErrorTxn) request.txn).getErr()));\n            }\n\n            KeeperException ke = request.getException();\n            if (ke != null && request.type != OpCode.multi) {\n                throw ke;\n            }\n\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"{}\",request);\n            }\n            switch (request.type) {\n            case OpCode.ping: {\n                zks.serverStats().updateLatency(request.createTime);\n\n                lastOp = \"PING\";\n                cnxn.updateStatsForResponse(request.cxid, request.zxid, lastOp,\n                        request.createTime, Time.currentElapsedTime());\n\n                cnxn.sendResponse(new ReplyHeader(-2,\n                        zks.getZKDatabase().getDataTreeLastProcessedZxid(), 0), null, \"response\");\n                return;\n            }\n            case OpCode.createSession: {\n                zks.serverStats().updateLatency(request.createTime);\n\n                lastOp = \"SESS\";\n                cnxn.updateStatsForResponse(request.cxid, request.zxid, lastOp,\n                        request.createTime, Time.currentElapsedTime());\n\n                zks.finishSessionInit(request.cnxn, true);\n                return;\n            }\n            case OpCode.multi: {\n                lastOp = \"MULT\";\n                rsp = new MultiResponse() ;\n\n                for (ProcessTxnResult subTxnResult : rc.multiResult) {\n\n                    OpResult subResult ;\n\n                    switch (subTxnResult.type) {\n                        case OpCode.check:\n                            subResult = new CheckResult();\n                            break;\n                        case OpCode.create:\n                            subResult = new CreateResult(subTxnResult.path);\n                            break;\n                        case OpCode.delete:\n                            subResult = new DeleteResult();\n                            break;\n                        case OpCode.setData:\n                            subResult = new SetDataResult(subTxnResult.stat);\n                            break;\n                        case OpCode.error:\n                            subResult = new ErrorResult(subTxnResult.err) ;\n                            break;\n                        default:\n                            throw new IOException(\"Invalid type of op\");\n                    }\n\n                    ((MultiResponse)rsp).add(subResult);\n                }\n\n                break;\n            }\n            case OpCode.create: {\n                lastOp = \"CREA\";\n                rsp = new CreateResponse(rc.path);\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.delete: {\n                lastOp = \"DELE\";\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.setData: {\n                lastOp = \"SETD\";\n                rsp = new SetDataResponse(rc.stat);\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.setACL: {\n                lastOp = \"SETA\";\n                rsp = new SetACLResponse(rc.stat);\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.closeSession: {\n                lastOp = \"CLOS\";\n                closeSession = true;\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.sync: {\n                lastOp = \"SYNC\";\n                SyncRequest syncRequest = new SyncRequest();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        syncRequest);\n                rsp = new SyncResponse(syncRequest.getPath());\n                break;\n            }\n            case OpCode.check: {\n                lastOp = \"CHEC\";\n                rsp = new SetDataResponse(rc.stat);\n                err = Code.get(rc.err);\n                break;\n            }\n            case OpCode.exists: {\n                lastOp = \"EXIS\";\n                // TODO we need to figure out the security requirement for this!\n                ExistsRequest existsRequest = new ExistsRequest();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        existsRequest);\n                String path = existsRequest.getPath();\n                if (path.indexOf('\\0') != -1) {\n                    throw new KeeperException.BadArgumentsException();\n                }\n                Stat stat = zks.getZKDatabase().statNode(path, existsRequest\n                        .getWatch() ? cnxn : null);\n                rsp = new ExistsResponse(stat);\n                break;\n            }\n            case OpCode.getData: {\n                lastOp = \"GETD\";\n                GetDataRequest getDataRequest = new GetDataRequest();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        getDataRequest);\n                DataNode n = zks.getZKDatabase().getNode(getDataRequest.getPath());\n                if (n == null) {\n                    throw new KeeperException.NoNodeException();\n                }\n                PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().aclForNode(n),\n                        ZooDefs.Perms.READ,\n                        request.authInfo);\n                Stat stat = new Stat();\n                byte b[] = zks.getZKDatabase().getData(getDataRequest.getPath(), stat,\n                        getDataRequest.getWatch() ? cnxn : null);\n                rsp = new GetDataResponse(b, stat);\n                break;\n            }\n            case OpCode.setWatches: {\n                lastOp = \"SETW\";\n                SetWatches setWatches = new SetWatches();\n                // XXX We really should NOT need this!!!!\n                request.request.rewind();\n                ByteBufferInputStream.byteBuffer2Record(request.request, setWatches);\n                long relativeZxid = setWatches.getRelativeZxid();\n                zks.getZKDatabase().setWatches(relativeZxid, \n                        setWatches.getDataWatches(), \n                        setWatches.getExistWatches(),\n                        setWatches.getChildWatches(), cnxn);\n                break;\n            }\n            case OpCode.getACL: {\n                lastOp = \"GETA\";\n                GetACLRequest getACLRequest = new GetACLRequest();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        getACLRequest);\n                Stat stat = new Stat();\n                List<ACL> acl = \n                    zks.getZKDatabase().getACL(getACLRequest.getPath(), stat);\n                rsp = new GetACLResponse(acl, stat);\n                break;\n            }\n            case OpCode.getChildren: {\n                lastOp = \"GETC\";\n                GetChildrenRequest getChildrenRequest = new GetChildrenRequest();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        getChildrenRequest);\n                DataNode n = zks.getZKDatabase().getNode(getChildrenRequest.getPath());\n                if (n == null) {\n                    throw new KeeperException.NoNodeException();\n                }\n                PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().aclForNode(n),\n                        ZooDefs.Perms.READ,\n                        request.authInfo);\n                List<String> children = zks.getZKDatabase().getChildren(\n                        getChildrenRequest.getPath(), null, getChildrenRequest\n                                .getWatch() ? cnxn : null);\n                rsp = new GetChildrenResponse(children);\n                break;\n            }\n            case OpCode.getChildren2: {\n                lastOp = \"GETC\";\n                GetChildren2Request getChildren2Request = new GetChildren2Request();\n                ByteBufferInputStream.byteBuffer2Record(request.request,\n                        getChildren2Request);\n                Stat stat = new Stat();\n                DataNode n = zks.getZKDatabase().getNode(getChildren2Request.getPath());\n                if (n == null) {\n                    throw new KeeperException.NoNodeException();\n                }\n                PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().aclForNode(n),\n                        ZooDefs.Perms.READ,\n                        request.authInfo);\n                List<String> children = zks.getZKDatabase().getChildren(\n                        getChildren2Request.getPath(), stat, getChildren2Request\n                                .getWatch() ? cnxn : null);\n                rsp = new GetChildren2Response(children, stat);\n                break;\n            }\n            }\n        } catch (SessionMovedException e) {\n            // session moved is a connection level error, we need to tear\n            // down the connection otw ZOOKEEPER-710 might happen\n            // ie client on slow follower starts to renew session, fails\n            // before this completes, then tries the fast follower (leader)\n            // and is successful, however the initial renew is then \n            // successfully fwd/processed by the leader and as a result\n            // the client and leader disagree on where the client is most\n            // recently attached (and therefore invalid SESSION MOVED generated)\n            cnxn.sendCloseSession();\n            return;\n        } catch (KeeperException e) {\n            err = e.code();\n        } catch (Exception e) {\n            // log at error level as we are returning a marshalling\n            // error to the user\n            LOG.error(\"Failed to process \" + request, e);\n            StringBuilder sb = new StringBuilder();\n            ByteBuffer bb = request.request;\n            bb.rewind();\n            while (bb.hasRemaining()) {\n                sb.append(Integer.toHexString(bb.get() & 0xff));\n            }\n            LOG.error(\"Dumping request buffer: 0x\" + sb.toString());\n            err = Code.MARSHALLINGERROR;\n        }\n\n        long lastZxid = zks.getZKDatabase().getDataTreeLastProcessedZxid();\n        ReplyHeader hdr =\n            new ReplyHeader(request.cxid, lastZxid, err.intValue());\n\n        zks.serverStats().updateLatency(request.createTime);\n        cnxn.updateStatsForResponse(request.cxid, lastZxid, lastOp,\n                    request.createTime, Time.currentElapsedTime());\n\n        try {\n            cnxn.sendResponse(hdr, rsp, \"response\");\n            if (closeSession) {\n                cnxn.sendCloseSession();\n            }\n        } catch (IOException e) {\n            LOG.error(\"FIXMSG\",e);\n        }\n    }\n\n    public void shutdown() {\n        // we are the final link in the chain\n        LOG.info(\"shutdown of request processor complete\");\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/LogFormatter.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.util.Date;\nimport java.util.zip.Adler32;\nimport java.util.zip.Checksum;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.Record;\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.persistence.FileHeader;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n@InterfaceAudience.Public\npublic class LogFormatter {\n    private static final Logger LOG = LoggerFactory.getLogger(LogFormatter.class);\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) throws Exception {\n        if (args.length != 1) {\n            System.err.println(\"USAGE: LogFormatter log_file\");\n            System.exit(2);\n        }\n        FileInputStream fis = new FileInputStream(args[0]);\n        BinaryInputArchive logStream = BinaryInputArchive.getArchive(fis);\n        FileHeader fhdr = new FileHeader();\n        fhdr.deserialize(logStream, \"fileheader\");\n\n        if (fhdr.getMagic() != FileTxnLog.TXNLOG_MAGIC) {\n            System.err.println(\"Invalid magic number for \" + args[0]);\n            System.exit(2);\n        }\n        System.out.println(\"ZooKeeper Transactional Log File with dbid \"\n                + fhdr.getDbid() + \" txnlog format version \"\n                + fhdr.getVersion());\n\n        int count = 0;\n        while (true) {\n            long crcValue;\n            byte[] bytes;\n            try {\n                crcValue = logStream.readLong(\"crcvalue\");\n\n                bytes = logStream.readBuffer(\"txnEntry\");\n            } catch (EOFException e) {\n                System.out.println(\"EOF reached after \" + count + \" txns.\");\n                return;\n            }\n            if (bytes.length == 0) {\n                // Since we preallocate, we define EOF to be an\n                // empty transaction\n                System.out.println(\"EOF reached after \" + count + \" txns.\");\n                return;\n            }\n            Checksum crc = new Adler32();\n            crc.update(bytes, 0, bytes.length);\n            if (crcValue != crc.getValue()) {\n                throw new IOException(\"CRC doesn't match \" + crcValue +\n                        \" vs \" + crc.getValue());\n            }\n            TxnHeader hdr = new TxnHeader();\n            Record txn = SerializeUtils.deserializeTxn(bytes, hdr);\n            System.out.println(DateFormat.getDateTimeInstance(DateFormat.SHORT,\n                    DateFormat.LONG).format(new Date(hdr.getTime()))\n                    + \" session 0x\"\n                    + Long.toHexString(hdr.getClientId())\n                    + \" cxid 0x\"\n                    + Long.toHexString(hdr.getCxid())\n                    + \" zxid 0x\"\n                    + Long.toHexString(hdr.getZxid())\n                    + \" \" + TraceFormatter.op2String(hdr.getType()) + \" \" + txn);\n            if (logStream.readByte(\"EOR\") != 'B') {\n                LOG.error(\"Last transaction was partial.\");\n                throw new EOFException(\"Last transaction was partial.\");\n            }\n            count++;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.CancelledKeyException;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.SocketChannel;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.Environment;\nimport org.apache.zookeeper.Version;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.proto.WatcherEvent;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.server.quorum.LeaderZooKeeperServer;\nimport org.apache.zookeeper.server.quorum.ReadOnlyZooKeeperServer;\nimport org.apache.zookeeper.server.util.OSMXBean;\n\n/**\n * This class handles communication with clients using NIO. There is one per\n * client, but only one thread doing the communication.\n */\npublic class NIOServerCnxn extends ServerCnxn {\n    static final Logger LOG = LoggerFactory.getLogger(NIOServerCnxn.class);\n\n    NIOServerCnxnFactory factory;\n\n    final SocketChannel sock;\n\n    protected final SelectionKey sk;\n\n    boolean initialized;\n\n    ByteBuffer lenBuffer = ByteBuffer.allocate(4);\n\n    ByteBuffer incomingBuffer = lenBuffer;\n\n    LinkedBlockingQueue<ByteBuffer> outgoingBuffers = new LinkedBlockingQueue<ByteBuffer>();\n\n    int sessionTimeout;\n\n    protected final ZooKeeperServer zkServer;\n\n    /**\n     * The number of requests that have been submitted but not yet responded to.\n     */\n    int outstandingRequests;\n\n    /**\n     * This is the id that uniquely identifies the session of a client. Once\n     * this session is no longer active, the ephemeral nodes will go away.\n     */\n    long sessionId;\n\n    static long nextSessionId = 1;\n    int outstandingLimit = 1;\n\n    public NIOServerCnxn(ZooKeeperServer zk, SocketChannel sock,\n            SelectionKey sk, NIOServerCnxnFactory factory) throws IOException {\n        this.zkServer = zk;\n        this.sock = sock;\n        this.sk = sk;\n        this.factory = factory;\n        if (this.factory.login != null) {\n            this.zooKeeperSaslServer = new ZooKeeperSaslServer(factory.login);\n        }\n        if (zk != null) { \n            outstandingLimit = zk.getGlobalOutstandingLimit();\n        }\n        sock.socket().setTcpNoDelay(true);\n        /* set socket linger to false, so that socket close does not\n         * block */\n        sock.socket().setSoLinger(false, -1);\n        InetAddress addr = ((InetSocketAddress) sock.socket()\n                .getRemoteSocketAddress()).getAddress();\n        authInfo.add(new Id(\"ip\", addr.getHostAddress()));\n        sk.interestOps(SelectionKey.OP_READ);\n    }\n\n    /* Send close connection packet to the client, doIO will eventually\n     * close the underlying machinery (like socket, selectorkey, etc...)\n     */\n    public void sendCloseSession() {\n        sendBuffer(ServerCnxnFactory.closeConn);\n    }\n\n    /**\n     * send buffer without using the asynchronous\n     * calls to selector and then close the socket\n     * @param bb\n     */\n    void sendBufferSync(ByteBuffer bb) {\n       try {\n           /* configure socket to be blocking\n            * so that we dont have to do write in \n            * a tight while loop\n            */\n           sock.configureBlocking(true);\n           if (bb != ServerCnxnFactory.closeConn) {\n               if (sock.isOpen()) {\n                   sock.write(bb);\n               }\n               packetSent();\n           } \n       } catch (IOException ie) {\n           LOG.error(\"Error sending data synchronously \", ie);\n       }\n    }\n    \n    public void sendBuffer(ByteBuffer bb) {\n        try {\n            internalSendBuffer(bb);\n        } catch(Exception e) {\n            LOG.error(\"Unexpected Exception: \", e);\n        }\n    }\n\n    /**\n     * This method implements the internals of sendBuffer. We\n     * have separated it from send buffer to be able to catch\n     * exceptions when testing.\n     *\n     * @param bb Buffer to send.\n     */\n    protected void internalSendBuffer(ByteBuffer bb) {\n        if (bb != ServerCnxnFactory.closeConn) {\n            // We check if write interest here because if it is NOT set,\n            // nothing is queued, so we can try to send the buffer right\n            // away without waking up the selector\n            if(sk.isValid() &&\n                    ((sk.interestOps() & SelectionKey.OP_WRITE) == 0)) {\n                try {\n                    sock.write(bb);\n                } catch (IOException e) {\n                    // we are just doing best effort right now\n                }\n            }\n            // if there is nothing left to send, we are done\n            if (bb.remaining() == 0) {\n                packetSent();\n                return;\n            }\n        }\n\n        synchronized(this.factory){\n            sk.selector().wakeup();\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Add a buffer to outgoingBuffers, sk \" + sk\n                        + \" is valid: \" + sk.isValid());\n            }\n            outgoingBuffers.add(bb);\n            if (sk.isValid()) {\n                sk.interestOps(sk.interestOps() | SelectionKey.OP_WRITE);\n            }\n        }\n    }\n\n    /** Read the request payload (everything following the length prefix) */\n    private void readPayload() throws IOException, InterruptedException {\n        if (incomingBuffer.remaining() != 0) { // have we read length bytes?\n            int rc = sock.read(incomingBuffer); // sock is non-blocking, so ok\n            if (rc < 0) {\n                throw new EndOfStreamException(\n                        \"Unable to read additional data from client sessionid 0x\"\n                        + Long.toHexString(sessionId)\n                        + \", likely client has closed socket\");\n            }\n        }\n\n        if (incomingBuffer.remaining() == 0) { // have we read length bytes?\n            packetReceived();\n            incomingBuffer.flip();\n            if (!initialized) {\n                readConnectRequest();\n            } else {\n                readRequest();\n            }\n            lenBuffer.clear();\n            incomingBuffer = lenBuffer;\n        }\n    }\n\n    /**\n     * Only used in order to allow testing\n     */\n    protected boolean isSocketOpen() {\n        return sock.isOpen();\n    }\n\n    @Override\n    public InetAddress getSocketAddress() {\n        if (sock == null) {\n            return null;\n        }\n\n        return sock.socket().getInetAddress();\n    }\n\n    /**\n     * Handles read/write IO on connection.\n     */\n    void doIO(SelectionKey k) throws InterruptedException {\n        try {\n            if (isSocketOpen() == false) {\n                LOG.warn(\"trying to do i/o on a null socket for session:0x\"\n                         + Long.toHexString(sessionId));\n\n                return;\n            }\n            if (k.isReadable()) {\n                int rc = sock.read(incomingBuffer);\n                if (rc < 0) {\n                    throw new EndOfStreamException(\n                            \"Unable to read additional data from client sessionid 0x\"\n                            + Long.toHexString(sessionId)\n                            + \", likely client has closed socket\");\n                }\n                if (incomingBuffer.remaining() == 0) {\n                    boolean isPayload;\n                    if (incomingBuffer == lenBuffer) { // start of next request\n                        incomingBuffer.flip();\n                        isPayload = readLength(k);\n                        incomingBuffer.clear();\n                    } else {\n                        // continuation\n                        isPayload = true;\n                    }\n                    if (isPayload) { // not the case for 4letterword\n                        readPayload();\n                    }\n                    else {\n                        // four letter words take care\n                        // need not do anything else\n                        return;\n                    }\n                }\n            }\n            if (k.isWritable()) {\n                // ZooLog.logTraceMessage(LOG,\n                // ZooLog.CLIENT_DATA_PACKET_TRACE_MASK\n                // \"outgoingBuffers.size() = \" +\n                // outgoingBuffers.size());\n                if (outgoingBuffers.size() > 0) {\n                    // ZooLog.logTraceMessage(LOG,\n                    // ZooLog.CLIENT_DATA_PACKET_TRACE_MASK,\n                    // \"sk \" + k + \" is valid: \" +\n                    // k.isValid());\n\n                    /*\n                     * This is going to reset the buffer position to 0 and the\n                     * limit to the size of the buffer, so that we can fill it\n                     * with data from the non-direct buffers that we need to\n                     * send.\n                     */\n                    ByteBuffer directBuffer = factory.directBuffer;\n                    directBuffer.clear();\n\n                    for (ByteBuffer b : outgoingBuffers) {\n                        if (directBuffer.remaining() < b.remaining()) {\n                            /*\n                             * When we call put later, if the directBuffer is to\n                             * small to hold everything, nothing will be copied,\n                             * so we've got to slice the buffer if it's too big.\n                             */\n                            b = (ByteBuffer) b.slice().limit(\n                                    directBuffer.remaining());\n                        }\n                        /*\n                         * put() is going to modify the positions of both\n                         * buffers, put we don't want to change the position of\n                         * the source buffers (we'll do that after the send, if\n                         * needed), so we save and reset the position after the\n                         * copy\n                         */\n                        int p = b.position();\n                        directBuffer.put(b);\n                        b.position(p);\n                        if (directBuffer.remaining() == 0) {\n                            break;\n                        }\n                    }\n                    /*\n                     * Do the flip: limit becomes position, position gets set to\n                     * 0. This sets us up for the write.\n                     */\n                    directBuffer.flip();\n\n                    int sent = sock.write(directBuffer);\n                    ByteBuffer bb;\n\n                    // Remove the buffers that we have sent\n                    while (outgoingBuffers.size() > 0) {\n                        bb = outgoingBuffers.peek();\n                        if (bb == ServerCnxnFactory.closeConn) {\n                            throw new CloseRequestException(\"close requested\");\n                        }\n                        int left = bb.remaining() - sent;\n                        if (left > 0) {\n                            /*\n                             * We only partially sent this buffer, so we update\n                             * the position and exit the loop.\n                             */\n                            bb.position(bb.position() + sent);\n                            break;\n                        }\n                        packetSent();\n                        /* We've sent the whole buffer, so drop the buffer */\n                        sent -= bb.remaining();\n                        outgoingBuffers.remove();\n                    }\n                    // ZooLog.logTraceMessage(LOG,\n                    // ZooLog.CLIENT_DATA_PACKET_TRACE_MASK, \"after send,\n                    // outgoingBuffers.size() = \" + outgoingBuffers.size());\n                }\n\n                synchronized(this.factory){\n                    if (outgoingBuffers.size() == 0) {\n                        if (!initialized\n                                && (sk.interestOps() & SelectionKey.OP_READ) == 0) {\n                            throw new CloseRequestException(\"responded to info probe\");\n                        }\n                        sk.interestOps(sk.interestOps()\n                                & (~SelectionKey.OP_WRITE));\n                    } else {\n                        sk.interestOps(sk.interestOps()\n                                | SelectionKey.OP_WRITE);\n                    }\n                }\n            }\n        } catch (CancelledKeyException e) {\n            LOG.warn(\"CancelledKeyException causing close of session 0x\"\n                     + Long.toHexString(sessionId));\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"CancelledKeyException stack trace\", e);\n            }\n            close();\n        } catch (CloseRequestException e) {\n            // expecting close to log session closure\n            close();\n        } catch (EndOfStreamException e) {\n            LOG.warn(e.getMessage());\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"EndOfStreamException stack trace\", e);\n            }\n            // expecting close to log session closure\n            close();\n        } catch (IOException e) {\n            LOG.warn(\"Exception causing close of session 0x\"\n                     + Long.toHexString(sessionId) + \": \" + e.getMessage());\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"IOException stack trace\", e);\n            }\n            close();\n        }\n    }\n\n    private void readRequest() throws IOException {\n        zkServer.processPacket(this, incomingBuffer);\n    }\n    \n    protected void incrOutstandingRequests(RequestHeader h) {\n        if (h.getXid() >= 0) {\n            synchronized (this) {\n                outstandingRequests++;\n            }\n            synchronized (this.factory) {        \n                // check throttling\n                if (zkServer.getInProcess() > outstandingLimit) {\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Throttling recv \" + zkServer.getInProcess());\n                    }\n                    disableRecv();\n                    // following lines should not be needed since we are\n                    // already reading\n                    // } else {\n                    // enableRecv();\n                }\n            }\n        }\n\n    }\n\n    public void disableRecv() {\n        sk.interestOps(sk.interestOps() & (~SelectionKey.OP_READ));\n    }\n\n    public void enableRecv() {\n        synchronized (this.factory) {\n            sk.selector().wakeup();\n            if (sk.isValid()) {\n                int interest = sk.interestOps();\n                if ((interest & SelectionKey.OP_READ) == 0) {\n                    sk.interestOps(interest | SelectionKey.OP_READ);\n                }\n            }\n        }\n    }\n\n    private void readConnectRequest() throws IOException, InterruptedException {\n        if (!isZKServerRunning()) {\n            throw new IOException(\"ZooKeeperServer not running\");\n        }\n        zkServer.processConnectRequest(this, incomingBuffer);\n        initialized = true;\n    }\n\n    /**\n     * clean up the socket related to a command and also make sure we flush the\n     * data before we do that\n     * \n     * @param pwriter\n     *            the pwriter for a command socket\n     */\n    private void cleanupWriterSocket(PrintWriter pwriter) {\n        try {\n            if (pwriter != null) {\n                pwriter.flush();\n                pwriter.close();\n            }\n        } catch (Exception e) {\n            LOG.info(\"Error closing PrintWriter \", e);\n        } finally {\n            try {\n                close();\n            } catch (Exception e) {\n                LOG.error(\"Error closing a command socket \", e);\n            }\n        }\n    }\n\n    /**\n     * This class wraps the sendBuffer method of NIOServerCnxn. It is\n     * responsible for chunking up the response to a client. Rather\n     * than cons'ing up a response fully in memory, which may be large\n     * for some commands, this class chunks up the result.\n     */\n    private class SendBufferWriter extends Writer {\n        private StringBuffer sb = new StringBuffer();\n        \n        /**\n         * Check if we are ready to send another chunk.\n         * @param force force sending, even if not a full chunk\n         */\n        private void checkFlush(boolean force) {\n            if ((force && sb.length() > 0) || sb.length() > 2048) {\n                sendBufferSync(ByteBuffer.wrap(sb.toString().getBytes()));\n                // clear our internal buffer\n                sb.setLength(0);\n            }\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (sb == null) return;\n            checkFlush(true);\n            sb = null; // clear out the ref to ensure no reuse\n        }\n\n        @Override\n        public void flush() throws IOException {\n            checkFlush(true);\n        }\n\n        @Override\n        public void write(char[] cbuf, int off, int len) throws IOException {\n            sb.append(cbuf, off, len);\n            checkFlush(false);\n        }\n    }\n\n    private static final String ZK_NOT_SERVING =\n        \"This ZooKeeper instance is not currently serving requests\";\n    \n    /**\n     * Set of threads for commmand ports. All the 4\n     * letter commands are run via a thread. Each class\n     * maps to a corresponding 4 letter command. CommandThread\n     * is the abstract class from which all the others inherit.\n     */\n    private abstract class CommandThread extends Thread {\n        PrintWriter pw;\n        \n        CommandThread(PrintWriter pw) {\n            this.pw = pw;\n        }\n        \n        public void run() {\n            try {\n                commandRun();\n            } catch (IOException ie) {\n                LOG.error(\"Error in running command \", ie);\n            } finally {\n                cleanupWriterSocket(pw);\n            }\n        }\n        \n        public abstract void commandRun() throws IOException;\n    }\n    \n    private class RuokCommand extends CommandThread {\n        public RuokCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            pw.print(\"imok\");\n            \n        }\n    }\n    \n    private class TraceMaskCommand extends CommandThread {\n        TraceMaskCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            long traceMask = ZooTrace.getTextTraceLevel();\n            pw.print(traceMask);\n        }\n    }\n    \n    private class SetTraceMaskCommand extends CommandThread {\n        long trace = 0;\n        SetTraceMaskCommand(PrintWriter pw, long trace) {\n            super(pw);\n            this.trace = trace;\n        }\n        \n        @Override\n        public void commandRun() {\n            pw.print(trace);\n        }\n    }\n    \n    private class EnvCommand extends CommandThread {\n        EnvCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            List<Environment.Entry> env = Environment.list();\n\n            pw.println(\"Environment:\");\n            for(Environment.Entry e : env) {\n                pw.print(e.getKey());\n                pw.print(\"=\");\n                pw.println(e.getValue());\n            }\n            \n        } \n    }\n    \n    private class ConfCommand extends CommandThread {\n        ConfCommand(PrintWriter pw) {\n            super(pw);\n        }\n            \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                zkServer.dumpConf(pw);\n            }\n        }\n    }\n    \n    private class StatResetCommand extends CommandThread {\n        public StatResetCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else { \n                zkServer.serverStats().reset();\n                pw.println(\"Server stats reset.\");\n            }\n        }\n    }\n    \n    private class CnxnStatResetCommand extends CommandThread {\n        public CnxnStatResetCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                synchronized(factory.cnxns){\n                    for(ServerCnxn c : factory.cnxns){\n                        c.resetStats();\n                    }\n                }\n                pw.println(\"Connection stats reset.\");\n            }\n        }\n    }\n\n    private class DumpCommand extends CommandThread {\n        public DumpCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else {\n                pw.println(\"SessionTracker dump:\");\n                zkServer.sessionTracker.dumpSessions(pw);\n                pw.println(\"ephemeral nodes dump:\");\n                zkServer.dumpEphemerals(pw);\n            }\n        }\n    }\n    \n    private class StatCommand extends CommandThread {\n        int len;\n        public StatCommand(PrintWriter pw, int len) {\n            super(pw);\n            this.len = len;\n        }\n        \n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else {   \n                pw.print(\"Zookeeper version: \");\n                pw.println(Version.getFullVersion());\n                if (zkServer instanceof ReadOnlyZooKeeperServer) {\n                    pw.println(\"READ-ONLY mode; serving only \" +\n                               \"read-only clients\");\n                }\n                if (len == statCmd) {\n                    LOG.info(\"Stat command output\");\n                    pw.println(\"Clients:\");\n                    // clone should be faster than iteration\n                    // ie give up the cnxns lock faster\n                    HashSet<NIOServerCnxn> cnxnset;\n                    synchronized(factory.cnxns){\n                        cnxnset = (HashSet<NIOServerCnxn>)factory\n                        .cnxns.clone();\n                    }\n                    for(NIOServerCnxn c : cnxnset){\n                        c.dumpConnectionInfo(pw, true);\n                        pw.println();\n                    }\n                    pw.println();\n                }\n                pw.print(zkServer.serverStats().toString());\n                pw.print(\"Node count: \");\n                pw.println(zkServer.getZKDatabase().getNodeCount());\n            }\n            \n        }\n    }\n    \n    private class ConsCommand extends CommandThread {\n        public ConsCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                // clone should be faster than iteration\n                // ie give up the cnxns lock faster\n                HashSet<NIOServerCnxn> cnxns;\n                synchronized (factory.cnxns) {\n                    cnxns = (HashSet<NIOServerCnxn>) factory.cnxns.clone();\n                }\n                for (NIOServerCnxn c : cnxns) {\n                    c.dumpConnectionInfo(pw, false);\n                    pw.println();\n                }\n                pw.println();\n            }\n        }\n    }\n    \n    private class WatchCommand extends CommandThread {\n        int len = 0;\n        public WatchCommand(PrintWriter pw, int len) {\n            super(pw);\n            this.len = len;\n        }\n\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                DataTree dt = zkServer.getZKDatabase().getDataTree();\n                if (len == wchsCmd) {\n                    dt.dumpWatchesSummary(pw);\n                } else if (len == wchpCmd) {\n                    dt.dumpWatches(pw, true);\n                } else {\n                    dt.dumpWatches(pw, false);\n                }\n                pw.println();\n            }\n        }\n    }\n\n    private class MonitorCommand extends CommandThread {\n\n        MonitorCommand(PrintWriter pw) {\n            super(pw);\n        }\n\n        @Override\n        public void commandRun() {\n            if(!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n                return;\n            }\n            ZKDatabase zkdb = zkServer.getZKDatabase();\n            ServerStats stats = zkServer.serverStats();\n\n            print(\"version\", Version.getFullVersion());\n\n            print(\"avg_latency\", stats.getAvgLatency());\n            print(\"max_latency\", stats.getMaxLatency());\n            print(\"min_latency\", stats.getMinLatency());\n\n            print(\"packets_received\", stats.getPacketsReceived());\n            print(\"packets_sent\", stats.getPacketsSent());\n            print(\"num_alive_connections\", stats.getNumAliveClientConnections());\n\n            print(\"outstanding_requests\", stats.getOutstandingRequests());\n\n            print(\"server_state\", stats.getServerState());\n            print(\"znode_count\", zkdb.getNodeCount());\n\n            print(\"watch_count\", zkdb.getDataTree().getWatchCount());\n            print(\"ephemerals_count\", zkdb.getDataTree().getEphemeralsCount());\n            print(\"approximate_data_size\", zkdb.getDataTree().approximateDataSize());\n\n            OSMXBean osMbean = new OSMXBean();\n            if (osMbean != null && osMbean.getUnix() == true) {\n                print(\"open_file_descriptor_count\", osMbean.getOpenFileDescriptorCount());\n                print(\"max_file_descriptor_count\", osMbean.getMaxFileDescriptorCount());\n            }\n\n            if(stats.getServerState().equals(\"leader\")) {\n                Leader leader = ((LeaderZooKeeperServer)zkServer).getLeader();\n\n                print(\"followers\", leader.getLearners().size());\n                print(\"synced_followers\", leader.getForwardingFollowers().size());\n                print(\"pending_syncs\", leader.getNumPendingSyncs());\n            }\n        }\n\n        private void print(String key, long number) {\n            print(key, \"\" + number);\n        }\n\n        private void print(String key, String value) {\n            pw.print(\"zk_\");\n            pw.print(key);\n            pw.print(\"\\t\");\n            pw.println(value);\n        }\n\n    }\n\n    private class IsroCommand extends CommandThread {\n\n        public IsroCommand(PrintWriter pw) {\n            super(pw);\n        }\n\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.print(\"null\");\n            } else if (zkServer instanceof ReadOnlyZooKeeperServer) {\n                pw.print(\"ro\");\n            } else {\n                pw.print(\"rw\");\n            }\n        }\n    }\n\n    private class NopCommand extends CommandThread {\n        private String msg;\n\n        public NopCommand(PrintWriter pw, String msg) {\n            super(pw);\n            this.msg = msg;\n        }\n\n        @Override\n        public void commandRun() {\n            pw.println(msg);\n        }\n    }\n\n    /** Return if four letter word found and responded to, otw false **/\n    private boolean checkFourLetterWord(final SelectionKey k, final int len)\n    throws IOException\n    {\n        // We take advantage of the limited size of the length to look\n        // for cmds. They are all 4-bytes which fits inside of an int\n        if (!ServerCnxn.isKnown(len)) {\n            return false;\n        }\n\n        packetReceived();\n\n        /** cancel the selection key to remove the socket handling\n         * from selector. This is to prevent netcat problem wherein\n         * netcat immediately closes the sending side after sending the\n         * commands and still keeps the receiving channel open. \n         * The idea is to remove the selectionkey from the selector\n         * so that the selector does not notice the closed read on the\n         * socket channel and keep the socket alive to write the data to\n         * and makes sure to close the socket after its done writing the data\n         */\n        if (k != null) {\n            try {\n                k.cancel();\n            } catch(Exception e) {\n                LOG.error(\"Error cancelling command selection key \", e);\n            }\n        }\n\n        final PrintWriter pwriter = new PrintWriter(\n                new BufferedWriter(new SendBufferWriter()));\n\n        String cmd = ServerCnxn.getCommandString(len);\n        // ZOOKEEPER-2693: don't execute 4lw if it's not enabled.\n        if (!ServerCnxn.isEnabled(cmd)) {\n            LOG.debug(\"Command {} is not executed because it is not in the whitelist.\", cmd);\n            NopCommand nopCmd = new NopCommand(pwriter, cmd + \" is not executed because it is not in the whitelist.\");\n            nopCmd.start();\n            return true;\n        }\n\n        LOG.info(\"Processing \" + cmd + \" command from \"\n                + sock.socket().getRemoteSocketAddress());\n\n        if (len == ruokCmd) {\n            RuokCommand ruok = new RuokCommand(pwriter);\n            ruok.start();\n            return true;\n        } else if (len == getTraceMaskCmd) {\n            TraceMaskCommand tmask = new TraceMaskCommand(pwriter);\n            tmask.start();\n            return true;\n        } else if (len == setTraceMaskCmd) {\n            incomingBuffer = ByteBuffer.allocate(8);\n            int rc = sock.read(incomingBuffer);\n            if (rc < 0) {\n                throw new IOException(\"Read error\");\n            }\n\n            incomingBuffer.flip();\n            long traceMask = incomingBuffer.getLong();\n            ZooTrace.setTextTraceLevel(traceMask);\n            SetTraceMaskCommand setMask = new SetTraceMaskCommand(pwriter, traceMask);\n            setMask.start();\n            return true;\n        } else if (len == enviCmd) {\n            EnvCommand env = new EnvCommand(pwriter);\n            env.start();\n            return true;\n        } else if (len == confCmd) {\n            ConfCommand ccmd = new ConfCommand(pwriter);\n            ccmd.start();\n            return true;\n        } else if (len == srstCmd) {\n            StatResetCommand strst = new StatResetCommand(pwriter);\n            strst.start();\n            return true;\n        } else if (len == crstCmd) {\n            CnxnStatResetCommand crst = new CnxnStatResetCommand(pwriter);\n            crst.start();\n            return true;\n        } else if (len == dumpCmd) {\n            DumpCommand dump = new DumpCommand(pwriter);\n            dump.start();\n            return true;\n        } else if (len == statCmd || len == srvrCmd) {\n            StatCommand stat = new StatCommand(pwriter, len);\n            stat.start();\n            return true;\n        } else if (len == consCmd) {\n            ConsCommand cons = new ConsCommand(pwriter);\n            cons.start();\n            return true;\n        } else if (len == wchpCmd || len == wchcCmd || len == wchsCmd) {\n            WatchCommand wcmd = new WatchCommand(pwriter, len);\n            wcmd.start();\n            return true;\n        } else if (len == mntrCmd) {\n            MonitorCommand mntr = new MonitorCommand(pwriter);\n            mntr.start();\n            return true;\n        } else if (len == isroCmd) {\n            IsroCommand isro = new IsroCommand(pwriter);\n            isro.start();\n            return true;\n        }\n        return false;\n    }\n\n    /** Reads the first 4 bytes of lenBuffer, which could be true length or\n     *  four letter word.\n     *\n     * @param k selection key\n     * @return true if length read, otw false (wasn't really the length)\n     * @throws IOException if buffer size exceeds maxBuffer size\n     */\n    private boolean readLength(SelectionKey k) throws IOException {\n        // Read the length, now get the buffer\n        int len = lenBuffer.getInt();\n        if (!initialized && checkFourLetterWord(sk, len)) {\n            return false;\n        }\n        if (len < 0 || len > BinaryInputArchive.maxBuffer) {\n            throw new IOException(\"Len error \" + len);\n        }\n        if (!isZKServerRunning()) {\n            throw new IOException(\"ZooKeeperServer not running\");\n        }\n        incomingBuffer = ByteBuffer.allocate(len);\n        return true;\n    }\n\n    public long getOutstandingRequests() {\n        synchronized (this) {\n            synchronized (this.factory) {\n                return outstandingRequests;\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.server.ServerCnxnIface#getSessionTimeout()\n     */\n    public int getSessionTimeout() {\n        return sessionTimeout;\n    }\n\n    @Override\n    public String toString() {\n        return \"NIOServerCnxn object with sock = \" + sock + \" and sk = \" + sk;\n    }\n\n    /*\n     * Close the cnxn and remove it from the factory cnxns list.\n     * \n     * This function returns immediately if the cnxn is not on the cnxns list.\n     */\n    @Override\n    public void close() {\n        factory.removeCnxn(this);\n\n        if (zkServer != null) {\n            zkServer.removeCnxn(this);\n        }\n\n        closeSock();\n\n        if (sk != null) {\n            try {\n                // need to cancel this selection key from the selector\n                sk.cancel();\n            } catch (Exception e) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"ignoring exception during selectionkey cancel\", e);\n                }\n            }\n        }\n    }\n\n    /**\n     * Close resources associated with the sock of this cnxn. \n     */\n    private void closeSock() {\n        if (sock.isOpen() == false) {\n            return;\n        }\n\n        LOG.info(\"Closed socket connection for client \"\n                + sock.socket().getRemoteSocketAddress()\n                + (sessionId != 0 ?\n                        \" which had sessionid 0x\" + Long.toHexString(sessionId) :\n                        \" (no session established for client)\"));\n        try {\n            /*\n             * The following sequence of code is stupid! You would think that\n             * only sock.close() is needed, but alas, it doesn't work that way.\n             * If you just do sock.close() there are cases where the socket\n             * doesn't actually close...\n             */\n            sock.socket().shutdownOutput();\n        } catch (IOException e) {\n            // This is a relatively common exception that we can't avoid\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"ignoring exception during output shutdown\", e);\n            }\n        }\n        try {\n            sock.socket().shutdownInput();\n        } catch (IOException e) {\n            // This is a relatively common exception that we can't avoid\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"ignoring exception during input shutdown\", e);\n            }\n        }\n        try {\n            sock.socket().close();\n        } catch (IOException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"ignoring exception during socket close\", e);\n            }\n        }\n        try {\n            sock.close();\n            // XXX The next line doesn't seem to be needed, but some posts\n            // to forums suggest that it is needed. Keep in mind if errors in\n            // this section arise.\n            // factory.selector.wakeup();\n        } catch (IOException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"ignoring exception during socketchannel close\", e);\n            }\n        }\n    }\n    \n    private final static byte fourBytes[] = new byte[4];\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.server.ServerCnxnIface#sendResponse(org.apache.zookeeper.proto.ReplyHeader,\n     *      org.apache.jute.Record, java.lang.String)\n     */\n    @Override\n    synchronized public void sendResponse(ReplyHeader h, Record r, String tag) {\n        try {\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            // Make space for length\n            BinaryOutputArchive bos = BinaryOutputArchive.getArchive(baos);\n            try {\n                baos.write(fourBytes);\n                bos.writeRecord(h, \"header\");\n                if (r != null) {\n                    bos.writeRecord(r, tag);\n                }\n                baos.close();\n            } catch (IOException e) {\n                LOG.error(\"Error serializing response\");\n            }\n            byte b[] = baos.toByteArray();\n            ByteBuffer bb = ByteBuffer.wrap(b);\n            bb.putInt(b.length - 4).rewind();\n            sendBuffer(bb);\n            if (h.getXid() > 0) {\n                synchronized(this){\n                    outstandingRequests--;\n                }\n                // check throttling\n                synchronized (this.factory) {        \n                    if (zkServer.getInProcess() < outstandingLimit\n                            || outstandingRequests < 1) {\n                        sk.selector().wakeup();\n                        enableRecv();\n                    }\n                }\n            }\n         } catch(Exception e) {\n            LOG.warn(\"Unexpected exception. Destruction averted.\", e);\n         }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.server.ServerCnxnIface#process(org.apache.zookeeper.proto.WatcherEvent)\n     */\n    @Override\n    synchronized public void process(WatchedEvent event) {\n        ReplyHeader h = new ReplyHeader(-1, -1L, 0);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,\n                                     \"Deliver event \" + event + \" to 0x\"\n                                     + Long.toHexString(this.sessionId)\n                                     + \" through \" + this);\n        }\n\n        // Convert WatchedEvent to a type that can be sent over the wire\n        WatcherEvent e = event.getWrapper();\n\n        sendResponse(h, e, \"notification\");\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.server.ServerCnxnIface#getSessionId()\n     */\n    @Override\n    public long getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public void setSessionId(long sessionId) {\n        this.sessionId = sessionId;\n        this.factory.addSession(sessionId, this);\n    }\n\n    @Override\n    public void setSessionTimeout(int sessionTimeout) {\n        this.sessionTimeout = sessionTimeout;\n    }\n\n    @Override\n    public int getInterestOps() {\n        return sk.isValid() ? sk.interestOps() : 0;\n    }\n\n    @Override\n    public InetSocketAddress getRemoteSocketAddress() {\n        if (sock.isOpen() == false) {\n            return null;\n        }\n        return (InetSocketAddress) sock.socket().getRemoteSocketAddress();\n    }\n\n    @Override\n    protected ServerStats serverStats() {\n        if (!isZKServerRunning()) {\n            return null;\n        }\n        return zkServer.serverStats();\n    }\n\n    /**\n     * @return true if the server is running, false otherwise.\n     */\n    boolean isZKServerRunning() {\n        return zkServer != null && zkServer.isRunning();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/NIOServerCnxnFactory.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class NIOServerCnxnFactory extends ServerCnxnFactory implements Runnable {\n    private static final Logger LOG = LoggerFactory.getLogger(NIOServerCnxnFactory.class);\n\n    static {\n        /**\n         * this is to avoid the jvm bug:\n         * NullPointerException in Selector.open()\n         * http://bugs.sun.com/view_bug.do?bug_id=6427854\n         */\n        try {\n            Selector.open().close();\n        } catch(IOException ie) {\n            LOG.error(\"Selector failed to open\", ie);\n        }\n    }\n\n    ServerSocketChannel ss;\n\n    final Selector selector = Selector.open();\n\n    /**\n     * We use this buffer to do efficient socket I/O. Since there is a single\n     * sender thread per NIOServerCnxn instance, we can use a member variable to\n     * only allocate it once.\n    */\n    final ByteBuffer directBuffer = ByteBuffer.allocateDirect(64 * 1024);\n\n    final HashMap<InetAddress, Set<NIOServerCnxn>> ipMap =\n        new HashMap<InetAddress, Set<NIOServerCnxn>>( );\n\n    int maxClientCnxns = 60;\n\n    /**\n     * Construct a new server connection factory which will accept an unlimited number\n     * of concurrent connections from each client (up to the file descriptor\n     * limits of the operating system). startup(zks) must be called subsequently.\n     * @throws IOException\n     */\n    public NIOServerCnxnFactory() throws IOException {\n    }\n\n    Thread thread;\n    @Override\n    public void configure(InetSocketAddress addr, int maxcc) throws IOException {\n        configureSaslLogin();\n\n        thread = new ZooKeeperThread(this, \"NIOServerCxn.Factory:\" + addr);\n        thread.setDaemon(true);\n        maxClientCnxns = maxcc;\n        this.ss = ServerSocketChannel.open();\n        ss.socket().setReuseAddress(true);\n        LOG.info(\"binding to port \" + addr);\n        ss.socket().bind(addr);\n        ss.configureBlocking(false);\n        ss.register(selector, SelectionKey.OP_ACCEPT);\n    }\n\n    /** {@inheritDoc} */\n    public int getMaxClientCnxnsPerHost() {\n        return maxClientCnxns;\n    }\n\n    /** {@inheritDoc} */\n    public void setMaxClientCnxnsPerHost(int max) {\n        maxClientCnxns = max;\n    }\n\n    @Override\n    public void start() {\n        // ensure thread is started once and only once\n        if (thread.getState() == Thread.State.NEW) {\n            thread.start();\n        }\n    }\n\n    @Override\n    public void startup(ZooKeeperServer zks) throws IOException,\n            InterruptedException {\n        start();\n        setZooKeeperServer(zks);\n        zks.startdata();\n        zks.startup();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress(){\n        return (InetSocketAddress)ss.socket().getLocalSocketAddress();\n    }\n\n    @Override\n    public int getLocalPort(){\n        return ss.socket().getLocalPort();\n    }\n\n    private void addCnxn(NIOServerCnxn cnxn) {\n        synchronized (cnxns) {\n            cnxns.add(cnxn);\n            synchronized (ipMap){\n                InetAddress addr = cnxn.sock.socket().getInetAddress();\n                Set<NIOServerCnxn> s = ipMap.get(addr);\n                if (s == null) {\n                    // in general we will see 1 connection from each\n                    // host, setting the initial cap to 2 allows us\n                    // to minimize mem usage in the common case\n                    // of 1 entry --  we need to set the initial cap\n                    // to 2 to avoid rehash when the first entry is added\n                    s = new HashSet<NIOServerCnxn>(2);\n                    s.add(cnxn);\n                    ipMap.put(addr,s);\n                } else {\n                    s.add(cnxn);\n                }\n            }\n        }\n    }\n\n    public void removeCnxn(NIOServerCnxn cnxn) {\n        synchronized(cnxns) {\n            // Remove the related session from the sessionMap.\n            long sessionId = cnxn.getSessionId();\n            if (sessionId != 0) {\n                sessionMap.remove(sessionId);\n            }\n\n            // if this is not in cnxns then it's already closed\n            if (!cnxns.remove(cnxn)) {\n                return;\n            }\n\n            synchronized (ipMap) {\n                Set<NIOServerCnxn> s =\n                        ipMap.get(cnxn.getSocketAddress());\n                s.remove(cnxn);\n            }\n\n            unregisterConnection(cnxn);\n        }\n    }\n\n    protected NIOServerCnxn createConnection(SocketChannel sock,\n            SelectionKey sk) throws IOException {\n        return new NIOServerCnxn(zkServer, sock, sk, this);\n    }\n\n    private int getClientCnxnCount(InetAddress cl) {\n        // The ipMap lock covers both the map, and its contents\n        // (that is, the cnxn sets shouldn't be modified outside of\n        // this lock)\n        synchronized (ipMap) {\n            Set<NIOServerCnxn> s = ipMap.get(cl);\n            if (s == null) return 0;\n            return s.size();\n        }\n    }\n\n    public void run() {\n        while (!ss.socket().isClosed()) {\n            try {\n                selector.select(1000);\n                Set<SelectionKey> selected;\n                synchronized (this) {\n                    selected = selector.selectedKeys();\n                }\n                ArrayList<SelectionKey> selectedList = new ArrayList<SelectionKey>(\n                        selected);\n                Collections.shuffle(selectedList);\n                for (SelectionKey k : selectedList) {\n                    if ((k.readyOps() & SelectionKey.OP_ACCEPT) != 0) {\n                        SocketChannel sc = ((ServerSocketChannel) k\n                                .channel()).accept();\n                        InetAddress ia = sc.socket().getInetAddress();\n                        int cnxncount = getClientCnxnCount(ia);\n                        if (maxClientCnxns > 0 && cnxncount >= maxClientCnxns){\n                            LOG.warn(\"Too many connections from \" + ia\n                                     + \" - max is \" + maxClientCnxns );\n                            sc.close();\n                        } else {\n                            LOG.info(\"Accepted socket connection from \"\n                                     + sc.socket().getRemoteSocketAddress());\n                            sc.configureBlocking(false);\n                            SelectionKey sk = sc.register(selector,\n                                    SelectionKey.OP_READ);\n                            NIOServerCnxn cnxn = createConnection(sc, sk);\n                            sk.attach(cnxn);\n                            addCnxn(cnxn);\n                        }\n                    } else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {\n                        NIOServerCnxn c = (NIOServerCnxn) k.attachment();\n                        c.doIO(k);\n                    } else {\n                        if (LOG.isDebugEnabled()) {\n                            LOG.debug(\"Unexpected ops in select \"\n                                      + k.readyOps());\n                        }\n                    }\n                }\n                selected.clear();\n            } catch (RuntimeException e) {\n                LOG.warn(\"Ignoring unexpected runtime exception\", e);\n            } catch (Exception e) {\n                LOG.warn(\"Ignoring exception\", e);\n            }\n        }\n        closeAll();\n        LOG.info(\"NIOServerCnxn factory exited run method\");\n    }\n\n    /**\n     * clear all the connections in the selector\n     *\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    synchronized public void closeAll() {\n        selector.wakeup();\n        HashSet<NIOServerCnxn> cnxns;\n        synchronized (this.cnxns) {\n            cnxns = (HashSet<NIOServerCnxn>)this.cnxns.clone();\n        }\n        // got to clear all the connections that we have in the selector\n        for (NIOServerCnxn cnxn: cnxns) {\n            try {\n                // don't hold this.cnxns lock as deadlock may occur\n                cnxn.close();\n            } catch (Exception e) {\n                LOG.warn(\"Ignoring exception closing cnxn sessionid 0x\"\n                         + Long.toHexString(cnxn.sessionId), e);\n            }\n        }\n    }\n\n    public void shutdown() {\n        try {\n            ss.close();\n            closeAll();\n            thread.interrupt();\n            thread.join();\n            if (login != null) {\n                login.shutdown();\n            }\n        } catch (InterruptedException e) {\n            LOG.warn(\"Ignoring interrupted exception during shutdown\", e);\n        } catch (Exception e) {\n            LOG.warn(\"Ignoring unexpected exception during shutdown\", e);\n        }\n        try {\n            selector.close();\n        } catch (IOException e) {\n            LOG.warn(\"Selector closing\", e);\n        }\n        if (zkServer != null) {\n            zkServer.shutdown();\n        }\n    }\n\n    @Override\n    public synchronized void closeSession(long sessionId) {\n        selector.wakeup();\n        closeSessionWithoutWakeup(sessionId);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void closeSessionWithoutWakeup(long sessionId) {\n        NIOServerCnxn cnxn = (NIOServerCnxn) sessionMap.remove(sessionId);\n        if (cnxn != null) {\n            try {\n                cnxn.close();\n            } catch (Exception e) {\n                LOG.warn(\"exception during session close\", e);\n            }\n        }\n    }\n\n    @Override\n    public void join() throws InterruptedException {\n        thread.join();\n    }\n\n    @Override\n    public Iterable<ServerCnxn> getConnections() {\n        return cnxns;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer;\n\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.AbstractSet;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.Environment;\nimport org.apache.zookeeper.Version;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.WatcherEvent;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.server.quorum.LeaderZooKeeperServer;\nimport org.apache.zookeeper.server.quorum.ReadOnlyZooKeeperServer;\nimport org.apache.zookeeper.server.util.OSMXBean;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelFuture;\nimport org.jboss.netty.channel.MessageEvent;\n\npublic class NettyServerCnxn extends ServerCnxn {\n    Logger LOG = LoggerFactory.getLogger(NettyServerCnxn.class);\n    Channel channel;\n    ChannelBuffer queuedBuffer;\n    volatile boolean throttled;\n    ByteBuffer bb;\n    ByteBuffer bbLen = ByteBuffer.allocate(4);\n    long sessionId;\n    int sessionTimeout;\n    AtomicLong outstandingCount = new AtomicLong();\n\n    /** The ZooKeeperServer for this connection. May be null if the server\n     * is not currently serving requests (for example if the server is not\n     * an active quorum participant.\n     */\n    private volatile ZooKeeperServer zkServer;\n\n    NettyServerCnxnFactory factory;\n    boolean initialized;\n    \n    NettyServerCnxn(Channel channel, ZooKeeperServer zks, NettyServerCnxnFactory factory) {\n        this.channel = channel;\n        this.zkServer = zks;\n        this.factory = factory;\n        if (this.factory.login != null) {\n            this.zooKeeperSaslServer = new ZooKeeperSaslServer(factory.login);\n        }\n    }\n    \n    @Override\n    public void close() {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"close called for sessionid:0x\"\n                    + Long.toHexString(sessionId));\n        }\n\n        // ZOOKEEPER-2743:\n        // Always unregister connection upon close to prevent\n        // connection bean leak under certain race conditions.\n        factory.unregisterConnection(this);\n\n        factory.removeCnxn(this);\n\n        if (channel.isOpen()) {\n            channel.close();\n        }\n    }\n\n    @Override\n    public long getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public int getSessionTimeout() {\n        return sessionTimeout;\n    }\n\n    @Override\n    public void process(WatchedEvent event) {\n        ReplyHeader h = new ReplyHeader(-1, -1L, 0);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,\n                                     \"Deliver event \" + event + \" to 0x\"\n                                     + Long.toHexString(this.sessionId)\n                                     + \" through \" + this);\n        }\n\n        // Convert WatchedEvent to a type that can be sent over the wire\n        WatcherEvent e = event.getWrapper();\n\n        try {\n            sendResponse(h, e, \"notification\");\n        } catch (IOException e1) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Problem sending to \" + getRemoteSocketAddress(), e1);\n            }\n            close();\n        }\n    }\n\n    private static final byte[] fourBytes = new byte[4];\n    static class ResumeMessageEvent implements MessageEvent {\n        Channel channel;\n        ResumeMessageEvent(Channel channel) {\n            this.channel = channel;\n        }\n        @Override\n        public Object getMessage() {return null;}\n        @Override\n        public SocketAddress getRemoteAddress() {return null;}\n        @Override\n        public Channel getChannel() {return channel;}\n        @Override\n        public ChannelFuture getFuture() {return null;}\n    };\n    \n    @Override\n    public void sendResponse(ReplyHeader h, Record r, String tag)\n            throws IOException {\n        if (!channel.isOpen()) {\n            return;\n        }\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        // Make space for length\n        BinaryOutputArchive bos = BinaryOutputArchive.getArchive(baos);\n        try {\n            baos.write(fourBytes);\n            bos.writeRecord(h, \"header\");\n            if (r != null) {\n                bos.writeRecord(r, tag);\n            }\n            baos.close();\n        } catch (IOException e) {\n            LOG.error(\"Error serializing response\");\n        }\n        byte b[] = baos.toByteArray();\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.putInt(b.length - 4).rewind();\n        sendBuffer(bb);\n        if (h.getXid() > 0) {\n            // zks cannot be null otherwise we would not have gotten here!\n            if (!zkServer.shouldThrottle(outstandingCount.decrementAndGet())) {\n                enableRecv();\n            }\n        }\n    }\n\n    @Override\n    public void setSessionId(long sessionId) {\n        this.sessionId = sessionId;\n        factory.addSession(sessionId, this);\n    }\n\n    @Override\n    public void enableRecv() {\n        if (throttled) {\n            throttled = false;\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Sending unthrottle event \" + this);\n            }\n            channel.getPipeline().sendUpstream(new ResumeMessageEvent(channel));\n        }\n    }\n\n    @Override\n    public void sendBuffer(ByteBuffer sendBuffer) {\n        if (sendBuffer == ServerCnxnFactory.closeConn) {\n            close();\n            return;\n        }\n        channel.write(wrappedBuffer(sendBuffer));\n        packetSent();\n    }\n\n    @Override\n    public InetAddress getSocketAddress() {\n        if (channel == null) {\n            return null;\n        }\n\n        return ((InetSocketAddress)(channel.getRemoteAddress())).getAddress();\n    }\n\n    /**\n     * clean up the socket related to a command and also make sure we flush the\n     * data before we do that\n     * \n     * @param pwriter\n     *            the pwriter for a command socket\n     */\n    private void cleanupWriterSocket(PrintWriter pwriter) {\n        try {\n            if (pwriter != null) {\n                pwriter.flush();\n                pwriter.close();\n            }\n        } catch (Exception e) {\n            LOG.info(\"Error closing PrintWriter \", e);\n        } finally {\n            try {\n                close();\n            } catch (Exception e) {\n                LOG.error(\"Error closing a command socket \", e);\n            }\n        }\n    }\n\n    /**\n     * This class wraps the sendBuffer method of NIOServerCnxn. It is\n     * responsible for chunking up the response to a client. Rather\n     * than cons'ing up a response fully in memory, which may be large\n     * for some commands, this class chunks up the result.\n     */\n    private class SendBufferWriter extends Writer {\n        private StringBuffer sb = new StringBuffer();\n        \n        /**\n         * Check if we are ready to send another chunk.\n         * @param force force sending, even if not a full chunk\n         */\n        private void checkFlush(boolean force) {\n            if ((force && sb.length() > 0) || sb.length() > 2048) {\n                sendBuffer(ByteBuffer.wrap(sb.toString().getBytes()));\n                // clear our internal buffer\n                sb.setLength(0);\n            }\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (sb == null) return;\n            checkFlush(true);\n            sb = null; // clear out the ref to ensure no reuse\n        }\n\n        @Override\n        public void flush() throws IOException {\n            checkFlush(true);\n        }\n\n        @Override\n        public void write(char[] cbuf, int off, int len) throws IOException {\n            sb.append(cbuf, off, len);\n            checkFlush(false);\n        }\n    }\n\n    private static final String ZK_NOT_SERVING =\n        \"This ZooKeeper instance is not currently serving requests\";\n    \n    /**\n     * Set of threads for commmand ports. All the 4\n     * letter commands are run via a thread. Each class\n     * maps to a correspoding 4 letter command. CommandThread\n     * is the abstract class from which all the others inherit.\n     */\n    private abstract class CommandThread /*extends Thread*/ {\n        PrintWriter pw;\n        \n        CommandThread(PrintWriter pw) {\n            this.pw = pw;\n        }\n        \n        public void start() {\n            run();\n        }\n\n        public void run() {\n            try {\n                commandRun();\n            } catch (IOException ie) {\n                LOG.error(\"Error in running command \", ie);\n            } finally {\n                cleanupWriterSocket(pw);\n            }\n        }\n        \n        public abstract void commandRun() throws IOException;\n    }\n    \n    private class RuokCommand extends CommandThread {\n        public RuokCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            pw.print(\"imok\");\n            \n        }\n    }\n    \n    private class TraceMaskCommand extends CommandThread {\n        TraceMaskCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            long traceMask = ZooTrace.getTextTraceLevel();\n            pw.print(traceMask);\n        }\n    }\n    \n    private class SetTraceMaskCommand extends CommandThread {\n        long trace = 0;\n        SetTraceMaskCommand(PrintWriter pw, long trace) {\n            super(pw);\n            this.trace = trace;\n        }\n        \n        @Override\n        public void commandRun() {\n            pw.print(trace);\n        }\n    }\n    \n    private class EnvCommand extends CommandThread {\n        EnvCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            List<Environment.Entry> env = Environment.list();\n\n            pw.println(\"Environment:\");\n            for(Environment.Entry e : env) {\n                pw.print(e.getKey());\n                pw.print(\"=\");\n                pw.println(e.getValue());\n            }\n            \n        } \n    }\n    \n    private class ConfCommand extends CommandThread {\n        ConfCommand(PrintWriter pw) {\n            super(pw);\n        }\n            \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                zkServer.dumpConf(pw);\n            }\n        }\n    }\n    \n    private class StatResetCommand extends CommandThread {\n        public StatResetCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else { \n                zkServer.serverStats().reset();\n                pw.println(\"Server stats reset.\");\n            }\n        }\n    }\n    \n    private class CnxnStatResetCommand extends CommandThread {\n        public CnxnStatResetCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                synchronized(factory.cnxns){\n                    for(ServerCnxn c : factory.cnxns){\n                        c.resetStats();\n                    }\n                }\n                pw.println(\"Connection stats reset.\");\n            }\n        }\n    }\n\n    private class DumpCommand extends CommandThread {\n        public DumpCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else {\n                pw.println(\"SessionTracker dump:\");\n                zkServer.sessionTracker.dumpSessions(pw);\n                pw.println(\"ephemeral nodes dump:\");\n                zkServer.dumpEphemerals(pw);\n            }\n        }\n    }\n    \n    private class StatCommand extends CommandThread {\n        int len;\n        public StatCommand(PrintWriter pw, int len) {\n            super(pw);\n            this.len = len;\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            }\n            else {   \n                pw.print(\"Zookeeper version: \");\n                pw.println(Version.getFullVersion());\n                if (zkServer instanceof ReadOnlyZooKeeperServer) {\n                    pw.println(\"READ-ONLY mode; serving only \" +\n                               \"read-only clients\");\n                }\n                if (len == statCmd) {\n                    LOG.info(\"Stat command output\");\n                    pw.println(\"Clients:\");\n                    // clone should be faster than iteration\n                    // ie give up the cnxns lock faster\n                    HashSet<ServerCnxn> cnxns;\n                    synchronized(factory.cnxns){\n                        cnxns = new HashSet<ServerCnxn>(factory.cnxns);\n                    }\n                    for(ServerCnxn c : cnxns){\n                        c.dumpConnectionInfo(pw, true);\n                        pw.println();\n                    }\n                    pw.println();\n                }\n                pw.print(zkServer.serverStats().toString());\n                pw.print(\"Node count: \");\n                pw.println(zkServer.getZKDatabase().getNodeCount());\n            }\n            \n        }\n    }\n    \n    private class ConsCommand extends CommandThread {\n        public ConsCommand(PrintWriter pw) {\n            super(pw);\n        }\n        \n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                // clone should be faster than iteration\n                // ie give up the cnxns lock faster\n                AbstractSet<ServerCnxn> cnxns;\n                synchronized (factory.cnxns) {\n                    cnxns = new HashSet<ServerCnxn>(factory.cnxns);\n                }\n                for (ServerCnxn c : cnxns) {\n                    c.dumpConnectionInfo(pw, false);\n                    pw.println();\n                }\n                pw.println();\n            }\n        }\n    }\n    \n    private class WatchCommand extends CommandThread {\n        int len = 0;\n        public WatchCommand(PrintWriter pw, int len) {\n            super(pw);\n            this.len = len;\n        }\n\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n            } else {\n                DataTree dt = zkServer.getZKDatabase().getDataTree();\n                if (len == wchsCmd) {\n                    dt.dumpWatchesSummary(pw);\n                } else if (len == wchpCmd) {\n                    dt.dumpWatches(pw, true);\n                } else {\n                    dt.dumpWatches(pw, false);\n                }\n                pw.println();\n            }\n        }\n    }\n\n    private class MonitorCommand extends CommandThread {\n\n        MonitorCommand(PrintWriter pw) {\n            super(pw);\n        }\n\n        @Override\n        public void commandRun() {\n            if(!isZKServerRunning()) {\n                pw.println(ZK_NOT_SERVING);\n                return;\n            }\n            ZKDatabase zkdb = zkServer.getZKDatabase();\n            ServerStats stats = zkServer.serverStats();\n\n            print(\"version\", Version.getFullVersion());\n\n            print(\"avg_latency\", stats.getAvgLatency());\n            print(\"max_latency\", stats.getMaxLatency());\n            print(\"min_latency\", stats.getMinLatency());\n\n            print(\"packets_received\", stats.getPacketsReceived());\n            print(\"packets_sent\", stats.getPacketsSent());\n            print(\"num_alive_connections\", stats.getNumAliveClientConnections());\n\n            print(\"outstanding_requests\", stats.getOutstandingRequests());\n\n            print(\"server_state\", stats.getServerState());\n            print(\"znode_count\", zkdb.getNodeCount());\n\n            print(\"watch_count\", zkdb.getDataTree().getWatchCount());\n            print(\"ephemerals_count\", zkdb.getDataTree().getEphemeralsCount());\n            print(\"approximate_data_size\", zkdb.getDataTree().approximateDataSize());\n\n            OSMXBean osMbean = new OSMXBean();\n            if (osMbean != null && osMbean.getUnix() == true) {\n                print(\"open_file_descriptor_count\", osMbean.getOpenFileDescriptorCount());\n                print(\"max_file_descriptor_count\", osMbean.getMaxFileDescriptorCount());\n            }\n          \n            if(stats.getServerState().equals(\"leader\")) {\n                Leader leader = ((LeaderZooKeeperServer)zkServer).getLeader();\n\n                print(\"followers\", leader.getLearners().size());\n                print(\"synced_followers\", leader.getForwardingFollowers().size());\n                print(\"pending_syncs\", leader.getNumPendingSyncs());\n            }\n        }\n\n        private void print(String key, long number) {\n            print(key, \"\" + number);\n        }\n\n        private void print(String key, String value) {\n            pw.print(\"zk_\");\n            pw.print(key);\n            pw.print(\"\\t\");\n            pw.println(value);\n        }\n\n    }\n\n    private class IsroCommand extends CommandThread {\n\n        public IsroCommand(PrintWriter pw) {\n            super(pw);\n        }\n\n        @Override\n        public void commandRun() {\n            if (!isZKServerRunning()) {\n                pw.print(\"null\");\n            } else if (zkServer instanceof ReadOnlyZooKeeperServer) {\n                pw.print(\"ro\");\n            } else {\n                pw.print(\"rw\");\n            }\n        }\n    }\n\n    private class NopCommand extends CommandThread {\n        private String msg;\n\n        public NopCommand(PrintWriter pw, String msg) {\n            super(pw);\n            this.msg = msg;\n        }\n\n        @Override\n        public void commandRun() {\n            pw.println(msg);\n        }\n    }\n\n    /** Return if four letter word found and responded to, otw false **/\n    private boolean checkFourLetterWord(final Channel channel,\n            ChannelBuffer message, final int len) throws IOException\n    {\n        // We take advantage of the limited size of the length to look\n        // for cmds. They are all 4-bytes which fits inside of an int\n        if (!ServerCnxn.isKnown(len)) {\n            return false;\n        }\n\n        channel.setInterestOps(0).awaitUninterruptibly();\n        packetReceived();\n\n        final PrintWriter pwriter = new PrintWriter(\n                new BufferedWriter(new SendBufferWriter()));\n\n        String cmd = ServerCnxn.getCommandString(len);\n        // ZOOKEEPER-2693: don't execute 4lw if it's not enabled.\n        if (!ServerCnxn.isEnabled(cmd)) {\n            LOG.debug(\"Command {} is not executed because it is not in the whitelist.\", cmd);\n            NopCommand nopCmd = new NopCommand(pwriter, cmd + \" is not executed because it is not in the whitelist.\");\n            nopCmd.start();\n            return true;\n        }\n\n        LOG.info(\"Processing \" + cmd + \" command from \" + channel.getRemoteAddress());\n\n        if (len == ruokCmd) {\n            RuokCommand ruok = new RuokCommand(pwriter);\n            ruok.start();\n            return true;\n        } else if (len == getTraceMaskCmd) {\n            TraceMaskCommand tmask = new TraceMaskCommand(pwriter);\n            tmask.start();\n            return true;\n        } else if (len == setTraceMaskCmd) {\n            ByteBuffer mask = ByteBuffer.allocate(8);\n            message.readBytes(mask);\n            mask.flip();\n            long traceMask = mask.getLong();\n            ZooTrace.setTextTraceLevel(traceMask);\n            SetTraceMaskCommand setMask = new SetTraceMaskCommand(pwriter, traceMask);\n            setMask.start();\n            return true;\n        } else if (len == enviCmd) {\n            EnvCommand env = new EnvCommand(pwriter);\n            env.start();\n            return true;\n        } else if (len == confCmd) {\n            ConfCommand ccmd = new ConfCommand(pwriter);\n            ccmd.start();\n            return true;\n        } else if (len == srstCmd) {\n            StatResetCommand strst = new StatResetCommand(pwriter);\n            strst.start();\n            return true;\n        } else if (len == crstCmd) {\n            CnxnStatResetCommand crst = new CnxnStatResetCommand(pwriter);\n            crst.start();\n            return true;\n        } else if (len == dumpCmd) {\n            DumpCommand dump = new DumpCommand(pwriter);\n            dump.start();\n            return true;\n        } else if (len == statCmd || len == srvrCmd) {\n            StatCommand stat = new StatCommand(pwriter, len);\n            stat.start();\n            return true;\n        } else if (len == consCmd) {\n            ConsCommand cons = new ConsCommand(pwriter);\n            cons.start();\n            return true;\n        } else if (len == wchpCmd || len == wchcCmd || len == wchsCmd) {\n            WatchCommand wcmd = new WatchCommand(pwriter, len);\n            wcmd.start();\n            return true;\n        } else if (len == mntrCmd) {\n            MonitorCommand mntr = new MonitorCommand(pwriter);\n            mntr.start();\n            return true;\n        } else if (len == isroCmd) {\n            IsroCommand isro = new IsroCommand(pwriter);\n            isro.start();\n            return true;\n        }\n        return false;\n    }\n\n    public void receiveMessage(ChannelBuffer message) {\n        try {\n            while(message.readable() && !throttled) {\n                if (bb != null) {\n                    if (LOG.isTraceEnabled()) {\n                        LOG.trace(\"message readable \" + message.readableBytes()\n                                + \" bb len \" + bb.remaining() + \" \" + bb);\n                        ByteBuffer dat = bb.duplicate();\n                        dat.flip();\n                        LOG.trace(Long.toHexString(sessionId)\n                                + \" bb 0x\"\n                                + ChannelBuffers.hexDump(\n                                        ChannelBuffers.copiedBuffer(dat)));\n                    }\n\n                    if (bb.remaining() > message.readableBytes()) {\n                        int newLimit = bb.position() + message.readableBytes();\n                        bb.limit(newLimit);\n                    }\n                    message.readBytes(bb);\n                    bb.limit(bb.capacity());\n\n                    if (LOG.isTraceEnabled()) {\n                        LOG.trace(\"after readBytes message readable \"\n                                + message.readableBytes()\n                                + \" bb len \" + bb.remaining() + \" \" + bb);\n                        ByteBuffer dat = bb.duplicate();\n                        dat.flip();\n                        LOG.trace(\"after readbytes \"\n                                + Long.toHexString(sessionId)\n                                + \" bb 0x\"\n                                + ChannelBuffers.hexDump(\n                                        ChannelBuffers.copiedBuffer(dat)));\n                    }\n                    if (bb.remaining() == 0) {\n                        packetReceived();\n                        bb.flip();\n\n                        ZooKeeperServer zks = this.zkServer;\n                        if (zks == null || !zks.isRunning()) {\n                            throw new IOException(\"ZK down\");\n                        }\n                        if (initialized) {\n                            zks.processPacket(this, bb);\n\n                            if (zks.shouldThrottle(outstandingCount.incrementAndGet())) {\n                                disableRecvNoWait();\n                            }\n                        } else {\n                            LOG.debug(\"got conn req request from \"\n                                    + getRemoteSocketAddress());\n                            zks.processConnectRequest(this, bb);\n                            initialized = true;\n                        }\n                        bb = null;\n                    }\n                } else {\n                    if (LOG.isTraceEnabled()) {\n                        LOG.trace(\"message readable \"\n                                + message.readableBytes()\n                                + \" bblenrem \" + bbLen.remaining());\n                        ByteBuffer dat = bbLen.duplicate();\n                        dat.flip();\n                        LOG.trace(Long.toHexString(sessionId)\n                                + \" bbLen 0x\"\n                                + ChannelBuffers.hexDump(\n                                        ChannelBuffers.copiedBuffer(dat)));\n                    }\n\n                    if (message.readableBytes() < bbLen.remaining()) {\n                        bbLen.limit(bbLen.position() + message.readableBytes());\n                    }\n                    message.readBytes(bbLen);\n                    bbLen.limit(bbLen.capacity());\n                    if (bbLen.remaining() == 0) {\n                        bbLen.flip();\n\n                        if (LOG.isTraceEnabled()) {\n                            LOG.trace(Long.toHexString(sessionId)\n                                    + \" bbLen 0x\"\n                                    + ChannelBuffers.hexDump(\n                                            ChannelBuffers.copiedBuffer(bbLen)));\n                        }\n                        int len = bbLen.getInt();\n                        if (LOG.isTraceEnabled()) {\n                            LOG.trace(Long.toHexString(sessionId)\n                                    + \" bbLen len is \" + len);\n                        }\n\n                        bbLen.clear();\n                        if (!initialized) {\n                            if (checkFourLetterWord(channel, message, len)) {\n                                return;\n                            }\n                        }\n                        if (len < 0 || len > BinaryInputArchive.maxBuffer) {\n                            throw new IOException(\"Len error \" + len);\n                        }\n                        bb = ByteBuffer.allocate(len);\n                    }\n                }\n            }\n        } catch(IOException e) {\n            LOG.warn(\"Closing connection to \" + getRemoteSocketAddress(), e);\n            close();\n        }\n    }\n\n    @Override\n    public void disableRecv() {\n        disableRecvNoWait().awaitUninterruptibly();\n    }\n    \n    private ChannelFuture disableRecvNoWait() {\n        throttled = true;\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Throttling - disabling recv \" + this);\n        }\n        return channel.setReadable(false);\n    }\n    \n    @Override\n    public long getOutstandingRequests() {\n        return outstandingCount.longValue();\n    }\n\n    @Override\n    public void setSessionTimeout(int sessionTimeout) {\n        this.sessionTimeout = sessionTimeout;\n    }\n\n    @Override\n    public int getInterestOps() {\n        return channel.getInterestOps();\n    }\n\n    @Override\n    public InetSocketAddress getRemoteSocketAddress() {\n        return (InetSocketAddress)channel.getRemoteAddress();\n    }\n\n    /** Send close connection packet to the client.\n     */\n    @Override\n    public void sendCloseSession() {\n        sendBuffer(ServerCnxnFactory.closeConn);\n    }\n\n    @Override\n    protected ServerStats serverStats() {\n        if (!isZKServerRunning()) {\n            return null;\n        }\n        return zkServer.serverStats();\n    }\n\n    /**\n     * @return true if the server is running, false otherwise.\n     */\n    boolean isZKServerRunning() {\n        return zkServer != null && zkServer.isRunning();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/NettyServerCnxnFactory.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.jboss.netty.buffer.ChannelBuffers.dynamicBuffer;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.jboss.netty.bootstrap.ServerBootstrap;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelHandler.Sharable;\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.ChannelStateEvent;\nimport org.jboss.netty.channel.ExceptionEvent;\nimport org.jboss.netty.channel.MessageEvent;\nimport org.jboss.netty.channel.SimpleChannelHandler;\nimport org.jboss.netty.channel.WriteCompletionEvent;\nimport org.jboss.netty.channel.group.ChannelGroup;\nimport org.jboss.netty.channel.group.DefaultChannelGroup;\nimport org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;\n\npublic class NettyServerCnxnFactory extends ServerCnxnFactory {\n    Logger LOG = LoggerFactory.getLogger(NettyServerCnxnFactory.class);\n\n    ServerBootstrap bootstrap;\n    Channel parentChannel;\n    ChannelGroup allChannels = new DefaultChannelGroup(\"zkServerCnxns\");\n    HashMap<InetAddress, Set<NettyServerCnxn>> ipMap =\n        new HashMap<InetAddress, Set<NettyServerCnxn>>( );\n    InetSocketAddress localAddress;\n    int maxClientCnxns = 60;\n    \n    /**\n     * This is an inner class since we need to extend SimpleChannelHandler, but\n     * NettyServerCnxnFactory already extends ServerCnxnFactory. By making it inner\n     * this class gets access to the member variables and methods.\n     */\n    @Sharable\n    class CnxnChannelHandler extends SimpleChannelHandler {\n\n        @Override\n        public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)\n            throws Exception\n        {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Channel closed \" + e);\n            }\n            allChannels.remove(ctx.getChannel());\n        }\n\n        @Override\n        public void channelConnected(ChannelHandlerContext ctx,\n                ChannelStateEvent e) throws Exception\n        {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Channel connected \" + e);\n            }\n            allChannels.add(ctx.getChannel());\n            NettyServerCnxn cnxn = new NettyServerCnxn(ctx.getChannel(),\n                    zkServer, NettyServerCnxnFactory.this);\n            ctx.setAttachment(cnxn);\n            addCnxn(cnxn);\n        }\n\n        @Override\n        public void channelDisconnected(ChannelHandlerContext ctx,\n                ChannelStateEvent e) throws Exception\n        {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Channel disconnected \" + e);\n            }\n            NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment();\n            if (cnxn != null) {\n                if (LOG.isTraceEnabled()) {\n                    LOG.trace(\"Channel disconnect caused close \" + e);\n                }\n                cnxn.close();\n            }\n        }\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)\n            throws Exception\n        {\n            LOG.warn(\"Exception caught \" + e, e.getCause());\n            NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment();\n            if (cnxn != null) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Closing \" + cnxn);\n                }\n                cnxn.close();\n            }\n        }\n\n        @Override\n        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)\n            throws Exception\n        {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"message received called \" + e.getMessage());\n            }\n            try {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"New message \" + e.toString()\n                            + \" from \" + ctx.getChannel());\n                }\n                NettyServerCnxn cnxn = (NettyServerCnxn)ctx.getAttachment();\n                synchronized(cnxn) {\n                    processMessage(e, cnxn);\n                }\n            } catch(Exception ex) {\n                LOG.error(\"Unexpected exception in receive\", ex);\n                throw ex;\n            }\n        }\n\n        private void processMessage(MessageEvent e, NettyServerCnxn cnxn) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(Long.toHexString(cnxn.sessionId) + \" queuedBuffer: \"\n                        + cnxn.queuedBuffer);\n            }\n\n            if (e instanceof NettyServerCnxn.ResumeMessageEvent) {\n                LOG.debug(\"Received ResumeMessageEvent\");\n                if (cnxn.queuedBuffer != null) {\n                    if (LOG.isTraceEnabled()) {\n                        LOG.trace(\"processing queue \"\n                                + Long.toHexString(cnxn.sessionId)\n                                + \" queuedBuffer 0x\"\n                                + ChannelBuffers.hexDump(cnxn.queuedBuffer));\n                    }\n                    cnxn.receiveMessage(cnxn.queuedBuffer);\n                    if (!cnxn.queuedBuffer.readable()) {\n                        LOG.debug(\"Processed queue - no bytes remaining\");\n                        cnxn.queuedBuffer = null;\n                    } else {\n                        LOG.debug(\"Processed queue - bytes remaining\");\n                    }\n                } else {\n                    LOG.debug(\"queue empty\");\n                }\n                cnxn.channel.setReadable(true);\n            } else {\n                ChannelBuffer buf = (ChannelBuffer)e.getMessage();\n                if (LOG.isTraceEnabled()) {\n                    LOG.trace(Long.toHexString(cnxn.sessionId)\n                            + \" buf 0x\"\n                            + ChannelBuffers.hexDump(buf));\n                }\n                \n                if (cnxn.throttled) {\n                    LOG.debug(\"Received message while throttled\");\n                    // we are throttled, so we need to queue\n                    if (cnxn.queuedBuffer == null) {\n                        LOG.debug(\"allocating queue\");\n                        cnxn.queuedBuffer = dynamicBuffer(buf.readableBytes());\n                    }\n                    cnxn.queuedBuffer.writeBytes(buf);\n                    if (LOG.isTraceEnabled()) {\n                        LOG.trace(Long.toHexString(cnxn.sessionId)\n                                + \" queuedBuffer 0x\"\n                                + ChannelBuffers.hexDump(cnxn.queuedBuffer));\n                    }\n                } else {\n                    LOG.debug(\"not throttled\");\n                    if (cnxn.queuedBuffer != null) {\n                        if (LOG.isTraceEnabled()) {\n                            LOG.trace(Long.toHexString(cnxn.sessionId)\n                                    + \" queuedBuffer 0x\"\n                                    + ChannelBuffers.hexDump(cnxn.queuedBuffer));\n                        }\n                        cnxn.queuedBuffer.writeBytes(buf);\n                        if (LOG.isTraceEnabled()) {\n                            LOG.trace(Long.toHexString(cnxn.sessionId)\n                                    + \" queuedBuffer 0x\"\n                                    + ChannelBuffers.hexDump(cnxn.queuedBuffer));\n                        }\n\n                        cnxn.receiveMessage(cnxn.queuedBuffer);\n                        if (!cnxn.queuedBuffer.readable()) {\n                            LOG.debug(\"Processed queue - no bytes remaining\");\n                            cnxn.queuedBuffer = null;\n                        } else {\n                            LOG.debug(\"Processed queue - bytes remaining\");\n                        }\n                    } else {\n                        cnxn.receiveMessage(buf);\n                        if (buf.readable()) {\n                            if (LOG.isTraceEnabled()) {\n                                LOG.trace(\"Before copy \" + buf);\n                            }\n                            cnxn.queuedBuffer = dynamicBuffer(buf.readableBytes()); \n                            cnxn.queuedBuffer.writeBytes(buf);\n                            if (LOG.isTraceEnabled()) {\n                                LOG.trace(\"Copy is \" + cnxn.queuedBuffer);\n                                LOG.trace(Long.toHexString(cnxn.sessionId)\n                                        + \" queuedBuffer 0x\"\n                                        + ChannelBuffers.hexDump(cnxn.queuedBuffer));\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void writeComplete(ChannelHandlerContext ctx,\n                WriteCompletionEvent e) throws Exception\n        {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"write complete \" + e);\n            }\n        }\n        \n    }\n    \n    CnxnChannelHandler channelHandler = new CnxnChannelHandler();\n    \n    NettyServerCnxnFactory() {\n        bootstrap = new ServerBootstrap(\n                new NioServerSocketChannelFactory(\n                        Executors.newCachedThreadPool(),\n                        Executors.newCachedThreadPool()));\n        // parent channel\n        bootstrap.setOption(\"reuseAddress\", true);\n        // child channels\n        bootstrap.setOption(\"child.tcpNoDelay\", true);\n        /* set socket linger to off, so that socket close does not block */\n        bootstrap.setOption(\"child.soLinger\", -1);\n\n        bootstrap.getPipeline().addLast(\"servercnxnfactory\", channelHandler);\n    }\n    \n    @Override\n    public void closeAll() {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"closeAll()\");\n        }\n\n        NettyServerCnxn[] allCnxns = null;\n        synchronized (cnxns) {\n            allCnxns = cnxns.toArray(new NettyServerCnxn[cnxns.size()]);\n        }\n        // got to clear all the connections that we have in the selector\n        for (NettyServerCnxn cnxn : allCnxns) {\n            try {\n                cnxn.close();\n            } catch (Exception e) {\n                LOG.warn(\"Ignoring exception closing cnxn sessionid 0x\"\n                                + Long.toHexString(cnxn.getSessionId()), e);\n            }\n        }\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"allChannels size:\" + allChannels.size() + \" cnxns size:\"\n                    + allCnxns.length);\n        }\n    }\n\n    @Override\n    public void closeSession(long sessionId) {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"closeSession sessionid:0x\" + sessionId);\n        }\n\n        NettyServerCnxn cnxn = (NettyServerCnxn) sessionMap.remove(sessionId);\n        if (cnxn != null) {\n            try {\n                cnxn.close();\n            } catch (Exception e) {\n                LOG.warn(\"exception during session close\", e);\n            }\n        }\n    }\n\n    @Override\n    public void configure(InetSocketAddress addr, int maxClientCnxns)\n            throws IOException\n    {\n        configureSaslLogin();\n        localAddress = addr;\n        this.maxClientCnxns = maxClientCnxns;\n    }\n\n    /** {@inheritDoc} */\n    public int getMaxClientCnxnsPerHost() {\n        return maxClientCnxns;\n    }\n\n    /** {@inheritDoc} */\n    public void setMaxClientCnxnsPerHost(int max) {\n        maxClientCnxns = max;\n    }\n\n    @Override\n    public int getLocalPort() {\n        return localAddress.getPort();\n    }\n\n    boolean killed;\n    @Override\n    public void join() throws InterruptedException {\n        synchronized(this) {\n            while(!killed) {\n                wait();\n            }\n        }\n    }\n\n    @Override\n    public void shutdown() {\n        LOG.info(\"shutdown called \" + localAddress);\n        if (login != null) {\n            login.shutdown();\n        }\n        // null if factory never started\n        if (parentChannel != null) {\n            parentChannel.close().awaitUninterruptibly();\n            closeAll();\n            allChannels.close().awaitUninterruptibly();\n            bootstrap.releaseExternalResources();\n        }\n\n        if (zkServer != null) {\n            zkServer.shutdown();\n        }\n        synchronized(this) {\n            killed = true;\n            notifyAll();\n        }\n    }\n    \n    @Override\n    public void start() {\n        LOG.info(\"binding to port \" + localAddress);\n        parentChannel = bootstrap.bind(localAddress);\n    }\n\n    @Override\n    public void startup(ZooKeeperServer zks) throws IOException,\n            InterruptedException {\n        start();\n        setZooKeeperServer(zks);\n        zks.startdata();\n        zks.startup();\n    }\n\n    @Override\n    public Iterable<ServerCnxn> getConnections() {\n        return cnxns;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return localAddress;\n    }\n\n    private void addCnxn(NettyServerCnxn cnxn) {\n        synchronized (cnxns) {\n            cnxns.add(cnxn);\n            synchronized (ipMap){\n                InetAddress addr =\n                    ((InetSocketAddress)cnxn.channel.getRemoteAddress())\n                        .getAddress();\n                Set<NettyServerCnxn> s = ipMap.get(addr);\n                if (s == null) {\n                    s = new HashSet<NettyServerCnxn>();\n                }\n                s.add(cnxn);\n                ipMap.put(addr,s);\n            }\n        }\n    }\n\n    public void removeCnxn(ServerCnxn cnxn) {\n        synchronized(cnxns){\n            // if this is not in cnxns then it's already closed\n            if (!cnxns.remove(cnxn)) {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"cnxns size:\" + cnxns.size());\n                }\n                return;\n            }\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"close in progress for sessionid:0x\"\n                        + Long.toHexString(cnxn.getSessionId()));\n            }\n\n            synchronized (ipMap) {\n                Set<NettyServerCnxn> s =\n                        ipMap.get(cnxn.getSocketAddress());\n                s.remove(cnxn);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ObserverBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.zookeeper.server.quorum.Observer;\nimport org.apache.zookeeper.server.quorum.ObserverMXBean;\n\n/**\n * ObserverBean\n *\n */\npublic class ObserverBean extends ZooKeeperServerBean implements ObserverMXBean{\n\n    private Observer observer;\n    \n    public ObserverBean(Observer observer, ZooKeeperServer zks) {\n        super(zks);        \n        this.observer = observer;\n    }\n\n    public String getName() {\n        return \"Observer\";\n    }\n\n    public int getPendingRevalidationCount() {\n       return this.observer.getPendingRevalidationsCount(); \n    }\n\n    public String getQuorumAddress() {\n        return observer.getSocket().toString();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.apache.jute.Record;\nimport org.apache.jute.BinaryOutputArchive;\n\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.BadArgumentsException;\nimport org.apache.zookeeper.MultiTransactionRecord;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.common.PathUtils;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.data.StatPersisted;\nimport org.apache.zookeeper.proto.CreateRequest;\nimport org.apache.zookeeper.proto.DeleteRequest;\nimport org.apache.zookeeper.proto.SetACLRequest;\nimport org.apache.zookeeper.proto.SetDataRequest;\nimport org.apache.zookeeper.proto.CheckVersionRequest;\nimport org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord;\nimport org.apache.zookeeper.server.auth.AuthenticationProvider;\nimport org.apache.zookeeper.server.auth.ProviderRegistry;\nimport org.apache.zookeeper.server.quorum.Leader.XidRolloverException;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.CheckVersionTxn;\nimport org.apache.zookeeper.txn.Txn;\nimport org.apache.zookeeper.txn.MultiTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This request processor is generally at the start of a RequestProcessor\n * change. It sets up any transactions associated with requests that change the\n * state of the system. It counts on ZooKeeperServer to update\n * outstandingRequests, so that it can take into account transactions that are\n * in the queue to be applied when generating a transaction.\n */\npublic class PrepRequestProcessor extends ZooKeeperCriticalThread implements\n        RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(PrepRequestProcessor.class);\n\n    static boolean skipACL;\n    static {\n        skipACL = System.getProperty(\"zookeeper.skipACL\", \"no\").equals(\"yes\");\n        if (skipACL) {\n            LOG.info(\"zookeeper.skipACL==\\\"yes\\\", ACL checks will be skipped\");\n        }\n    }\n\n    /**\n     * this is only for testing purposes.\n     * should never be useed otherwise\n     */\n    private static  boolean failCreate = false;\n\n    LinkedBlockingQueue<Request> submittedRequests = new LinkedBlockingQueue<Request>();\n\n    RequestProcessor nextProcessor;\n\n    ZooKeeperServer zks;\n\n    public PrepRequestProcessor(ZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        super(\"ProcessThread(sid:\" + zks.getServerId() + \" cport:\"\n                + zks.getClientPort() + \"):\", zks.getZooKeeperServerListener());\n        this.nextProcessor = nextProcessor;\n        this.zks = zks;\n    }\n\n    /**\n     * method for tests to set failCreate\n     * @param b\n     */\n    public static void setFailCreate(boolean b) {\n        failCreate = b;\n    }\n    @Override\n    public void run() {\n        try {\n            while (true) {\n                Request request = submittedRequests.take();\n                long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;\n                if (request.type == OpCode.ping) {\n                    traceMask = ZooTrace.CLIENT_PING_TRACE_MASK;\n                }\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logRequest(LOG, traceMask, 'P', request, \"\");\n                }\n                if (Request.requestOfDeath == request) {\n                    break;\n                }\n                pRequest(request);\n            }\n        } catch (RequestProcessorException e) {\n            if (e.getCause() instanceof XidRolloverException) {\n                LOG.info(e.getCause().getMessage());\n            }\n            handleException(this.getName(), e);\n        } catch (Exception e) {\n            handleException(this.getName(), e);\n        }\n        LOG.info(\"PrepRequestProcessor exited loop!\");\n    }\n\n    ChangeRecord getRecordForPath(String path) throws KeeperException.NoNodeException {\n        ChangeRecord lastChange = null;\n        synchronized (zks.outstandingChanges) {\n            lastChange = zks.outstandingChangesForPath.get(path);\n            if (lastChange == null) {\n                DataNode n = zks.getZKDatabase().getNode(path);\n                if (n != null) {\n                    Set<String> children;\n                    synchronized(n) {\n                        children = n.getChildren();\n                    }\n                    lastChange = new ChangeRecord(-1, path, n.stat, children.size(),\n                            zks.getZKDatabase().aclForNode(n));\n                }\n            }\n        }\n        if (lastChange == null || lastChange.stat == null) {\n            throw new KeeperException.NoNodeException(path);\n        }\n        return lastChange;\n    }\n\n    private ChangeRecord getOutstandingChange(String path) {\n        synchronized (zks.outstandingChanges) {\n            return zks.outstandingChangesForPath.get(path);\n        }\n    }\n\n    void addChangeRecord(ChangeRecord c) {\n        synchronized (zks.outstandingChanges) {\n            zks.outstandingChanges.add(c);\n            zks.outstandingChangesForPath.put(c.path, c);\n        }\n    }\n\n    /**\n     * Grab current pending change records for each op in a multi-op.\n     * \n     * This is used inside MultiOp error code path to rollback in the event\n     * of a failed multi-op.\n     *\n     * @param multiRequest\n     * @return a map that contains previously existed records that probably need to be\n     *         rolled back in any failure.\n     */\n    HashMap<String, ChangeRecord> getPendingChanges(MultiTransactionRecord multiRequest) {\n        HashMap<String, ChangeRecord> pendingChangeRecords = new HashMap<String, ChangeRecord>();\n\n        for (Op op : multiRequest) {\n            String path = op.getPath();\n            ChangeRecord cr = getOutstandingChange(path);\n            // only previously existing records need to be rolled back.\n            if (cr != null) {\n                pendingChangeRecords.put(path, cr);\n            }\n\n            /*\n             * ZOOKEEPER-1624 - We need to store for parent's ChangeRecord\n             * of the parent node of a request. So that if this is a\n             * sequential node creation request, rollbackPendingChanges()\n             * can restore previous parent's ChangeRecord correctly.\n             *\n             * Otherwise, sequential node name generation will be incorrect\n             * for a subsequent request.\n             */\n            int lastSlash = path.lastIndexOf('/');\n            if (lastSlash == -1 || path.indexOf('\\0') != -1) {\n                continue;\n            }\n            String parentPath = path.substring(0, lastSlash);\n            ChangeRecord parentCr = getOutstandingChange(parentPath);\n            if (parentCr != null) {\n                pendingChangeRecords.put(parentPath, parentCr);\n            }\n        }\n\n        return pendingChangeRecords;\n    }\n\n    /**\n     * Rollback pending changes records from a failed multi-op.\n     *\n     * If a multi-op fails, we can't leave any invalid change records we created\n     * around. We also need to restore their prior value (if any) if their prior\n     * value is still valid.\n     *\n     * @param zxid\n     * @param pendingChangeRecords\n     */\n    void rollbackPendingChanges(long zxid, HashMap<String, ChangeRecord>pendingChangeRecords) {\n        synchronized (zks.outstandingChanges) {\n            // Grab a list iterator starting at the END of the list so we can iterate in reverse\n            ListIterator<ChangeRecord> iter = zks.outstandingChanges.listIterator(zks.outstandingChanges.size());\n            while (iter.hasPrevious()) {\n                ChangeRecord c = iter.previous();\n                if (c.zxid == zxid) {\n                    iter.remove();\n                    // Remove all outstanding changes for paths of this multi.\n                    // Previous records will be added back later.\n                    zks.outstandingChangesForPath.remove(c.path);\n                } else {\n                    break;\n                }\n            }\n\n            // we don't need to roll back any records because there is nothing left.\n            if (zks.outstandingChanges.isEmpty()) {\n                return;\n            }\n\n            long firstZxid = zks.outstandingChanges.get(0).zxid;\n\n            for (ChangeRecord c : pendingChangeRecords.values()) {\n                // Don't apply any prior change records less than firstZxid.\n                // Note that previous outstanding requests might have been removed\n                // once they are completed.\n                if (c.zxid < firstZxid) {\n                    continue;\n                }\n\n                // add previously existing records back.\n                zks.outstandingChangesForPath.put(c.path, c);\n            }\n        }\n    }\n\n    static void checkACL(ZooKeeperServer zks, List<ACL> acl, int perm,\n            List<Id> ids) throws KeeperException.NoAuthException {\n        if (skipACL) {\n            return;\n        }\n        if (acl == null || acl.size() == 0) {\n            return;\n        }\n        for (Id authId : ids) {\n            if (authId.getScheme().equals(\"super\")) {\n                return;\n            }\n        }\n        for (ACL a : acl) {\n            Id id = a.getId();\n            if ((a.getPerms() & perm) != 0) {\n                if (id.getScheme().equals(\"world\")\n                        && id.getId().equals(\"anyone\")) {\n                    return;\n                }\n                AuthenticationProvider ap = ProviderRegistry.getProvider(id\n                        .getScheme());\n                if (ap != null) {\n                    for (Id authId : ids) {                        \n                        if (authId.getScheme().equals(id.getScheme())\n                                && ap.matches(authId.getId(), id.getId())) {\n                            return;\n                        }\n                    }\n                }\n            }\n        }\n        throw new KeeperException.NoAuthException();\n    }\n\n    /**\n     * This method will be called inside the ProcessRequestThread, which is a\n     * singleton, so there will be a single thread calling this code.\n     *\n     * @param type\n     * @param zxid\n     * @param request\n     * @param record\n     */\n    @SuppressWarnings(\"unchecked\")\n    protected void pRequest2Txn(int type, long zxid, Request request, Record record, boolean deserialize)\n        throws KeeperException, IOException, RequestProcessorException\n    {\n        request.hdr = new TxnHeader(request.sessionId, request.cxid, zxid,\n                                    Time.currentWallTime(), type);\n\n        switch (type) {\n            case OpCode.create:                \n                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                CreateRequest createRequest = (CreateRequest)record;   \n                if(deserialize)\n                    ByteBufferInputStream.byteBuffer2Record(request.request, createRequest);\n                String path = createRequest.getPath();\n                int lastSlash = path.lastIndexOf('/');\n                if (lastSlash == -1 || path.indexOf('\\0') != -1 || failCreate) {\n                    LOG.info(\"Invalid path \" + path + \" with session 0x\" +\n                            Long.toHexString(request.sessionId));\n                    throw new KeeperException.BadArgumentsException(path);\n                }\n                List<ACL> listACL = removeDuplicates(createRequest.getAcl());\n                if (!fixupACL(request.authInfo, listACL)) {\n                    throw new KeeperException.InvalidACLException(path);\n                }\n                String parentPath = path.substring(0, lastSlash);\n                ChangeRecord parentRecord = getRecordForPath(parentPath);\n\n                checkACL(zks, parentRecord.acl, ZooDefs.Perms.CREATE,\n                        request.authInfo);\n                int parentCVersion = parentRecord.stat.getCversion();\n                CreateMode createMode =\n                    CreateMode.fromFlag(createRequest.getFlags());\n                if (createMode.isSequential()) {\n                    path = path + String.format(Locale.ENGLISH, \"%010d\", parentCVersion);\n                }\n                validatePath(path, request.sessionId);\n                try {\n                    if (getRecordForPath(path) != null) {\n                        throw new KeeperException.NodeExistsException(path);\n                    }\n                } catch (KeeperException.NoNodeException e) {\n                    // ignore this one\n                }\n                boolean ephemeralParent = parentRecord.stat.getEphemeralOwner() != 0;\n                if (ephemeralParent) {\n                    throw new KeeperException.NoChildrenForEphemeralsException(path);\n                }\n                int newCversion = parentRecord.stat.getCversion()+1;\n                request.txn = new CreateTxn(path, createRequest.getData(),\n                        listACL,\n                        createMode.isEphemeral(), newCversion);\n                StatPersisted s = new StatPersisted();\n                if (createMode.isEphemeral()) {\n                    s.setEphemeralOwner(request.sessionId);\n                }\n                parentRecord = parentRecord.duplicate(request.hdr.getZxid());\n                parentRecord.childCount++;\n                parentRecord.stat.setCversion(newCversion);\n                addChangeRecord(parentRecord);\n                addChangeRecord(new ChangeRecord(request.hdr.getZxid(), path, s,\n                        0, listACL));\n                break;\n            case OpCode.delete:\n                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                DeleteRequest deleteRequest = (DeleteRequest)record;\n                if(deserialize)\n                    ByteBufferInputStream.byteBuffer2Record(request.request, deleteRequest);\n                path = deleteRequest.getPath();\n                lastSlash = path.lastIndexOf('/');\n                if (lastSlash == -1 || path.indexOf('\\0') != -1\n                        || zks.getZKDatabase().isSpecialPath(path)) {\n                    throw new KeeperException.BadArgumentsException(path);\n                }\n                parentPath = path.substring(0, lastSlash);\n                parentRecord = getRecordForPath(parentPath);\n                ChangeRecord nodeRecord = getRecordForPath(path);\n                checkACL(zks, parentRecord.acl, ZooDefs.Perms.DELETE,\n                        request.authInfo);\n                int version = deleteRequest.getVersion();\n                if (version != -1 && nodeRecord.stat.getVersion() != version) {\n                    throw new KeeperException.BadVersionException(path);\n                }\n                if (nodeRecord.childCount > 0) {\n                    throw new KeeperException.NotEmptyException(path);\n                }\n                request.txn = new DeleteTxn(path);\n                parentRecord = parentRecord.duplicate(request.hdr.getZxid());\n                parentRecord.childCount--;\n                addChangeRecord(parentRecord);\n                addChangeRecord(new ChangeRecord(request.hdr.getZxid(), path,\n                        null, -1, null));\n                break;\n            case OpCode.setData:\n                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                SetDataRequest setDataRequest = (SetDataRequest)record;\n                if(deserialize)\n                    ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);\n                path = setDataRequest.getPath();\n                validatePath(path, request.sessionId);\n                nodeRecord = getRecordForPath(path);\n                checkACL(zks, nodeRecord.acl, ZooDefs.Perms.WRITE,\n                        request.authInfo);\n                version = setDataRequest.getVersion();\n                int currentVersion = nodeRecord.stat.getVersion();\n                if (version != -1 && version != currentVersion) {\n                    throw new KeeperException.BadVersionException(path);\n                }\n                version = currentVersion + 1;\n                request.txn = new SetDataTxn(path, setDataRequest.getData(), version);\n                nodeRecord = nodeRecord.duplicate(request.hdr.getZxid());\n                nodeRecord.stat.setVersion(version);\n                addChangeRecord(nodeRecord);\n                break;\n            case OpCode.setACL:\n                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                SetACLRequest setAclRequest = (SetACLRequest)record;\n                if(deserialize)\n                    ByteBufferInputStream.byteBuffer2Record(request.request, setAclRequest);\n                path = setAclRequest.getPath();\n                validatePath(path, request.sessionId);\n                listACL = removeDuplicates(setAclRequest.getAcl());\n                if (!fixupACL(request.authInfo, listACL)) {\n                    throw new KeeperException.InvalidACLException(path);\n                }\n                nodeRecord = getRecordForPath(path);\n                checkACL(zks, nodeRecord.acl, ZooDefs.Perms.ADMIN,\n                        request.authInfo);\n                version = setAclRequest.getVersion();\n                currentVersion = nodeRecord.stat.getAversion();\n                if (version != -1 && version != currentVersion) {\n                    throw new KeeperException.BadVersionException(path);\n                }\n                version = currentVersion + 1;\n                request.txn = new SetACLTxn(path, listACL, version);\n                nodeRecord = nodeRecord.duplicate(request.hdr.getZxid());\n                nodeRecord.stat.setAversion(version);\n                addChangeRecord(nodeRecord);\n                break;\n            case OpCode.createSession:\n                request.request.rewind();\n                int to = request.request.getInt();\n                request.txn = new CreateSessionTxn(to);\n                request.request.rewind();\n                zks.sessionTracker.addSession(request.sessionId, to);\n                zks.setOwner(request.sessionId, request.getOwner());\n                break;\n            case OpCode.closeSession:\n                // We don't want to do this check since the session expiration thread\n                // queues up this operation without being the session owner.\n                // this request is the last of the session so it should be ok\n                //zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                HashSet<String> es = zks.getZKDatabase()\n                        .getEphemerals(request.sessionId);\n                synchronized (zks.outstandingChanges) {\n                    for (ChangeRecord c : zks.outstandingChanges) {\n                        if (c.stat == null) {\n                            // Doing a delete\n                            es.remove(c.path);\n                        } else if (c.stat.getEphemeralOwner() == request.sessionId) {\n                            es.add(c.path);\n                        }\n                    }\n                    for (String path2Delete : es) {\n                        addChangeRecord(new ChangeRecord(request.hdr.getZxid(),\n                                path2Delete, null, 0, null));\n                    }\n\n                    zks.sessionTracker.setSessionClosing(request.sessionId);\n                }\n\n                LOG.info(\"Processed session termination for sessionid: 0x\"\n                        + Long.toHexString(request.sessionId));\n                break;\n            case OpCode.check:\n                zks.sessionTracker.checkSession(request.sessionId, request.getOwner());\n                CheckVersionRequest checkVersionRequest = (CheckVersionRequest)record;\n                if(deserialize)\n                    ByteBufferInputStream.byteBuffer2Record(request.request, checkVersionRequest);\n                path = checkVersionRequest.getPath();\n                validatePath(path, request.sessionId);\n                nodeRecord = getRecordForPath(path);\n                checkACL(zks, nodeRecord.acl, ZooDefs.Perms.READ,\n                        request.authInfo);\n                version = checkVersionRequest.getVersion();\n                currentVersion = nodeRecord.stat.getVersion();\n                if (version != -1 && version != currentVersion) {\n                    throw new KeeperException.BadVersionException(path);\n                }\n                version = currentVersion + 1;\n                request.txn = new CheckVersionTxn(path, version);\n                break;\n            default:\n                LOG.error(\"Invalid OpCode: {} received by PrepRequestProcessor\", type);\n        }\n    }\n\n    private void validatePath(String path, long sessionId) throws BadArgumentsException {\n        try {\n            PathUtils.validatePath(path);\n        } catch(IllegalArgumentException ie) {\n            LOG.info(\"Invalid path \" +  path + \" with session 0x\" + Long.toHexString(sessionId) +\n                    \", reason: \" + ie.getMessage());\n            throw new BadArgumentsException(path);\n        }\n    }\n\n    /**\n     * This method will be called inside the ProcessRequestThread, which is a\n     * singleton, so there will be a single thread calling this code.\n     *\n     * @param request\n     */\n    @SuppressWarnings(\"unchecked\")\n    protected void pRequest(Request request) throws RequestProcessorException {\n        // LOG.info(\"Prep>>> cxid = \" + request.cxid + \" type = \" +\n        // request.type + \" id = 0x\" + Long.toHexString(request.sessionId));\n        request.hdr = null;\n        request.txn = null;\n        \n        try {\n            switch (request.type) {\n                case OpCode.create:\n                CreateRequest createRequest = new CreateRequest();\n                pRequest2Txn(request.type, zks.getNextZxid(), request, createRequest, true);\n                break;\n            case OpCode.delete:\n                DeleteRequest deleteRequest = new DeleteRequest();               \n                pRequest2Txn(request.type, zks.getNextZxid(), request, deleteRequest, true);\n                break;\n            case OpCode.setData:\n                SetDataRequest setDataRequest = new SetDataRequest();                \n                pRequest2Txn(request.type, zks.getNextZxid(), request, setDataRequest, true);\n                break;\n            case OpCode.setACL:\n                SetACLRequest setAclRequest = new SetACLRequest();                \n                pRequest2Txn(request.type, zks.getNextZxid(), request, setAclRequest, true);\n                break;\n            case OpCode.check:\n                CheckVersionRequest checkRequest = new CheckVersionRequest();              \n                pRequest2Txn(request.type, zks.getNextZxid(), request, checkRequest, true);\n                break;\n            case OpCode.multi:\n                MultiTransactionRecord multiRequest = new MultiTransactionRecord();\n                try {\n                    ByteBufferInputStream.byteBuffer2Record(request.request, multiRequest);\n                } catch(IOException e) {\n                    request.hdr =  new TxnHeader(request.sessionId, request.cxid, zks.getNextZxid(),\n                            Time.currentWallTime(), OpCode.multi);\n                    throw e;\n                }\n                List<Txn> txns = new ArrayList<Txn>();\n                //Each op in a multi-op must have the same zxid!\n                long zxid = zks.getNextZxid();\n                KeeperException ke = null;\n\n                //Store off current pending change records in case we need to rollback\n                HashMap<String, ChangeRecord> pendingChanges = getPendingChanges(multiRequest);\n\n                int index = 0;\n                for(Op op: multiRequest) {\n                    Record subrequest = op.toRequestRecord() ;\n\n                    /* If we've already failed one of the ops, don't bother\n                     * trying the rest as we know it's going to fail and it\n                     * would be confusing in the logfiles.\n                     */\n                    if (ke != null) {\n                        request.hdr.setType(OpCode.error);\n                        request.txn = new ErrorTxn(Code.RUNTIMEINCONSISTENCY.intValue());\n                    } \n                    \n                    /* Prep the request and convert to a Txn */\n                    else {\n                        try {\n                            pRequest2Txn(op.getType(), zxid, request, subrequest, false);\n                        } catch (KeeperException e) {\n                            ke = e;\n                            request.hdr.setType(OpCode.error);\n                            request.txn = new ErrorTxn(e.code().intValue());\n                            LOG.info(\"Got user-level KeeperException when processing \"\n                            \t\t+ request.toString() + \" aborting remaining multi ops.\"\n                            \t\t+ \" Error Path:\" + e.getPath()\n                            \t\t+ \" Error:\" + e.getMessage());\n\n                            request.setException(e);\n\n                            /* Rollback change records from failed multi-op */\n                            rollbackPendingChanges(zxid, pendingChanges);\n                        }\n                    }\n\n                    //FIXME: I don't want to have to serialize it here and then\n                    //       immediately deserialize in next processor. But I'm \n                    //       not sure how else to get the txn stored into our list.\n                    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                    BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                    request.txn.serialize(boa, \"request\") ;\n                    ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n\n                    txns.add(new Txn(request.hdr.getType(), bb.array()));\n                    index++;\n                }\n\n                request.hdr = new TxnHeader(request.sessionId, request.cxid, zxid,\n                        Time.currentWallTime(), request.type);\n                request.txn = new MultiTxn(txns);\n                \n                break;\n\n            //create/close session don't require request record\n            case OpCode.createSession:\n            case OpCode.closeSession:\n                pRequest2Txn(request.type, zks.getNextZxid(), request, null, true);\n                break;\n \n            //All the rest don't need to create a Txn - just verify session\n            case OpCode.sync:\n            case OpCode.exists:\n            case OpCode.getData:\n            case OpCode.getACL:\n            case OpCode.getChildren:\n            case OpCode.getChildren2:\n            case OpCode.ping:\n            case OpCode.setWatches:\n                zks.sessionTracker.checkSession(request.sessionId,\n                        request.getOwner());\n                break;\n            default:\n                LOG.warn(\"unknown type \" + request.type);\n                break;\n            }\n        } catch (KeeperException e) {\n            if (request.hdr != null) {\n                request.hdr.setType(OpCode.error);\n                request.txn = new ErrorTxn(e.code().intValue());\n            }\n            LOG.info(\"Got user-level KeeperException when processing \"\n                    + request.toString()\n                    + \" Error Path:\" + e.getPath()\n                    + \" Error:\" + e.getMessage());\n            request.setException(e);\n        } catch (Exception e) {\n            // log at error level as we are returning a marshalling\n            // error to the user\n            LOG.error(\"Failed to process \" + request, e);\n\n            StringBuilder sb = new StringBuilder();\n            ByteBuffer bb = request.request;\n            if(bb != null){\n                bb.rewind();\n                while (bb.hasRemaining()) {\n                    sb.append(Integer.toHexString(bb.get() & 0xff));\n                }\n            } else {\n                sb.append(\"request buffer is null\");\n            }\n\n            LOG.error(\"Dumping request buffer: 0x\" + sb.toString());\n            if (request.hdr != null) {\n                request.hdr.setType(OpCode.error);\n                request.txn = new ErrorTxn(Code.MARSHALLINGERROR.intValue());\n            }\n        }\n        request.zxid = zks.getZxid();\n        nextProcessor.processRequest(request);\n    }\n\n    private List<ACL> removeDuplicates(List<ACL> acl) {\n\n        ArrayList<ACL> retval = new ArrayList<ACL>();\n        Iterator<ACL> it = acl.iterator();\n        while (it.hasNext()) {\n            ACL a = it.next();\n            if (retval.contains(a) == false) {\n                retval.add(a);\n            }\n        }\n        return retval;\n    }\n\n\n    /**\n     * This method checks out the acl making sure it isn't null or empty,\n     * it has valid schemes and ids, and expanding any relative ids that\n     * depend on the requestor's authentication information.\n     *\n     * @param authInfo list of ACL IDs associated with the client connection\n     * @param acl list of ACLs being assigned to the node (create or setACL operation)\n     * @return\n     */\n    private boolean fixupACL(List<Id> authInfo, List<ACL> acl) {\n        if (skipACL) {\n            return true;\n        }\n        if (acl == null || acl.size() == 0) {\n            return false;\n        }\n\n        Iterator<ACL> it = acl.iterator();\n        LinkedList<ACL> toAdd = null;\n        while (it.hasNext()) {\n            ACL a = it.next();\n            Id id = a.getId();\n            if (id.getScheme().equals(\"world\") && id.getId().equals(\"anyone\")) {\n                // wide open\n            } else if (id.getScheme().equals(\"auth\")) {\n                // This is the \"auth\" id, so we have to expand it to the\n                // authenticated ids of the requestor\n                it.remove();\n                if (toAdd == null) {\n                    toAdd = new LinkedList<ACL>();\n                }\n                boolean authIdValid = false;\n                for (Id cid : authInfo) {\n                    AuthenticationProvider ap =\n                        ProviderRegistry.getProvider(cid.getScheme());\n                    if (ap == null) {\n                        LOG.error(\"Missing AuthenticationProvider for \"\n                                + cid.getScheme());\n                    } else if (ap.isAuthenticated()) {\n                        authIdValid = true;\n                        toAdd.add(new ACL(a.getPerms(), cid));\n                    }\n                }\n                if (!authIdValid) {\n                    return false;\n                }\n            } else {\n                AuthenticationProvider ap = ProviderRegistry.getProvider(id\n                        .getScheme());\n                if (ap == null) {\n                    return false;\n                }\n                if (!ap.isValid(id.getId())) {\n                    return false;\n                }\n            }\n        }\n        if (toAdd != null) {\n            for (ACL a : toAdd) {\n                acl.add(a);\n            }\n        }\n        return acl.size() > 0;\n    }\n\n    public void processRequest(Request request) {\n        // request.addRQRec(\">prep=\"+zks.outstandingChanges.size());\n        submittedRequests.add(request);\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        submittedRequests.clear();\n        submittedRequests.add(Request.requestOfDeath);\n        nextProcessor.shutdown();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/PurgeTxnLog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * this class is used to clean up the \n * snapshot and data log dir's. This is usually\n * run as a cronjob on the zookeeper server machine.\n * Invocation of this class will clean up the datalogdir\n * files and snapdir files keeping the last \"-n\" snapshot files\n * and the corresponding logs.\n */\n@InterfaceAudience.Public\npublic class PurgeTxnLog {\n    private static final Logger LOG = LoggerFactory.getLogger(PurgeTxnLog.class);\n\n    private static final String COUNT_ERR_MSG = \"count should be greater than or equal to 3\";\n\n    static void printUsage(){\n        System.out.println(\"Usage:\");\n        System.out.println(\"PurgeTxnLog dataLogDir [snapDir] -n count\");\n        System.out.println(\"\\tdataLogDir -- path to the txn log directory\");\n        System.out.println(\"\\tsnapDir -- path to the snapshot directory\");\n        System.out.println(\"\\tcount -- the number of old snaps/logs you want \" +\n            \"to keep, value should be greater than or equal to 3\");\n    }\n\n    private static final String PREFIX_SNAPSHOT = \"snapshot\";\n    private static final String PREFIX_LOG = \"log\";\n\n    /**\n     * Purges the snapshot and logs keeping the last num snapshots and the\n     * corresponding logs. If logs are rolling or a new snapshot is created\n     * during this process, these newest N snapshots or any data logs will be\n     * excluded from current purging cycle.\n     *\n     * @param dataDir the dir that has the logs\n     * @param snapDir the dir that has the snapshots\n     * @param num the number of snapshots to keep\n     * @throws IOException\n     */\n    public static void purge(File dataDir, File snapDir, int num) throws IOException {\n        if (num < 3) {\n            throw new IllegalArgumentException(COUNT_ERR_MSG);\n        }\n\n        FileTxnSnapLog txnLog = new FileTxnSnapLog(dataDir, snapDir);\n\n        List<File> snaps = txnLog.findNRecentSnapshots(num);\n        int numSnaps = snaps.size();\n        if (numSnaps > 0) {\n            purgeOlderSnapshots(txnLog, snaps.get(numSnaps - 1));\n        }\n    }\n\n    // VisibleForTesting\n    static void purgeOlderSnapshots(FileTxnSnapLog txnLog, File snapShot) {\n        final long leastZxidToBeRetain = Util.getZxidFromName(\n                snapShot.getName(), PREFIX_SNAPSHOT);\n\n        /**\n         * We delete all files with a zxid in their name that is less than leastZxidToBeRetain.\n         * This rule applies to both snapshot files as well as log files, with the following\n         * exception for log files.\n         *\n         * A log file with zxid less than X may contain transactions with zxid larger than X.  More\n         * precisely, a log file named log.(X-a) may contain transactions newer than snapshot.X if\n         * there are no other log files with starting zxid in the interval (X-a, X].  Assuming the\n         * latter condition is true, log.(X-a) must be retained to ensure that snapshot.X is\n         * recoverable.  In fact, this log file may very well extend beyond snapshot.X to newer\n         * snapshot files if these newer snapshots were not accompanied by log rollover (possible in\n         * the learner state machine at the time of this writing).  We can make more precise\n         * determination of whether log.(leastZxidToBeRetain-a) for the smallest 'a' is actually\n         * needed or not (e.g. not needed if there's a log file named log.(leastZxidToBeRetain+1)),\n         * but the complexity quickly adds up with gains only in uncommon scenarios.  It's safe and\n         * simple to just preserve log.(leastZxidToBeRetain-a) for the smallest 'a' to ensure\n         * recoverability of all snapshots being retained.  We determine that log file here by\n         * calling txnLog.getSnapshotLogs().\n         */\n        final Set<File> retainedTxnLogs = new HashSet<File>();\n        retainedTxnLogs.addAll(Arrays.asList(txnLog.getSnapshotLogs(leastZxidToBeRetain)));\n\n        /**\n         * Finds all candidates for deletion, which are files with a zxid in their name that is less\n         * than leastZxidToBeRetain.  There's an exception to this rule, as noted above.\n         */\n        class MyFileFilter implements FileFilter{\n            private final String prefix;\n            MyFileFilter(String prefix){\n                this.prefix=prefix;\n            }\n            public boolean accept(File f){\n                if(!f.getName().startsWith(prefix + \".\"))\n                    return false;\n                if (retainedTxnLogs.contains(f)) {\n                    return false;\n                }\n                long fZxid = Util.getZxidFromName(f.getName(), prefix);\n                if (fZxid >= leastZxidToBeRetain) {\n                    return false;\n                }\n                return true;\n            }\n        }\n        // add all non-excluded log files\n        List<File> files = new ArrayList<File>();\n        File[] fileArray = txnLog.getDataDir().listFiles(new MyFileFilter(PREFIX_LOG));\n        if (fileArray != null) {\n            files.addAll(Arrays.asList(fileArray));\n        }\n\n        // add all non-excluded snapshot files to the deletion list\n        fileArray = txnLog.getSnapDir().listFiles(new MyFileFilter(PREFIX_SNAPSHOT));\n        if (fileArray != null) {\n            files.addAll(Arrays.asList(fileArray));\n        }\n\n        // remove the old files\n        for(File f: files)\n        {\n            final String msg = \"Removing file: \"+\n                DateFormat.getDateTimeInstance().format(f.lastModified())+\n                \"\\t\"+f.getPath();\n            LOG.info(msg);\n            System.out.println(msg);\n            if(!f.delete()){\n                System.err.println(\"Failed to remove \"+f.getPath());\n            }\n        }\n\n    }\n    \n    /**\n     * @param args dataLogDir [snapDir] -n count\n     * dataLogDir -- path to the txn log directory\n     * snapDir -- path to the snapshot directory\n     * count -- the number of old snaps/logs you want to keep, value should be greater than or equal to 3<br>\n     */\n    public static void main(String[] args) throws IOException {\n        if (args.length < 3 || args.length > 4) {\n            printUsageThenExit();\n        }\n        File dataDir = validateAndGetFile(args[0]);\n        File snapDir = dataDir;\n        int num = -1;\n        String countOption = \"\";\n        if (args.length == 3) {\n            countOption = args[1];\n            num = validateAndGetCount(args[2]);\n        } else {\n            snapDir = validateAndGetFile(args[1]);\n            countOption = args[2];\n            num = validateAndGetCount(args[3]);\n        }\n        if (!\"-n\".equals(countOption)) {\n            printUsageThenExit();\n        }\n        purge(dataDir, snapDir, num);\n    }\n\n    /**\n     * validates file existence and returns the file\n     *\n     * @param path\n     * @return File\n     */\n    private static File validateAndGetFile(String path) {\n        File file = new File(path);\n        if (!file.exists()) {\n            System.err.println(\"Path '\" + file.getAbsolutePath()\n                    + \"' does not exist. \");\n            printUsageThenExit();\n        }\n        return file;\n    }\n\n    /**\n     * Returns integer if parsed successfully and it is valid otherwise prints\n     * error and usage and then exits\n     *\n     * @param number\n     * @return count\n     */\n    private static int validateAndGetCount(String number) {\n        int result = 0;\n        try {\n            result = Integer.parseInt(number);\n            if (result < 3) {\n                System.err.println(COUNT_ERR_MSG);\n                printUsageThenExit();\n            }\n        } catch (NumberFormatException e) {\n            System.err\n                    .println(\"'\" + number + \"' can not be parsed to integer.\");\n            printUsageThenExit();\n        }\n        return result;\n    }\n\n    private static void printUsageThenExit() {\n        printUsage();\n        System.exit(1);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ReferenceCountedACLCache.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.jute.Index;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.data.ACL;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class ReferenceCountedACLCache {\n    private static final Logger LOG = LoggerFactory.getLogger(ReferenceCountedACLCache.class);\n\n    final Map<Long, List<ACL>> longKeyMap =\n            new HashMap<Long, List<ACL>>();\n\n    final Map<List<ACL>, Long> aclKeyMap =\n            new HashMap<List<ACL>, Long>();\n\n    final Map<Long, AtomicLongWithEquals> referenceCounter =\n            new HashMap<Long, AtomicLongWithEquals>();\n    private static final long OPEN_UNSAFE_ACL_ID = -1L;\n\n    /**\n     * these are the number of acls that we have in the datatree\n     */\n    long aclIndex = 0;\n\n    /**\n     * converts the list of acls to a long.\n     * Increments the reference counter for this ACL.\n     * @param acls\n     * @return a long that map to the acls\n     */\n    public synchronized Long convertAcls(List<ACL> acls) {\n        if (acls == null)\n            return OPEN_UNSAFE_ACL_ID;\n\n        // get the value from the map\n        Long ret = aclKeyMap.get(acls);\n        if (ret == null) {\n            ret = incrementIndex();\n            longKeyMap.put(ret, acls);\n            aclKeyMap.put(acls, ret);\n        }\n\n        addUsage(ret);\n\n        return ret;\n    }\n\n    /**\n     * converts a long to a list of acls.\n     *\n     * @param longVal\n     * @return a list of ACLs that map to the long\n     */\n    public synchronized List<ACL> convertLong(Long longVal) {\n        if (longVal == null)\n            return null;\n        if (longVal == OPEN_UNSAFE_ACL_ID)\n            return ZooDefs.Ids.OPEN_ACL_UNSAFE;\n        List<ACL> acls = longKeyMap.get(longVal);\n        if (acls == null) {\n            LOG.error(\"ERROR: ACL not available for long \" + longVal);\n            throw new RuntimeException(\"Failed to fetch acls for \" + longVal);\n        }\n        return acls;\n    }\n\n    private long incrementIndex() {\n        return ++aclIndex;\n    }\n\n    public synchronized void deserialize(InputArchive ia) throws IOException {\n        clear();\n        int i = ia.readInt(\"map\");\n        while (i > 0) {\n            Long val = ia.readLong(\"long\");\n            if (aclIndex < val) {\n                aclIndex = val;\n            }\n            List<ACL> aclList = new ArrayList<ACL>();\n            Index j = ia.startVector(\"acls\");\n            while (!j.done()) {\n                ACL acl = new ACL();\n                acl.deserialize(ia, \"acl\");\n                aclList.add(acl);\n                j.incr();\n            }\n            longKeyMap.put(val, aclList);\n            aclKeyMap.put(aclList, val);\n            referenceCounter.put(val, new AtomicLongWithEquals(0));\n            i--;\n        }\n    }\n\n    public synchronized void serialize(OutputArchive oa) throws IOException {\n        oa.writeInt(longKeyMap.size(), \"map\");\n        Set<Map.Entry<Long, List<ACL>>> set = longKeyMap.entrySet();\n        for (Map.Entry<Long, List<ACL>> val : set) {\n            oa.writeLong(val.getKey(), \"long\");\n            List<ACL> aclList = val.getValue();\n            oa.startVector(aclList, \"acls\");\n            for (ACL acl : aclList) {\n                acl.serialize(oa, \"acl\");\n            }\n            oa.endVector(aclList, \"acls\");\n        }\n    }\n\n    public int size() {\n        return aclKeyMap.size();\n    }\n\n    private void clear() {\n        aclKeyMap.clear();\n        longKeyMap.clear();\n        referenceCounter.clear();\n    }\n\n    public synchronized void addUsage(Long acl) {\n        if (acl == OPEN_UNSAFE_ACL_ID) {\n            return;\n        }\n\n        if (!longKeyMap.containsKey(acl)) {\n            LOG.info(\"Ignoring acl \" + acl + \" as it does not exist in the cache\");\n            return;\n        }\n\n        AtomicLong count = referenceCounter.get(acl);\n        if (count == null) {\n            referenceCounter.put(acl, new AtomicLongWithEquals(1));\n        } else {\n            count.incrementAndGet();\n        }\n    }\n\n    public synchronized void removeUsage(Long acl) {\n        if (acl == OPEN_UNSAFE_ACL_ID) {\n            return;\n        }\n\n        if (!longKeyMap.containsKey(acl)) {\n            LOG.info(\"Ignoring acl \" + acl + \" as it does not exist in the cache\");\n            return;\n        }\n\n        long newCount = referenceCounter.get(acl).decrementAndGet();\n        if (newCount <= 0) {\n            referenceCounter.remove(acl);\n            aclKeyMap.remove(longKeyMap.get(acl));\n            longKeyMap.remove(acl);\n        }\n    }\n\n    public synchronized void purgeUnused() {\n        Iterator<Map.Entry<Long, AtomicLongWithEquals>> refCountIter = referenceCounter.entrySet().iterator();\n        while (refCountIter.hasNext()) {\n            Map.Entry<Long, AtomicLongWithEquals> entry = refCountIter.next();\n            if (entry.getValue().get() <= 0) {\n                Long acl = entry.getKey();\n                aclKeyMap.remove(longKeyMap.get(acl));\n                longKeyMap.remove(acl);\n                refCountIter.remove();\n            }\n        }\n    }\n\n    private static class AtomicLongWithEquals extends AtomicLong {\n\n        private static final long serialVersionUID = 3355155896813725462L;\n\n        public AtomicLongWithEquals(long i) {\n            super(i);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            return equals((AtomicLongWithEquals) o);\n        }\n\n        public boolean equals(AtomicLongWithEquals that) {\n            return get() == that.get();\n        }\n\n        @Override\n        public int hashCode() {\n            return 31 * Long.valueOf(get()).hashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/Request.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.nio.ByteBuffer;\nimport java.util.List;\n\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This is the structure that represents a request moving through a chain of\n * RequestProcessors. There are various pieces of information that is tacked\n * onto the request as it is processed.\n */\npublic class Request {\n    private static final Logger LOG = LoggerFactory.getLogger(Request.class);\n\n    public final static Request requestOfDeath = new Request(null, 0, 0, 0,\n            null, null);\n\n    /**\n     * @param cnxn\n     * @param sessionId\n     * @param xid\n     * @param type\n     * @param bb\n     */\n    public Request(ServerCnxn cnxn, long sessionId, int xid, int type,\n            ByteBuffer bb, List<Id> authInfo) {\n        this.cnxn = cnxn;\n        this.sessionId = sessionId;\n        this.cxid = xid;\n        this.type = type;\n        this.request = bb;\n        this.authInfo = authInfo;\n    }\n\n    public final long sessionId;\n\n    public final int cxid;\n\n    public final int type;\n\n    public final ByteBuffer request;\n\n    public final ServerCnxn cnxn;\n\n    public TxnHeader hdr;\n\n    public Record txn;\n\n    public long zxid = -1;\n\n    public final List<Id> authInfo;\n\n    public final long createTime = Time.currentElapsedTime();\n    \n    private Object owner;\n    \n    private KeeperException e;\n\n    public Object getOwner() {\n        return owner;\n    }\n    \n    public void setOwner(Object owner) {\n        this.owner = owner;\n    }\n\n    /**\n     * is the packet type a valid packet in zookeeper\n     * \n     * @param type\n     *                the type of the packet\n     * @return true if a valid packet, false if not\n     */\n    static boolean isValid(int type) {\n        // make sure this is always synchronized with Zoodefs!!\n        switch (type) {\n        case OpCode.notification:\n            return false;\n        case OpCode.create:\n        case OpCode.delete:\n        case OpCode.createSession:\n        case OpCode.exists:\n        case OpCode.getData:\n        case OpCode.check:\n        case OpCode.multi:\n        case OpCode.setData:\n        case OpCode.sync:\n        case OpCode.getACL:\n        case OpCode.setACL:\n        case OpCode.getChildren:\n        case OpCode.getChildren2:\n        case OpCode.ping:\n        case OpCode.closeSession:\n        case OpCode.setWatches:\n            return true;\n        default:\n            return false;\n        }\n    }\n\n    static boolean isQuorum(int type) {\n        switch (type) {\n        case OpCode.exists:\n        case OpCode.getACL:\n        case OpCode.getChildren:\n        case OpCode.getChildren2:\n        case OpCode.getData:\n            return false;\n        case OpCode.error:\n        case OpCode.closeSession:\n        case OpCode.create:\n        case OpCode.createSession:\n        case OpCode.delete:\n        case OpCode.setACL:\n        case OpCode.setData:\n        case OpCode.check:\n        case OpCode.multi:\n            return true;\n        default:\n            return false;\n        }\n    }\n    \n    static String op2String(int op) {\n        switch (op) {\n        case OpCode.notification:\n            return \"notification\";\n        case OpCode.create:\n            return \"create\";\n        case OpCode.setWatches:\n            return \"setWatches\";\n        case OpCode.delete:\n            return \"delete\";\n        case OpCode.exists:\n            return \"exists\";\n        case OpCode.getData:\n            return \"getData\";\n        case OpCode.check:\n            return \"check\";\n        case OpCode.multi:\n            return \"multi\";\n        case OpCode.setData:\n            return \"setData\";\n        case OpCode.sync:\n              return \"sync:\";\n        case OpCode.getACL:\n            return \"getACL\";\n        case OpCode.setACL:\n            return \"setACL\";\n        case OpCode.getChildren:\n            return \"getChildren\";\n        case OpCode.getChildren2:\n            return \"getChildren2\";\n        case OpCode.ping:\n            return \"ping\";\n        case OpCode.createSession:\n            return \"createSession\";\n        case OpCode.closeSession:\n            return \"closeSession\";\n        case OpCode.error:\n            return \"error\";\n        default:\n            return \"unknown \" + op;\n        }\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"sessionid:0x\").append(Long.toHexString(sessionId))\n            .append(\" type:\").append(op2String(type))\n            .append(\" cxid:0x\").append(Long.toHexString(cxid))\n            .append(\" zxid:0x\").append(Long.toHexString(hdr == null ?\n                    -2 : hdr.getZxid()))\n            .append(\" txntype:\").append(hdr == null ?\n                    \"unknown\" : \"\" + hdr.getType());\n\n        // best effort to print the path assoc with this request\n        String path = \"n/a\";\n        if (type != OpCode.createSession\n                && type != OpCode.setWatches\n                && type != OpCode.closeSession\n                && request != null\n                && request.remaining() >= 4)\n        {\n            try {\n                // make sure we don't mess with request itself\n                ByteBuffer rbuf = request.asReadOnlyBuffer();\n                rbuf.clear();\n                int pathLen = rbuf.getInt();\n                // sanity check\n                if (pathLen >= 0\n                        && pathLen < 4096\n                        && rbuf.remaining() >= pathLen)\n                {\n                    byte b[] = new byte[pathLen];\n                    rbuf.get(b);\n                    path = new String(b);\n                }\n            } catch (Exception e) {\n                // ignore - can't find the path, will output \"n/a\" instead\n            }\n        }\n        sb.append(\" reqpath:\").append(path);\n\n        return sb.toString();\n    }\n\n    public void setException(KeeperException e) {\n        this.e = e;\n    }\n\t\n    public KeeperException getException() {\n        return e;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/RequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\n/**\n * RequestProcessors are chained together to process transactions. Requests are\n * always processed in order. The standalone server, follower, and leader all\n * have slightly different RequestProcessors chained together.\n * \n * Requests always move forward through the chain of RequestProcessors. Requests\n * are passed to a RequestProcessor through processRequest(). Generally method\n * will always be invoked by a single thread.\n * \n * When shutdown is called, the request RequestProcessor should also shutdown\n * any RequestProcessors that it is connected to.\n */\npublic interface RequestProcessor {\n    @SuppressWarnings(\"serial\")\n    public static class RequestProcessorException extends Exception {\n        public RequestProcessorException(String msg, Throwable t) {\n            super(msg, t);\n        }\n    }\n\n    void processRequest(Request request) throws RequestProcessorException;\n\n    void shutdown();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ServerCnxn.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.HashMap;\nimport java.util.Set;\nimport java.util.HashSet;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\n\n/**\n * Interface to a Server connection - represents a connection from a client\n * to the server.\n */\npublic abstract class ServerCnxn implements Stats, Watcher {\n    // This is just an arbitrary object to represent requests issued by\n    // (aka owned by) this class\n    final public static Object me = new Object();\n    \n    protected ArrayList<Id> authInfo = new ArrayList<Id>();\n\n    /**\n     * If the client is of old version, we don't send r-o mode info to it.\n     * The reason is that if we would, old C client doesn't read it, which\n     * results in TCP RST packet, i.e. \"connection reset by peer\".\n     */\n    boolean isOldClient = true;\n\n    abstract int getSessionTimeout();\n\n    abstract void close();\n\n    public abstract void sendResponse(ReplyHeader h, Record r, String tag)\n        throws IOException;\n\n    /* notify the client the session is closing and close/cleanup socket */\n    abstract void sendCloseSession();\n\n    public abstract void process(WatchedEvent event);\n\n    abstract long getSessionId();\n\n    abstract void setSessionId(long sessionId);\n\n    /** auth info for the cnxn, returns an unmodifyable list */\n    public List<Id> getAuthInfo() {\n        return Collections.unmodifiableList(authInfo);\n    }\n\n    public void addAuthInfo(Id id) {\n        if (authInfo.contains(id) == false) {\n            authInfo.add(id);\n        }\n    }\n\n    public boolean removeAuthInfo(Id id) {\n        return authInfo.remove(id);\n    }\n\n    abstract void sendBuffer(ByteBuffer closeConn);\n\n    abstract void enableRecv();\n\n    abstract void disableRecv();\n\n    abstract void setSessionTimeout(int sessionTimeout);\n\n    /**\n     * Wrapper method to return the socket address\n     */\n    public abstract InetAddress getSocketAddress();\n\n    protected ZooKeeperSaslServer zooKeeperSaslServer = null;\n\n    protected static class CloseRequestException extends IOException {\n        private static final long serialVersionUID = -7854505709816442681L;\n\n        public CloseRequestException(String msg) {\n            super(msg);\n        }\n    }\n\n    protected static class EndOfStreamException extends IOException {\n        private static final long serialVersionUID = -8255690282104294178L;\n\n        public EndOfStreamException(String msg) {\n            super(msg);\n        }\n\n        public String toString() {\n            return \"EndOfStreamException: \" + getMessage();\n        }\n    }\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int confCmd =\n        ByteBuffer.wrap(\"conf\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int consCmd =\n        ByteBuffer.wrap(\"cons\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int crstCmd =\n        ByteBuffer.wrap(\"crst\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int dumpCmd =\n        ByteBuffer.wrap(\"dump\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int enviCmd =\n        ByteBuffer.wrap(\"envi\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int getTraceMaskCmd =\n        ByteBuffer.wrap(\"gtmk\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int ruokCmd =\n        ByteBuffer.wrap(\"ruok\".getBytes()).getInt();\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int setTraceMaskCmd =\n        ByteBuffer.wrap(\"stmk\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int srvrCmd =\n        ByteBuffer.wrap(\"srvr\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int srstCmd =\n        ByteBuffer.wrap(\"srst\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int statCmd =\n        ByteBuffer.wrap(\"stat\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int wchcCmd =\n        ByteBuffer.wrap(\"wchc\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int wchpCmd =\n        ByteBuffer.wrap(\"wchp\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int wchsCmd =\n        ByteBuffer.wrap(\"wchs\".getBytes()).getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int mntrCmd = ByteBuffer.wrap(\"mntr\".getBytes())\n            .getInt();\n\n    /*\n     * See <a href=\"{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands\">\n     * Zk Admin</a>. this link is for all the commands.\n     */\n    protected final static int isroCmd = ByteBuffer.wrap(\"isro\".getBytes())\n            .getInt();\n\n    final static Map<Integer, String> cmd2String = new HashMap<Integer, String>();\n\n    private static final String ZOOKEEPER_4LW_COMMANDS_WHITELIST = \"zookeeper.4lw.commands.whitelist\";\n\n    private static final Logger LOG = LoggerFactory.getLogger(ServerCnxn.class);\n\n    private static final Set<String> whiteListedCommands = new HashSet<String>();\n\n    private static boolean whiteListInitialized = false;\n\n    // @VisibleForTesting\n    public synchronized static void resetWhiteList() {\n        whiteListInitialized = false;\n        whiteListedCommands.clear();\n    }\n\n    /**\n     * Return the string representation of the specified command code.\n     */\n    public static String getCommandString(int command) {\n        return cmd2String.get(command);\n    }\n\n    /**\n     * Check if the specified command code is from a known command.\n     *\n     * @param command The integer code of command.\n     * @return true if the specified command is known, false otherwise.\n     */\n    public static boolean isKnown(int command) {\n        return cmd2String.containsKey(command);\n    }\n\n    /**\n     * Check if the specified command is enabled.\n     *\n     * In ZOOKEEPER-2693 we introduce a configuration option to only\n     * allow a specific set of white listed commands to execute.\n     * A command will only be executed if it is also configured\n     * in the white list.\n     *\n     * @param command The command string.\n     * @return true if the specified command is enabled.\n     */\n    public synchronized static boolean isEnabled(String command) {\n        if (whiteListInitialized) {\n            return whiteListedCommands.contains(command);\n        }\n\n        String commands = System.getProperty(ZOOKEEPER_4LW_COMMANDS_WHITELIST);\n        if (commands != null) {\n            String[] list = commands.split(\",\");\n            for (String cmd : list) {\n                if (cmd.trim().equals(\"*\")) {\n                    for (Map.Entry<Integer, String> entry : cmd2String.entrySet()) {\n                        whiteListedCommands.add(entry.getValue());\n                    }\n                    break;\n                }\n                if (!cmd.trim().isEmpty()) {\n                    whiteListedCommands.add(cmd.trim());\n                }\n            }\n        } else {\n            for (Map.Entry<Integer, String> entry : cmd2String.entrySet()) {\n                String cmd = entry.getValue();\n                if (cmd.equals(\"wchc\") || cmd.equals(\"wchp\")) {\n                    // ZOOKEEPER-2693 / disable these exploitable commands by default.\n                    continue;\n                }\n                whiteListedCommands.add(cmd);\n            }\n        }\n\n        // Readonly mode depends on \"isro\".\n        if (System.getProperty(\"readonlymode.enabled\", \"false\").equals(\"true\")) {\n            whiteListedCommands.add(\"isro\");\n        }\n        // zkServer.sh depends on \"srvr\".\n        whiteListedCommands.add(\"srvr\");\n        whiteListInitialized = true;\n        LOG.info(\"The list of known four letter word commands is : {}\", Collections.singletonList(cmd2String));\n        LOG.info(\"The list of enabled four letter word commands is : {}\", Collections.singletonList(whiteListedCommands));\n        return whiteListedCommands.contains(command);\n    }\n\n    // specify all of the commands that are available\n    static {\n        cmd2String.put(confCmd, \"conf\");\n        cmd2String.put(consCmd, \"cons\");\n        cmd2String.put(crstCmd, \"crst\");\n        cmd2String.put(dumpCmd, \"dump\");\n        cmd2String.put(enviCmd, \"envi\");\n        cmd2String.put(getTraceMaskCmd, \"gtmk\");\n        cmd2String.put(ruokCmd, \"ruok\");\n        cmd2String.put(setTraceMaskCmd, \"stmk\");\n        cmd2String.put(srstCmd, \"srst\");\n        cmd2String.put(srvrCmd, \"srvr\");\n        cmd2String.put(statCmd, \"stat\");\n        cmd2String.put(wchcCmd, \"wchc\");\n        cmd2String.put(wchpCmd, \"wchp\");\n        cmd2String.put(wchsCmd, \"wchs\");\n        cmd2String.put(mntrCmd, \"mntr\");\n        cmd2String.put(isroCmd, \"isro\");\n    }\n\n    protected void packetReceived() {\n        incrPacketsReceived();\n        ServerStats serverStats = serverStats();\n        if (serverStats != null) {\n            serverStats().incrementPacketsReceived();\n        }\n    }\n\n    protected void packetSent() {\n        incrPacketsSent();\n        ServerStats serverStats = serverStats();\n        if (serverStats != null) {\n            serverStats().incrementPacketsSent();\n        }\n    }\n\n    protected abstract ServerStats serverStats();\n    \n    protected final Date established = new Date();\n\n    protected final AtomicLong packetsReceived = new AtomicLong();\n    protected final AtomicLong packetsSent = new AtomicLong();\n\n    protected long minLatency;\n    protected long maxLatency;\n    protected String lastOp;\n    protected long lastCxid;\n    protected long lastZxid;\n    protected long lastResponseTime;\n    protected long lastLatency;\n\n    protected long count;\n    protected long totalLatency;\n\n    public synchronized void resetStats() {\n        packetsReceived.set(0);\n        packetsSent.set(0);\n        minLatency = Long.MAX_VALUE;\n        maxLatency = 0;\n        lastOp = \"NA\";\n        lastCxid = -1;\n        lastZxid = -1;\n        lastResponseTime = 0;\n        lastLatency = 0;\n\n        count = 0;\n        totalLatency = 0;\n    }\n\n    protected long incrPacketsReceived() {\n        return packetsReceived.incrementAndGet();\n    }\n    \n    protected void incrOutstandingRequests(RequestHeader h) {\n    }\n\n    protected long incrPacketsSent() {\n        return packetsSent.incrementAndGet();\n    }\n\n    protected synchronized void updateStatsForResponse(long cxid, long zxid,\n            String op, long start, long end)\n    {\n        // don't overwrite with \"special\" xids - we're interested\n        // in the clients last real operation\n        if (cxid >= 0) {\n            lastCxid = cxid;\n        }\n        lastZxid = zxid;\n        lastOp = op;\n        lastResponseTime = end;\n        long elapsed = end - start;\n        lastLatency = elapsed;\n        if (elapsed < minLatency) {\n            minLatency = elapsed;\n        }\n        if (elapsed > maxLatency) {\n            maxLatency = elapsed;\n        }\n        count++;\n        totalLatency += elapsed;\n    }\n\n    public Date getEstablished() {\n        return (Date)established.clone();\n    }\n\n    public abstract long getOutstandingRequests();\n\n    public long getPacketsReceived() {\n        return packetsReceived.longValue();\n    }\n\n    public long getPacketsSent() {\n        return packetsSent.longValue();\n    }\n\n    public synchronized long getMinLatency() {\n        return minLatency == Long.MAX_VALUE ? 0 : minLatency;\n    }\n\n    public synchronized long getAvgLatency() {\n        return count == 0 ? 0 : totalLatency / count;\n    }\n\n    public synchronized long getMaxLatency() {\n        return maxLatency;\n    }\n\n    public synchronized String getLastOperation() {\n        return lastOp;\n    }\n\n    public synchronized long getLastCxid() {\n        return lastCxid;\n    }\n\n    public synchronized long getLastZxid() {\n        return lastZxid;\n    }\n\n    public synchronized long getLastResponseTime() {\n        return lastResponseTime;\n    }\n\n    public synchronized long getLastLatency() {\n        return lastLatency;\n    }\n\n    /**\n     * Prints detailed stats information for the connection.\n     *\n     * @see dumpConnectionInfo(PrintWriter, boolean) for brief stats\n     */\n    @Override\n    public String toString() {\n        StringWriter sw = new StringWriter();\n        PrintWriter pwriter = new PrintWriter(sw);\n        dumpConnectionInfo(pwriter, false);\n        pwriter.flush();\n        pwriter.close();\n        return sw.toString();\n    }\n\n    public abstract InetSocketAddress getRemoteSocketAddress();\n    public abstract int getInterestOps();\n    \n    /**\n     * Print information about the connection.\n     * @param brief iff true prints brief details, otw full detail\n     * @return information about this connection\n     */\n    protected synchronized void\n    dumpConnectionInfo(PrintWriter pwriter, boolean brief) {\n        pwriter.print(\" \");\n        pwriter.print(getRemoteSocketAddress());\n        pwriter.print(\"[\");\n        int interestOps = getInterestOps();\n        pwriter.print(interestOps == 0 ? \"0\" : Integer.toHexString(interestOps));\n        pwriter.print(\"](queued=\");\n        pwriter.print(getOutstandingRequests());\n        pwriter.print(\",recved=\");\n        pwriter.print(getPacketsReceived());\n        pwriter.print(\",sent=\");\n        pwriter.print(getPacketsSent());\n\n        if (!brief) {\n            long sessionId = getSessionId();\n            if (sessionId != 0) {\n                pwriter.print(\",sid=0x\");\n                pwriter.print(Long.toHexString(sessionId));\n                pwriter.print(\",lop=\");\n                pwriter.print(getLastOperation());\n                pwriter.print(\",est=\");\n                pwriter.print(getEstablished().getTime());\n                pwriter.print(\",to=\");\n                pwriter.print(getSessionTimeout());\n                long lastCxid = getLastCxid();\n                if (lastCxid >= 0) {\n                    pwriter.print(\",lcxid=0x\");\n                    pwriter.print(Long.toHexString(lastCxid));\n                }\n                pwriter.print(\",lzxid=0x\");\n                pwriter.print(Long.toHexString(getLastZxid()));\n                pwriter.print(\",lresp=\");\n                pwriter.print(getLastResponseTime());\n                pwriter.print(\",llat=\");\n                pwriter.print(getLastLatency());\n                pwriter.print(\",minlat=\");\n                pwriter.print(getMinLatency());\n                pwriter.print(\",avglat=\");\n                pwriter.print(getAvgLatency());\n                pwriter.print(\",maxlat=\");\n                pwriter.print(getMaxLatency());\n            }\n        }\n        pwriter.print(\")\");\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ServerCnxnFactory.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginException;\nimport javax.security.auth.login.AppConfigurationEntry;\n\nimport javax.management.JMException;\n\nimport org.apache.zookeeper.Login;\nimport org.apache.zookeeper.Environment;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.auth.SaslServerCallbackHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class ServerCnxnFactory {\n\n    public static final String ZOOKEEPER_SERVER_CNXN_FACTORY = \"zookeeper.serverCnxnFactory\";\n\n    public interface PacketProcessor {\n        public void processPacket(ByteBuffer packet, ServerCnxn src);\n    }\n    \n    private static final Logger LOG = LoggerFactory.getLogger(ServerCnxnFactory.class);\n\n    // sessionMap is used to speed up closeSession()\n    protected final ConcurrentMap<Long, ServerCnxn> sessionMap =\n            new ConcurrentHashMap<Long, ServerCnxn>();\n\n    /**\n     * The buffer will cause the connection to be close when we do a send.\n     */\n    static final ByteBuffer closeConn = ByteBuffer.allocate(0);\n\n    public abstract int getLocalPort();\n    \n    public abstract Iterable<ServerCnxn> getConnections();\n\n    public int getNumAliveConnections() {\n        synchronized(cnxns) {\n            return cnxns.size();\n        }\n    }\n\n    ZooKeeperServer getZooKeeperServer() {\n        return zkServer;\n    }\n\n    public abstract void closeSession(long sessionId);\n\n    public abstract void configure(InetSocketAddress addr,\n                                   int maxClientCnxns) throws IOException;\n\n    protected SaslServerCallbackHandler saslServerCallbackHandler;\n    public Login login;\n\n    /** Maximum number of connections allowed from particular host (ip) */\n    public abstract int getMaxClientCnxnsPerHost();\n\n    /** Maximum number of connections allowed from particular host (ip) */\n    public abstract void setMaxClientCnxnsPerHost(int max);\n\n    public abstract void startup(ZooKeeperServer zkServer)\n        throws IOException, InterruptedException;\n\n    public abstract void join() throws InterruptedException;\n\n    public abstract void shutdown();\n\n    public abstract void start();\n\n    protected ZooKeeperServer zkServer;\n    final public void setZooKeeperServer(ZooKeeperServer zk) {\n        this.zkServer = zk;\n        if (zk != null) {\n            zk.setServerCnxnFactory(this);\n        }\n    }\n\n    public abstract void closeAll();\n    \n    static public ServerCnxnFactory createFactory() throws IOException {\n        String serverCnxnFactoryName =\n            System.getProperty(ZOOKEEPER_SERVER_CNXN_FACTORY);\n        if (serverCnxnFactoryName == null) {\n            serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();\n        }\n        try {\n            ServerCnxnFactory serverCnxnFactory = (ServerCnxnFactory) Class.forName(serverCnxnFactoryName)\n                    .getDeclaredConstructor().newInstance();\n            LOG.info(\"Using {} as server connection factory\", serverCnxnFactoryName);\n            return serverCnxnFactory;\n        } catch (Exception e) {\n            IOException ioe = new IOException(\"Couldn't instantiate \"\n                    + serverCnxnFactoryName);\n            ioe.initCause(e);\n            throw ioe;\n        }\n    }\n    \n    static public ServerCnxnFactory createFactory(int clientPort,\n            int maxClientCnxns) throws IOException\n    {\n        return createFactory(new InetSocketAddress(clientPort), maxClientCnxns);\n    }\n\n    static public ServerCnxnFactory createFactory(InetSocketAddress addr,\n            int maxClientCnxns) throws IOException\n    {\n        ServerCnxnFactory factory = createFactory();\n        factory.configure(addr, maxClientCnxns);\n        return factory;\n    }\n\n    public abstract InetSocketAddress getLocalAddress();\n\n    private final Map<ServerCnxn, ConnectionBean> connectionBeans\n        = new ConcurrentHashMap<ServerCnxn, ConnectionBean>();\n\n    protected final HashSet<ServerCnxn> cnxns = new HashSet<ServerCnxn>();\n    public void unregisterConnection(ServerCnxn serverCnxn) {\n        ConnectionBean jmxConnectionBean = connectionBeans.remove(serverCnxn);\n        if (jmxConnectionBean != null){\n            MBeanRegistry.getInstance().unregister(jmxConnectionBean);\n        }\n    }\n    \n    public void registerConnection(ServerCnxn serverCnxn) {\n        if (zkServer != null) {\n            ConnectionBean jmxConnectionBean = new ConnectionBean(serverCnxn, zkServer);\n            try {\n                MBeanRegistry.getInstance().register(jmxConnectionBean, zkServer.jmxServerBean);\n                connectionBeans.put(serverCnxn, jmxConnectionBean);\n            } catch (JMException e) {\n                LOG.warn(\"Could not register connection\", e);\n            }\n        }\n\n    }\n\n    public void addSession(long sessionId, ServerCnxn cnxn) {\n        sessionMap.put(sessionId, cnxn);\n    }\n\n    /**\n     * Initialize the server SASL if specified.\n     *\n     * If the user has specified a \"ZooKeeperServer.LOGIN_CONTEXT_NAME_KEY\"\n     * or a jaas.conf using \"java.security.auth.login.config\"\n     * the authentication is required and an exception is raised.\n     * Otherwise no authentication is configured and no exception is raised.\n     *\n     * @throws IOException if jaas.conf is missing or there's an error in it.\n     */\n    protected void configureSaslLogin() throws IOException {\n        String serverSection = System.getProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY,\n                                                  ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME);\n\n        // Note that 'Configuration' here refers to javax.security.auth.login.Configuration.\n        AppConfigurationEntry entries[] = null;\n        SecurityException securityException = null;\n        try {\n            entries = Configuration.getConfiguration().getAppConfigurationEntry(serverSection);\n        } catch (SecurityException e) {\n            // handle below: might be harmless if the user doesn't intend to use JAAS authentication.\n            securityException = e;\n        }\n\n        // No entries in jaas.conf\n        // If there's a configuration exception fetching the jaas section and\n        // the user has required sasl by specifying a LOGIN_CONTEXT_NAME_KEY or a jaas file\n        // we throw an exception otherwise we continue without authentication.\n        if (entries == null) {\n            String jaasFile = System.getProperty(Environment.JAAS_CONF_KEY);\n            String loginContextName = System.getProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY);\n            if (securityException != null && (loginContextName != null || jaasFile != null)) {\n                String errorMessage = \"No JAAS configuration section named '\" + serverSection +  \"' was found\";\n                if (jaasFile != null) {\n                    errorMessage += \"in '\" + jaasFile + \"'.\";\n                }\n                if (loginContextName != null) {\n                    errorMessage += \" But \" + ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY + \" was set.\";\n                }\n                LOG.error(errorMessage);\n                throw new IOException(errorMessage);\n            }\n            return;\n        }\n\n        // jaas.conf entry available\n        try {\n            saslServerCallbackHandler = new SaslServerCallbackHandler(Configuration.getConfiguration());\n            login = new Login(serverSection, saslServerCallbackHandler);\n            login.startThreadIfNeeded();\n        } catch (LoginException e) {\n            throw new IOException(\"Could not configure server because SASL configuration did not allow the \"\n              + \" ZooKeeper server to authenticate itself properly: \" + e);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ServerConfig.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;\n\n/**\n * Server configuration storage.\n *\n * We use this instead of Properties as it's typed.\n *\n */\n@InterfaceAudience.Public\npublic class ServerConfig {\n    ////\n    //// If you update the configuration parameters be sure\n    //// to update the \"conf\" 4letter word\n    ////\n    protected InetSocketAddress clientPortAddress;\n    protected String dataDir;\n    protected String dataLogDir;\n    protected int tickTime = ZooKeeperServer.DEFAULT_TICK_TIME;\n    protected int maxClientCnxns;\n    /** defaults to -1 if not set explicitly */\n    protected int minSessionTimeout = -1;\n    /** defaults to -1 if not set explicitly */\n    protected int maxSessionTimeout = -1;\n\n    /**\n     * Parse arguments for server configuration\n     * @param args clientPort dataDir and optional tickTime and maxClientCnxns\n     * @return ServerConfig configured wrt arguments\n     * @throws IllegalArgumentException on invalid usage\n     */\n    public void parse(String[] args) {\n        if (args.length < 2 || args.length > 4) {\n            throw new IllegalArgumentException(\"Invalid number of arguments:\" + Arrays.toString(args));\n        }\n\n        clientPortAddress = new InetSocketAddress(Integer.parseInt(args[0]));\n        dataDir = args[1];\n        dataLogDir = dataDir;\n        if (args.length >= 3) {\n            tickTime = Integer.parseInt(args[2]);\n        }\n        if (args.length == 4) {\n            maxClientCnxns = Integer.parseInt(args[3]);\n        }\n    }\n\n    /**\n     * Parse a ZooKeeper configuration file\n     * @param path the patch of the configuration file\n     * @return ServerConfig configured wrt arguments\n     * @throws ConfigException error processing configuration\n     */\n    public void parse(String path) throws ConfigException {\n        QuorumPeerConfig config = new QuorumPeerConfig();\n        config.parse(path);\n\n        // let qpconfig parse the file and then pull the stuff we are\n        // interested in\n        readFrom(config);\n    }\n\n    /**\n     * Read attributes from a QuorumPeerConfig.\n     * @param config\n     */\n    public void readFrom(QuorumPeerConfig config) {\n      clientPortAddress = config.getClientPortAddress();\n      dataDir = config.getDataDir();\n      dataLogDir = config.getDataLogDir();\n      tickTime = config.getTickTime();\n      maxClientCnxns = config.getMaxClientCnxns();\n      minSessionTimeout = config.getMinSessionTimeout();\n      maxSessionTimeout = config.getMaxSessionTimeout();\n    }\n\n    public InetSocketAddress getClientPortAddress() {\n        return clientPortAddress;\n    }\n    public String getDataDir() { return dataDir; }\n    public String getDataLogDir() { return dataLogDir; }\n    public int getTickTime() { return tickTime; }\n    public int getMaxClientCnxns() { return maxClientCnxns; }\n    /** minimum session timeout in milliseconds, -1 if unset */\n    public int getMinSessionTimeout() { return minSessionTimeout; }\n    /** maximum session timeout in milliseconds, -1 if unset */\n    public int getMaxSessionTimeout() { return maxSessionTimeout; }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ServerStats.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\n\n\nimport org.apache.zookeeper.common.Time;\n\n/**\n * Basic Server Statistics\n */\npublic class ServerStats {\n    private long packetsSent;\n    private long packetsReceived;\n    private long maxLatency;\n    private long minLatency = Long.MAX_VALUE;\n    private long totalLatency = 0;\n    private long count = 0;\n\n    private final Provider provider;\n\n    public interface Provider {\n        public long getOutstandingRequests();\n        public long getLastProcessedZxid();\n        public String getState();\n        public int getNumAliveConnections();\n    }\n    \n    public ServerStats(Provider provider) {\n        this.provider = provider;\n    }\n    \n    // getters\n    synchronized public long getMinLatency() {\n        return minLatency == Long.MAX_VALUE ? 0 : minLatency;\n    }\n\n    synchronized public long getAvgLatency() {\n        if (count != 0) {\n            return totalLatency / count;\n        }\n        return 0;\n    }\n\n    synchronized public long getMaxLatency() {\n        return maxLatency;\n    }\n\n    public long getOutstandingRequests() {\n        return provider.getOutstandingRequests();\n    }\n    \n    public long getLastProcessedZxid(){\n        return provider.getLastProcessedZxid();\n    }\n    \n    synchronized public long getPacketsReceived() {\n        return packetsReceived;\n    }\n\n    synchronized public long getPacketsSent() {\n        return packetsSent;\n    }\n\n    public String getServerState() {\n        return provider.getState();\n    }\n    \n    /** The number of client connections alive to this server */\n    public int getNumAliveClientConnections() {\n    \treturn provider.getNumAliveConnections();\n    }\n\n    @Override\n    public String toString(){\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Latency min/avg/max: \" + getMinLatency() + \"/\"\n                + getAvgLatency() + \"/\" + getMaxLatency() + \"\\n\");\n        sb.append(\"Received: \" + getPacketsReceived() + \"\\n\");\n        sb.append(\"Sent: \" + getPacketsSent() + \"\\n\");\n        sb.append(\"Connections: \" + getNumAliveClientConnections() + \"\\n\");\n\n        if (provider != null) {\n            sb.append(\"Outstanding: \" + getOutstandingRequests() + \"\\n\");\n            sb.append(\"Zxid: 0x\"+ Long.toHexString(getLastProcessedZxid())+ \"\\n\");\n        }\n        sb.append(\"Mode: \" + getServerState() + \"\\n\");\n        return sb.toString();\n    }\n    // mutators\n    synchronized void updateLatency(long requestCreateTime) {\n        long latency = Time.currentElapsedTime() - requestCreateTime;\n        totalLatency += latency;\n        count++;\n        if (latency < minLatency) {\n            minLatency = latency;\n        }\n        if (latency > maxLatency) {\n            maxLatency = latency;\n        }\n    }\n    synchronized public void resetLatency(){\n        totalLatency = 0;\n        count = 0;\n        maxLatency = 0;\n        minLatency = Long.MAX_VALUE;\n    }\n    synchronized public void resetMaxLatency(){\n        maxLatency = getMinLatency();\n    }\n    synchronized public void incrementPacketsReceived() {\n        packetsReceived++;\n    }\n    synchronized public void incrementPacketsSent() {\n        packetsSent++;\n    }\n    synchronized public void resetRequestCounters(){\n        packetsReceived = 0;\n        packetsSent = 0;\n    }\n    synchronized public void reset() {\n        resetLatency();\n        resetRequestCounters();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/SessionTracker.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.PrintWriter;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.KeeperException.SessionMovedException;\n\n/**\n * This is the basic interface that ZooKeeperServer uses to track sessions. The\n * standalone and leader ZooKeeperServer use the same SessionTracker. The\n * FollowerZooKeeperServer uses a SessionTracker which is basically a simple\n * shell to track information to be forwarded to the leader.\n */\npublic interface SessionTracker {\n    public static interface Session {\n        long getSessionId();\n        int getTimeout();\n        boolean isClosing();\n    }\n    public static interface SessionExpirer {\n        void expire(Session session);\n\n        long getServerId();\n    }\n\n    long createSession(int sessionTimeout);\n\n    void addSession(long id, int to);\n\n    /**\n     * @param sessionId\n     * @param sessionTimeout\n     * @return false if session is no longer active\n     */\n    boolean touchSession(long sessionId, int sessionTimeout);\n\n    /**\n     * Mark that the session is in the process of closing.\n     * @param sessionId\n     */\n    void setSessionClosing(long sessionId);\n\n    /**\n     * \n     */\n    void shutdown();\n\n    /**\n     * @param sessionId\n     */\n    void removeSession(long sessionId);\n\n    void checkSession(long sessionId, Object owner) throws KeeperException.SessionExpiredException, SessionMovedException;\n\n    void setOwner(long id, Object owner) throws SessionExpiredException;\n\n    /**\n     * Text dump of session information, suitable for debugging.\n     * @param pwriter the output writer\n     */\n    void dumpSessions(PrintWriter pwriter);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/SessionTrackerImpl.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map.Entry;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.common.Time;\n\n/**\n * This is a full featured SessionTracker. It tracks session in grouped by tick\n * interval. It always rounds up the tick interval to provide a sort of grace\n * period. Sessions are thus expired in batches made up of sessions that expire\n * in a given interval.\n */\npublic class SessionTrackerImpl extends ZooKeeperCriticalThread implements SessionTracker {\n    private static final Logger LOG = LoggerFactory.getLogger(SessionTrackerImpl.class);\n\n    HashMap<Long, SessionImpl> sessionsById = new HashMap<Long, SessionImpl>();\n\n    HashMap<Long, SessionSet> sessionSets = new HashMap<Long, SessionSet>();\n\n    ConcurrentHashMap<Long, Integer> sessionsWithTimeout;\n    long nextSessionId = 0;\n    long nextExpirationTime;\n\n    int expirationInterval;\n\n    public static class SessionImpl implements Session {\n        SessionImpl(long sessionId, int timeout, long expireTime) {\n            this.sessionId = sessionId;\n            this.timeout = timeout;\n            this.tickTime = expireTime;\n            isClosing = false;\n        }\n\n        final long sessionId;\n        final int timeout;\n        long tickTime;\n        boolean isClosing;\n\n        Object owner;\n\n        public long getSessionId() { return sessionId; }\n        public int getTimeout() { return timeout; }\n        public boolean isClosing() { return isClosing; }\n    }\n\n    public static long initializeNextSession(long id) {\n        long nextSid = 0;\n        nextSid = (Time.currentElapsedTime() << 24) >>> 8;\n        nextSid =  nextSid | (id <<56);\n        return nextSid;\n    }\n\n    static class SessionSet {\n        HashSet<SessionImpl> sessions = new HashSet<SessionImpl>();\n    }\n\n    SessionExpirer expirer;\n\n    private long roundToInterval(long time) {\n        // We give a one interval grace period\n        return (time / expirationInterval + 1) * expirationInterval;\n    }\n\n    public SessionTrackerImpl(SessionExpirer expirer,\n            ConcurrentHashMap<Long, Integer> sessionsWithTimeout, int tickTime,\n            long sid, ZooKeeperServerListener listener)\n    {\n        super(\"SessionTracker\", listener);\n        this.expirer = expirer;\n        this.expirationInterval = tickTime;\n        this.sessionsWithTimeout = sessionsWithTimeout;\n        nextExpirationTime = roundToInterval(Time.currentElapsedTime());\n        this.nextSessionId = initializeNextSession(sid);\n        for (Entry<Long, Integer> e : sessionsWithTimeout.entrySet()) {\n            addSession(e.getKey(), e.getValue());\n        }\n    }\n\n    volatile boolean running = true;\n\n    volatile long currentTime;\n\n    synchronized public void dumpSessions(PrintWriter pwriter) {\n        pwriter.print(\"Session Sets (\");\n        pwriter.print(sessionSets.size());\n        pwriter.println(\"):\");\n        ArrayList<Long> keys = new ArrayList<Long>(sessionSets.keySet());\n        Collections.sort(keys);\n        for (long time : keys) {\n            pwriter.print(sessionSets.get(time).sessions.size());\n            pwriter.print(\" expire at \");\n            pwriter.print(new Date(time));\n            pwriter.println(\":\");\n            for (SessionImpl s : sessionSets.get(time).sessions) {\n                pwriter.print(\"\\t0x\");\n                pwriter.println(Long.toHexString(s.sessionId));\n            }\n        }\n    }\n\n    @Override\n    synchronized public String toString() {\n        StringWriter sw = new StringWriter();\n        PrintWriter pwriter = new PrintWriter(sw);\n        dumpSessions(pwriter);\n        pwriter.flush();\n        pwriter.close();\n        return sw.toString();\n    }\n\n    @Override\n    synchronized public void run() {\n        try {\n            while (running) {\n                currentTime = Time.currentElapsedTime();\n                if (nextExpirationTime > currentTime) {\n                    this.wait(nextExpirationTime - currentTime);\n                    continue;\n                }\n                SessionSet set;\n                set = sessionSets.remove(nextExpirationTime);\n                if (set != null) {\n                    for (SessionImpl s : set.sessions) {\n                        setSessionClosing(s.sessionId);\n                        expirer.expire(s);\n                    }\n                }\n                nextExpirationTime += expirationInterval;\n            }\n        } catch (InterruptedException e) {\n            handleException(this.getName(), e);\n        }\n        LOG.info(\"SessionTrackerImpl exited loop!\");\n    }\n\n    synchronized public boolean touchSession(long sessionId, int timeout) {\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG,\n                                     ZooTrace.CLIENT_PING_TRACE_MASK,\n                                     \"SessionTrackerImpl --- Touch session: 0x\"\n                    + Long.toHexString(sessionId) + \" with timeout \" + timeout);\n        }\n        SessionImpl s = sessionsById.get(sessionId);\n        // Return false, if the session doesn't exists or marked as closing\n        if (s == null || s.isClosing()) {\n            return false;\n        }\n        long expireTime = roundToInterval(Time.currentElapsedTime() + timeout);\n        if (s.tickTime >= expireTime) {\n            // Nothing needs to be done\n            return true;\n        }\n        SessionSet set = sessionSets.get(s.tickTime);\n        if (set != null) {\n            set.sessions.remove(s);\n        }\n        s.tickTime = expireTime;\n        set = sessionSets.get(s.tickTime);\n        if (set == null) {\n            set = new SessionSet();\n            sessionSets.put(expireTime, set);\n        }\n        set.sessions.add(s);\n        return true;\n    }\n\n    synchronized public void setSessionClosing(long sessionId) {\n        if (LOG.isTraceEnabled()) {\n            LOG.info(\"Session closing: 0x\" + Long.toHexString(sessionId));\n        }\n        SessionImpl s = sessionsById.get(sessionId);\n        if (s == null) {\n            return;\n        }\n        s.isClosing = true;\n    }\n\n    synchronized public void removeSession(long sessionId) {\n        SessionImpl s = sessionsById.remove(sessionId);\n        sessionsWithTimeout.remove(sessionId);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                    \"SessionTrackerImpl --- Removing session 0x\"\n                    + Long.toHexString(sessionId));\n        }\n        if (s != null) {\n            SessionSet set = sessionSets.get(s.tickTime);\n            // Session expiration has been removing the sessions   \n            if(set != null){\n                set.sessions.remove(s);\n            }\n        }\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n\n        running = false;\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(),\n                                     \"Shutdown SessionTrackerImpl!\");\n        }\n    }\n\n\n    synchronized public long createSession(int sessionTimeout) {\n        addSession(nextSessionId, sessionTimeout);\n        return nextSessionId++;\n    }\n\n    synchronized public void addSession(long id, int sessionTimeout) {\n        sessionsWithTimeout.put(id, sessionTimeout);\n        if (sessionsById.get(id) == null) {\n            SessionImpl s = new SessionImpl(id, sessionTimeout, 0);\n            sessionsById.put(id, s);\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                        \"SessionTrackerImpl --- Adding session 0x\"\n                        + Long.toHexString(id) + \" \" + sessionTimeout);\n            }\n        } else {\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                        \"SessionTrackerImpl --- Existing session 0x\"\n                        + Long.toHexString(id) + \" \" + sessionTimeout);\n            }\n        }\n        touchSession(id, sessionTimeout);\n    }\n\n    synchronized public void checkSession(long sessionId, Object owner) throws KeeperException.SessionExpiredException, KeeperException.SessionMovedException {\n        SessionImpl session = sessionsById.get(sessionId);\n        if (session == null || session.isClosing()) {\n            throw new KeeperException.SessionExpiredException();\n        }\n        if (session.owner == null) {\n            session.owner = owner;\n        } else if (session.owner != owner) {\n            throw new KeeperException.SessionMovedException();\n        }\n    }\n\n    synchronized public void setOwner(long id, Object owner) throws SessionExpiredException {\n        SessionImpl session = sessionsById.get(id);\n        if (session == null || session.isClosing()) {\n            throw new KeeperException.SessionExpiredException();\n        }\n        session.owner = owner;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.zip.Adler32;\nimport java.util.zip.CheckedInputStream;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.apache.zookeeper.data.StatPersisted;\nimport org.apache.zookeeper.server.persistence.FileSnap;\n\n/**\n * Dump a snapshot file to stdout.\n */\n@InterfaceAudience.Public\npublic class SnapshotFormatter {\n\n    /**\n     * USAGE: SnapshotFormatter snapshot_file\n     */\n    public static void main(String[] args) throws Exception {\n        if (args.length != 1) {\n            System.err.println(\"USAGE: SnapshotFormatter snapshot_file\");\n            System.exit(2);\n        }\n\n        new SnapshotFormatter().run(args[0]);\n    }\n    \n    public void run(String snapshotFileName) throws IOException {\n        InputStream is = new CheckedInputStream(\n                new BufferedInputStream(new FileInputStream(snapshotFileName)),\n                new Adler32());\n        InputArchive ia = BinaryInputArchive.getArchive(is);\n        \n        FileSnap fileSnap = new FileSnap(null);\n\n        DataTree dataTree = new DataTree();\n        Map<Long, Integer> sessions = new HashMap<Long, Integer>();\n        \n        fileSnap.deserialize(dataTree, sessions, ia);\n\n        printDetails(dataTree, sessions);\n    }\n\n    private void printDetails(DataTree dataTree, Map<Long, Integer> sessions) {\n        printZnodeDetails(dataTree);\n        printSessionDetails(dataTree, sessions);\n    }\n\n    private void printZnodeDetails(DataTree dataTree) {\n        System.out.println(String.format(\"ZNode Details (count=%d):\",\n                dataTree.getNodeCount()));\n        \n        printZnode(dataTree, \"/\");\n        System.out.println(\"----\");\n    }\n\n    private void printZnode(DataTree dataTree, String name) {\n        System.out.println(\"----\");\n        DataNode n = dataTree.getNode(name);\n        Set<String> children;\n        synchronized(n) { // keep findbugs happy\n            System.out.println(name);\n            printStat(n.stat);\n            if (n.data != null) {\n                System.out.println(\"  dataLength = \" + n.data.length);\n            } else {\n                System.out.println(\"  no data\");\n            }\n            children = n.getChildren();\n        }\n        for (String child : children) {\n            printZnode(dataTree, name + (name.equals(\"/\") ? \"\" : \"/\") + child);\n        }\n    }\n\n    private void printSessionDetails(DataTree dataTree, Map<Long, Integer> sessions) {\n        System.out.println(\"Session Details (sid, timeout, ephemeralCount):\");\n        for (Map.Entry<Long, Integer> e : sessions.entrySet()) {\n            long sid = e.getKey();\n            System.out.println(String.format(\"%#016x, %d, %d\",\n                    sid, e.getValue(), dataTree.getEphemerals(sid).size()));\n        }\n    }\n\n    private void printStat(StatPersisted stat) {\n        printHex(\"cZxid\", stat.getCzxid());\n        System.out.println(\"  ctime = \" + new Date(stat.getCtime()).toString());\n        printHex(\"mZxid\", stat.getMzxid());\n        System.out.println(\"  mtime = \" + new Date(stat.getMtime()).toString());\n        printHex(\"pZxid\", stat.getPzxid());\n        System.out.println(\"  cversion = \" + stat.getCversion());\n        System.out.println(\"  dataVersion = \" + stat.getVersion());\n        System.out.println(\"  aclVersion = \" + stat.getAversion());\n        printHex(\"ephemeralOwner\", stat.getEphemeralOwner());\n    }\n\n    private void printHex(String prefix, long value) {\n        System.out.println(String.format(\"  %s = %#016x\", prefix, value));\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/Stats.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.util.Date;\n\n/**\n * Statistics on the ServerCnxn\n */\ninterface Stats {\n    /** Date/time the connection was established\n     * @since 3.3.0 */\n    Date getEstablished();\n\n    /**\n     * The number of requests that have been submitted but not yet\n     * responded to.\n     */\n    long getOutstandingRequests();\n    /** Number of packets received */\n    long getPacketsReceived();\n    /** Number of packets sent (incl notifications) */\n    long getPacketsSent();\n    /** Min latency in ms\n     * @since 3.3.0 */\n    long getMinLatency();\n    /** Average latency in ms\n     * @since 3.3.0 */\n    long getAvgLatency();\n    /** Max latency in ms\n     * @since 3.3.0 */\n    long getMaxLatency();\n    /** Last operation performed by this connection\n     * @since 3.3.0 */\n    String getLastOperation();\n    /** Last cxid of this connection\n     * @since 3.3.0 */\n    long getLastCxid();\n    /** Last zxid of this connection\n     * @since 3.3.0 */\n    long getLastZxid();\n    /** Last time server sent a response to client on this connection\n     * @since 3.3.0 */\n    long getLastResponseTime();\n    /** Latency of last response to client on this connection in ms\n     * @since 3.3.0 */\n    long getLastLatency();\n\n    /** Reset counters\n     * @since 3.3.0 */\n    void resetStats();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/SyncRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.Flushable;\nimport java.io.IOException;\nimport java.util.LinkedList;\nimport java.util.Random;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This RequestProcessor logs requests to disk. It batches the requests to do\n * the io efficiently. The request is not passed to the next RequestProcessor\n * until its log has been synced to disk.\n *\n * SyncRequestProcessor is used in 3 different cases\n * 1. Leader - Sync request to disk and forward it to AckRequestProcessor which\n *             send ack back to itself.\n * 2. Follower - Sync request to disk and forward request to\n *             SendAckRequestProcessor which send the packets to leader.\n *             SendAckRequestProcessor is flushable which allow us to force\n *             push packets to leader.\n * 3. Observer - Sync committed request to disk (received as INFORM packet).\n *             It never send ack back to the leader, so the nextProcessor will\n *             be null. This change the semantic of txnlog on the observer\n *             since it only contains committed txns.\n */\npublic class SyncRequestProcessor extends ZooKeeperCriticalThread implements RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(SyncRequestProcessor.class);\n    private final ZooKeeperServer zks;\n    private final LinkedBlockingQueue<Request> queuedRequests =\n        new LinkedBlockingQueue<Request>();\n    private final RequestProcessor nextProcessor;\n\n    private Thread snapInProcess = null;\n    volatile private boolean running;\n\n    /**\n     * Transactions that have been written and are waiting to be flushed to\n     * disk. Basically this is the list of SyncItems whose callbacks will be\n     * invoked after flush returns successfully.\n     */\n    private final LinkedList<Request> toFlush = new LinkedList<Request>();\n    private final Random r = new Random(System.nanoTime());\n    /**\n     * The number of log entries to log before starting a snapshot\n     */\n    private static int snapCount = ZooKeeperServer.getSnapCount();\n    \n    /**\n     * The number of log entries before rolling the log, number\n     * is chosen randomly\n     */\n    private static int randRoll;\n\n    private final Request requestOfDeath = Request.requestOfDeath;\n\n    public SyncRequestProcessor(ZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        super(\"SyncThread:\" + zks.getServerId(), zks\n                .getZooKeeperServerListener());\n        this.zks = zks;\n        this.nextProcessor = nextProcessor;\n        running = true;\n    }\n    \n    /**\n     * used by tests to check for changing\n     * snapcounts\n     * @param count\n     */\n    public static void setSnapCount(int count) {\n        snapCount = count;\n        randRoll = count;\n    }\n\n    /**\n     * used by tests to get the snapcount\n     * @return the snapcount\n     */\n    public static int getSnapCount() {\n        return snapCount;\n    }\n    \n    /**\n     * Sets the value of randRoll. This method \n     * is here to avoid a findbugs warning for\n     * setting a static variable in an instance\n     * method. \n     * \n     * @param roll\n     */\n    private static void setRandRoll(int roll) {\n        randRoll = roll;\n    }\n\n    @Override\n    public void run() {\n        try {\n            int logCount = 0;\n\n            // we do this in an attempt to ensure that not all of the servers\n            // in the ensemble take a snapshot at the same time\n            setRandRoll(r.nextInt(snapCount/2));\n            while (true) {\n                Request si = null;\n                if (toFlush.isEmpty()) {\n                    si = queuedRequests.take();\n                } else {\n                    si = queuedRequests.poll();\n                    if (si == null) {\n                        flush(toFlush);\n                        continue;\n                    }\n                }\n                if (si == requestOfDeath) {\n                    break;\n                }\n                if (si != null) {\n                    // track the number of records written to the log\n                    if (zks.getZKDatabase().append(si)) {\n                        logCount++;\n                        if (logCount > (snapCount / 2 + randRoll)) {\n                            setRandRoll(r.nextInt(snapCount/2));\n                            // roll the log\n                            zks.getZKDatabase().rollLog();\n                            // take a snapshot\n                            if (snapInProcess != null && snapInProcess.isAlive()) {\n                                LOG.warn(\"Too busy to snap, skipping\");\n                            } else {\n                                snapInProcess = new ZooKeeperThread(\"Snapshot Thread\") {\n                                        public void run() {\n                                            try {\n                                                zks.takeSnapshot();\n                                            } catch(Exception e) {\n                                                LOG.warn(\"Unexpected exception\", e);\n                                            }\n                                        }\n                                    };\n                                snapInProcess.start();\n                            }\n                            logCount = 0;\n                        }\n                    } else if (toFlush.isEmpty()) {\n                        // optimization for read heavy workloads\n                        // iff this is a read, and there are no pending\n                        // flushes (writes), then just pass this to the next\n                        // processor\n                        if (nextProcessor != null) {\n                            nextProcessor.processRequest(si);\n                            if (nextProcessor instanceof Flushable) {\n                                ((Flushable)nextProcessor).flush();\n                            }\n                        }\n                        continue;\n                    }\n                    toFlush.add(si);\n                    if (toFlush.size() > 1000) {\n                        flush(toFlush);\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            handleException(this.getName(), t);\n            running = false;\n        }\n        LOG.info(\"SyncRequestProcessor exited!\");\n    }\n\n    private void flush(LinkedList<Request> toFlush)\n        throws IOException, RequestProcessorException\n    {\n        if (toFlush.isEmpty())\n            return;\n\n        zks.getZKDatabase().commit();\n        while (!toFlush.isEmpty()) {\n            Request i = toFlush.remove();\n            if (nextProcessor != null) {\n                nextProcessor.processRequest(i);\n            }\n        }\n        if (nextProcessor != null && nextProcessor instanceof Flushable) {\n            ((Flushable)nextProcessor).flush();\n        }\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        queuedRequests.add(requestOfDeath);\n        try {\n            if(running){\n                this.join();\n            }\n            if (!toFlush.isEmpty()) {\n                flush(toFlush);\n            }\n        } catch(InterruptedException e) {\n            LOG.warn(\"Interrupted while wating for \" + this + \" to finish\");\n        } catch (IOException e) {\n            LOG.warn(\"Got IO exception during shutdown\");\n        } catch (RequestProcessorException e) {\n            LOG.warn(\"Got request processor exception during shutdown\");\n        }\n        if (nextProcessor != null) {\n            nextProcessor.shutdown();\n        }\n    }\n\n    public void processRequest(Request request) {\n        // request.addRQRec(\">sync\");\n        queuedRequests.add(request);\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/TraceFormatter.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.text.DateFormat;\nimport java.util.Date;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\n\npublic class TraceFormatter {\n\n    static String op2String(int op) {\n        switch (op) {\n        case OpCode.notification:\n            return \"notification\";\n        case OpCode.create:\n            return \"create\";\n        case OpCode.delete:\n            return \"delete\";\n        case OpCode.exists:\n            return \"exists\";\n        case OpCode.getData:\n            return \"getDate\";\n        case OpCode.setData:\n            return \"setData\";\n        case OpCode.multi:\n            return \"multi\";\n        case OpCode.getACL:\n            return \"getACL\";\n        case OpCode.setACL:\n            return \"setACL\";\n        case OpCode.getChildren:\n            return \"getChildren\";\n        case OpCode.getChildren2:\n            return \"getChildren2\";\n        case OpCode.ping:\n            return \"ping\";\n        case OpCode.createSession:\n            return \"createSession\";\n        case OpCode.closeSession:\n            return \"closeSession\";\n        case OpCode.error:\n            return \"error\";\n        default:\n            return \"unknown \" + op;\n        }\n    }\n\n    /**\n     * @param args\n     * @throws IOException\n     */\n    public static void main(String[] args) throws IOException {\n        if (args.length != 1) {\n            System.err.println(\"USAGE: TraceFormatter trace_file\");\n            System.exit(2);\n        }\n        FileChannel fc = new FileInputStream(args[0]).getChannel();\n        while (true) {\n            ByteBuffer bb = ByteBuffer.allocate(41);\n            fc.read(bb);\n            bb.flip();\n\n            byte app = bb.get();\n            long time = bb.getLong();\n            long id = bb.getLong();\n            int cxid = bb.getInt();\n            long zxid = bb.getLong();\n            int txnType = bb.getInt();\n            int type = bb.getInt();\n            int len = bb.getInt();\n            bb = ByteBuffer.allocate(len);\n            fc.read(bb);\n            bb.flip();\n            String path = \"n/a\";\n            if (bb.remaining() > 0) {\n                if (type != OpCode.createSession) {\n                    int pathLen = bb.getInt();\n                    byte b[] = new byte[pathLen];\n                    bb.get(b);\n                    path = new String(b);\n                }\n            }\n            System.out.println(DateFormat.getDateTimeInstance(DateFormat.SHORT,\n                    DateFormat.LONG).format(new Date(time))\n                    + \": \"\n                    + (char) app\n                    + \" id=0x\"\n                    + Long.toHexString(id)\n                    + \" cxid=\"\n                    + cxid\n                    + \" op=\"\n                    + op2String(type)\n                    + \" zxid=0x\"\n                    + Long.toHexString(zxid)\n                    + \" txnType=\"\n                    + txnType\n                    + \" len=\"\n                    + len + \" path=\" + path);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/UnimplementedRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.proto.ReplyHeader;\n\n/**\n * Manages the unknown requests (i.e. unknown OpCode), by:\n * - sending back the KeeperException.UnimplementedException() error code to the client\n * - closing the connection.\n */\npublic class UnimplementedRequestProcessor implements RequestProcessor {\n\n    public void processRequest(Request request) throws RequestProcessorException {\n        KeeperException ke = new KeeperException.UnimplementedException();\n        request.setException(ke);\n        ReplyHeader rh = new ReplyHeader(request.cxid, request.zxid, ke.code().intValue());\n        try {\n            request.cnxn.sendResponse(rh, null, \"response\");\n        } catch (IOException e) {\n            throw new RequestProcessorException(\"Can't send the response\", e);\n        }\n\n        request.cnxn.sendCloseSession();\n    }\n\n    public void shutdown() {\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/WatchManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.Map.Entry;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\n\n/**\n * This class manages watches. It allows watches to be associated with a string\n * and removes watchers and their watches in addition to managing triggers.\n */\npublic class WatchManager {\n    private static final Logger LOG = LoggerFactory.getLogger(WatchManager.class);\n\n    private final HashMap<String, HashSet<Watcher>> watchTable =\n        new HashMap<String, HashSet<Watcher>>();\n\n    private final HashMap<Watcher, HashSet<String>> watch2Paths =\n        new HashMap<Watcher, HashSet<String>>();\n\n    public synchronized int size(){\n        int result = 0;\n        for(Set<Watcher> watches : watchTable.values()) {\n            result += watches.size();\n        }\n        return result;\n    }\n\n    public synchronized void addWatch(String path, Watcher watcher) {\n        HashSet<Watcher> list = watchTable.get(path);\n        if (list == null) {\n            // don't waste memory if there are few watches on a node\n            // rehash when the 4th entry is added, doubling size thereafter\n            // seems like a good compromise\n            list = new HashSet<Watcher>(4);\n            watchTable.put(path, list);\n        }\n        list.add(watcher);\n\n        HashSet<String> paths = watch2Paths.get(watcher);\n        if (paths == null) {\n            // cnxns typically have many watches, so use default cap here\n            paths = new HashSet<String>();\n            watch2Paths.put(watcher, paths);\n        }\n        paths.add(path);\n    }\n\n    public synchronized void removeWatcher(Watcher watcher) {\n        HashSet<String> paths = watch2Paths.remove(watcher);\n        if (paths == null) {\n            return;\n        }\n        for (String p : paths) {\n            HashSet<Watcher> list = watchTable.get(p);\n            if (list != null) {\n                list.remove(watcher);\n                if (list.size() == 0) {\n                    watchTable.remove(p);\n                }\n            }\n        }\n    }\n\n    public Set<Watcher> triggerWatch(String path, EventType type) {\n        return triggerWatch(path, type, null);\n    }\n\n    public Set<Watcher> triggerWatch(String path, EventType type, Set<Watcher> supress) {\n        WatchedEvent e = new WatchedEvent(type,\n                KeeperState.SyncConnected, path);\n        HashSet<Watcher> watchers;\n        synchronized (this) {\n            watchers = watchTable.remove(path);\n            if (watchers == null || watchers.isEmpty()) {\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logTraceMessage(LOG,\n                            ZooTrace.EVENT_DELIVERY_TRACE_MASK,\n                            \"No watchers for \" + path);\n                }\n                return null;\n            }\n            for (Watcher w : watchers) {\n                HashSet<String> paths = watch2Paths.get(w);\n                if (paths != null) {\n                    paths.remove(path);\n                }\n            }\n        }\n        for (Watcher w : watchers) {\n            if (supress != null && supress.contains(w)) {\n                continue;\n            }\n            w.process(e);\n        }\n        return watchers;\n    }\n\n    /**\n     * Brief description of this object.\n     */\n    @Override\n    public synchronized String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(watch2Paths.size()).append(\" connections watching \")\n            .append(watchTable.size()).append(\" paths\\n\");\n\n        int total = 0;\n        for (HashSet<String> paths : watch2Paths.values()) {\n            total += paths.size();\n        }\n        sb.append(\"Total watches:\").append(total);\n\n        return sb.toString();\n    }\n\n    /**\n     * String representation of watches. Warning, may be large!\n     * @param byPath iff true output watches by paths, otw output\n     * watches by connection\n     * @return string representation of watches\n     */\n    public synchronized void dumpWatches(PrintWriter pwriter, boolean byPath) {\n        if (byPath) {\n            for (Entry<String, HashSet<Watcher>> e : watchTable.entrySet()) {\n                pwriter.println(e.getKey());\n                for (Watcher w : e.getValue()) {\n                    pwriter.print(\"\\t0x\");\n                    pwriter.print(Long.toHexString(((ServerCnxn)w).getSessionId()));\n                    pwriter.print(\"\\n\");\n                }\n            }\n        } else {\n            for (Entry<Watcher, HashSet<String>> e : watch2Paths.entrySet()) {\n                pwriter.print(\"0x\");\n                pwriter.println(Long.toHexString(((ServerCnxn)e.getKey()).getSessionId()));\n                for (String path : e.getValue()) {\n                    pwriter.print(\"\\t\");\n                    pwriter.println(path);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZKDatabase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.DataTree.ProcessTxnResult;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog.PlayBackListener;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.server.quorum.Leader.Proposal;\nimport org.apache.zookeeper.server.quorum.QuorumPacket;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This class maintains the in memory database of zookeeper\n * server states that includes the sessions, datatree and the\n * committed logs. It is booted up  after reading the logs\n * and snapshots from the disk.\n */\npublic class ZKDatabase {\n    \n    private static final Logger LOG = LoggerFactory.getLogger(ZKDatabase.class);\n    \n    /**\n     * make sure on a clear you take care of \n     * all these members.\n     */\n    protected DataTree dataTree;\n    protected ConcurrentHashMap<Long, Integer> sessionsWithTimeouts;\n    protected FileTxnSnapLog snapLog;\n    protected long minCommittedLog, maxCommittedLog;\n    public static final int commitLogCount = 500;\n    protected static int commitLogBuffer = 700;\n    protected LinkedList<Proposal> committedLog = new LinkedList<Proposal>();\n    protected ReentrantReadWriteLock logLock = new ReentrantReadWriteLock();\n    volatile private boolean initialized = false;\n    \n    /**\n     * the filetxnsnaplog that this zk database\n     * maps to. There is a one to one relationship\n     * between a filetxnsnaplog and zkdatabase.\n     * @param snapLog the FileTxnSnapLog mapping this zkdatabase\n     */\n    public ZKDatabase(FileTxnSnapLog snapLog) {\n        dataTree = new DataTree();\n        sessionsWithTimeouts = new ConcurrentHashMap<Long, Integer>();\n        this.snapLog = snapLog;\n    }\n    \n    /**\n     * checks to see if the zk database has been\n     * initialized or not.\n     * @return true if zk database is initialized and false if not\n     */\n    public boolean isInitialized() {\n        return initialized;\n    }\n    \n    /**\n     * clear the zkdatabase. \n     * Note to developers - be careful to see that \n     * the clear method does clear out all the\n     * data structures in zkdatabase.\n     */\n    public void clear() {\n        minCommittedLog = 0;\n        maxCommittedLog = 0;\n        /* to be safe we just create a new \n         * datatree.\n         */\n        dataTree = new DataTree();\n        sessionsWithTimeouts.clear();\n        WriteLock lock = logLock.writeLock();\n        try {            \n            lock.lock();\n            committedLog.clear();\n        } finally {\n            lock.unlock();\n        }\n        initialized = false;\n    }\n    \n    /**\n     * the datatree for this zkdatabase\n     * @return the datatree for this zkdatabase\n     */\n    public DataTree getDataTree() {\n        return this.dataTree;\n    }\n \n    /**\n     * the committed log for this zk database\n     * @return the committed log for this zkdatabase\n     */\n    public long getmaxCommittedLog() {\n        return maxCommittedLog;\n    }\n    \n    \n    /**\n     * the minimum committed transaction log\n     * available in memory\n     * @return the minimum committed transaction\n     * log available in memory\n     */\n    public long getminCommittedLog() {\n        return minCommittedLog;\n    }\n    /**\n     * Get the lock that controls the committedLog. If you want to get the pointer to the committedLog, you need\n     * to use this lock to acquire a read lock before calling getCommittedLog()\n     * @return the lock that controls the committed log\n     */\n    public ReentrantReadWriteLock getLogLock() {\n        return logLock;\n    }\n    \n\n    public synchronized LinkedList<Proposal> getCommittedLog() {\n        ReadLock rl = logLock.readLock();\n        // only make a copy if this thread isn't already holding a lock\n        if(logLock.getReadHoldCount() <=0) {\n            try {\n                rl.lock();\n                return new LinkedList<Proposal>(this.committedLog);\n            } finally {\n                rl.unlock();\n            }\n        } \n        return this.committedLog;\n    }      \n    \n    /**\n     * get the last processed zxid from a datatree\n     * @return the last processed zxid of a datatree\n     */\n    public long getDataTreeLastProcessedZxid() {\n        return dataTree.lastProcessedZxid;\n    }\n    \n    /**\n     * set the datatree initialized or not\n     * @param b set the datatree initialized to b\n     */\n    public void setDataTreeInit(boolean b) {\n        dataTree.initialized = b;\n    }\n    \n    /**\n     * return the sessions in the datatree\n     * @return the data tree sessions\n     */\n    public Collection<Long> getSessions() {\n        return dataTree.getSessions();\n    }\n    \n    /**\n     * get sessions with timeouts\n     * @return the hashmap of sessions with timeouts\n     */\n    public ConcurrentHashMap<Long, Integer> getSessionWithTimeOuts() {\n        return sessionsWithTimeouts;\n    }\n\n    private final PlayBackListener commitProposalPlaybackListener = new PlayBackListener() {\n        public void onTxnLoaded(TxnHeader hdr, Record txn){\n            addCommittedProposal(hdr, txn);\n        }\n    };\n\n    /**\n     * load the database from the disk onto memory and also add \n     * the transactions to the committedlog in memory.\n     * @return the last valid zxid on disk\n     * @throws IOException\n     */\n    public long loadDataBase() throws IOException {\n        long zxid = snapLog.restore(dataTree, sessionsWithTimeouts, commitProposalPlaybackListener);\n        initialized = true;\n        return zxid;\n    }\n\n    /**\n     * Fast forward the database adding transactions from the committed log into memory.\n     * @return the last valid zxid.\n     * @throws IOException\n     */\n    public long fastForwardDataBase() throws IOException {\n        long zxid = snapLog.fastForwardFromEdits(dataTree, sessionsWithTimeouts, commitProposalPlaybackListener);\n        initialized = true;\n        return zxid;\n    }\n\n    private void addCommittedProposal(TxnHeader hdr, Record txn) {\n        Request r = new Request(null, 0, hdr.getCxid(), hdr.getType(), null, null);\n        r.txn = txn;\n        r.hdr = hdr;\n        r.zxid = hdr.getZxid();\n        addCommittedProposal(r);\n    }\n\n    /**\n     * maintains a list of last <i>committedLog</i>\n     *  or so committed requests. This is used for\n     * fast follower synchronization.\n     * @param request committed request\n     */\n    public void addCommittedProposal(Request request) {\n        WriteLock wl = logLock.writeLock();\n        try {\n            wl.lock();\n            if (committedLog.size() > commitLogCount) {\n                committedLog.removeFirst();\n                minCommittedLog = committedLog.getFirst().packet.getZxid();\n            }\n            if (committedLog.size() == 0) {\n                minCommittedLog = request.zxid;\n                maxCommittedLog = request.zxid;\n            }\n\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n            try {\n                request.hdr.serialize(boa, \"hdr\");\n                if (request.txn != null) {\n                    request.txn.serialize(boa, \"txn\");\n                }\n                baos.close();\n            } catch (IOException e) {\n                LOG.error(\"This really should be impossible\", e);\n            }\n            QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid,\n                    baos.toByteArray(), null);\n            Proposal p = new Proposal();\n            p.packet = pp;\n            p.request = request;\n            committedLog.add(p);\n            maxCommittedLog = p.packet.getZxid();\n        } finally {\n            wl.unlock();\n        }\n    }\n\n\n    public List<ACL> aclForNode(DataNode n) {\n        return dataTree.getACL(n);\n    }\n    /**\n     * remove a cnxn from the datatree\n     * @param cnxn the cnxn to remove from the datatree\n     */\n    public void removeCnxn(ServerCnxn cnxn) {\n        dataTree.removeCnxn(cnxn);\n    }\n\n    /**\n     * kill a given session in the datatree\n     * @param sessionId the session id to be killed\n     * @param zxid the zxid of kill session transaction\n     */\n    public void killSession(long sessionId, long zxid) {\n        dataTree.killSession(sessionId, zxid);\n    }\n\n    /**\n     * write a text dump of all the ephemerals in the datatree\n     * @param pwriter the output to write to\n     */\n    public void dumpEphemerals(PrintWriter pwriter) {\n        dataTree.dumpEphemerals(pwriter);\n    }\n\n    /**\n     * the node count of the datatree\n     * @return the node count of datatree\n     */\n    public int getNodeCount() {\n        return dataTree.getNodeCount();\n    }\n\n    /**\n     * the paths for  ephemeral session id \n     * @param sessionId the session id for which paths match to \n     * @return the paths for a session id\n     */\n    public HashSet<String> getEphemerals(long sessionId) {\n        return dataTree.getEphemerals(sessionId);\n    }\n\n    /**\n     * the last processed zxid in the datatree\n     * @param zxid the last processed zxid in the datatree\n     */\n    public void setlastProcessedZxid(long zxid) {\n        dataTree.lastProcessedZxid = zxid;\n    }\n\n    /**\n     * the process txn on the data\n     * @param hdr the txnheader for the txn\n     * @param txn the transaction that needs to be processed\n     * @return the result of processing the transaction on this\n     * datatree/zkdatabase\n     */\n    public ProcessTxnResult processTxn(TxnHeader hdr, Record txn) {\n        return dataTree.processTxn(hdr, txn);\n    }\n\n    /**\n     * stat the path \n     * @param path the path for which stat is to be done\n     * @param serverCnxn the servercnxn attached to this request\n     * @return the stat of this node\n     * @throws KeeperException.NoNodeException\n     */\n    public Stat statNode(String path, ServerCnxn serverCnxn) throws KeeperException.NoNodeException {\n        return dataTree.statNode(path, serverCnxn);\n    }\n    \n    /**\n     * get the datanode for this path\n     * @param path the path to lookup\n     * @return the datanode for getting the path\n     */\n    public DataNode getNode(String path) {\n      return dataTree.getNode(path);\n    }\n\n    /**\n     * get data and stat for a path \n     * @param path the path being queried\n     * @param stat the stat for this path\n     * @param watcher the watcher function\n     * @return\n     * @throws KeeperException.NoNodeException\n     */\n    public byte[] getData(String path, Stat stat, Watcher watcher) \n    throws KeeperException.NoNodeException {\n        return dataTree.getData(path, stat, watcher);\n    }\n\n    /**\n     * set watches on the datatree\n     * @param relativeZxid the relative zxid that client has seen\n     * @param dataWatches the data watches the client wants to reset\n     * @param existWatches the exists watches the client wants to reset\n     * @param childWatches the child watches the client wants to reset\n     * @param watcher the watcher function\n     */\n    public void setWatches(long relativeZxid, List<String> dataWatches,\n            List<String> existWatches, List<String> childWatches, Watcher watcher) {\n        dataTree.setWatches(relativeZxid, dataWatches, existWatches, childWatches, watcher);\n    }\n    \n    /**\n     * get acl for a path\n     * @param path the path to query for acl\n     * @param stat the stat for the node\n     * @return the acl list for this path\n     * @throws NoNodeException\n     */\n    public List<ACL> getACL(String path, Stat stat) throws NoNodeException {\n        return dataTree.getACL(path, stat);\n    }\n\n    /**\n     * get children list for this path\n     * @param path the path of the node\n     * @param stat the stat of the node\n     * @param watcher the watcher function for this path\n     * @return the list of children for this path\n     * @throws KeeperException.NoNodeException\n     */\n    public List<String> getChildren(String path, Stat stat, Watcher watcher)\n    throws KeeperException.NoNodeException {\n        return dataTree.getChildren(path, stat, watcher);\n    }\n\n    /**\n     * check if the path is special or not\n     * @param path the input path\n     * @return true if path is special and false if not\n     */\n    public boolean isSpecialPath(String path) {\n        return dataTree.isSpecialPath(path);\n    }\n\n    /**\n     * get the acl size of the datatree\n     * @return the acl size of the datatree\n     */\n    public int getAclSize() {\n        return dataTree.aclCacheSize();\n    }\n\n    /**\n     * Truncate the ZKDatabase to the specified zxid\n     * @param zxid the zxid to truncate zk database to\n     * @return true if the truncate is successful and false if not\n     * @throws IOException\n     */\n    public boolean truncateLog(long zxid) throws IOException {\n        clear();\n\n        // truncate the log\n        boolean truncated = snapLog.truncateLog(zxid);\n\n        if (!truncated) {\n            return false;\n        }\n\n        loadDataBase();\n        return true;\n    }\n    \n    /**\n     * deserialize a snapshot from an input archive \n     * @param ia the input archive you want to deserialize from\n     * @throws IOException\n     */\n    public void deserializeSnapshot(InputArchive ia) throws IOException {\n        clear();\n        SerializeUtils.deserializeSnapshot(getDataTree(),ia,getSessionWithTimeOuts());\n        initialized = true;\n    }   \n    \n    /**\n     * serialize the snapshot\n     * @param oa the output archive to which the snapshot needs to be serialized\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    public void serializeSnapshot(OutputArchive oa) throws IOException,\n    InterruptedException {\n        SerializeUtils.serializeSnapshot(getDataTree(), oa, getSessionWithTimeOuts());\n    }\n\n    /**\n     * append to the underlying transaction log \n     * @param si the request to append\n     * @return true if the append was succesfull and false if not\n     */\n    public boolean append(Request si) throws IOException {\n        return this.snapLog.append(si);\n    }\n\n    /**\n     * roll the underlying log\n     */\n    public void rollLog() throws IOException {\n        this.snapLog.rollLog();\n    }\n\n    /**\n     * commit to the underlying transaction log\n     * @throws IOException\n     */\n    public void commit() throws IOException {\n        this.snapLog.commit();\n    }\n    \n    /**\n     * close this database. free the resources\n     * @throws IOException\n     */\n    public void close() throws IOException {\n        this.snapLog.close();\n    }\n    \n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperCriticalThread.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Represents critical thread. When there is an uncaught exception thrown by the\n * thread this will exit the system.\n */\npublic class ZooKeeperCriticalThread extends ZooKeeperThread {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(ZooKeeperCriticalThread.class);\n    private final ZooKeeperServerListener listener;\n\n    public ZooKeeperCriticalThread(String threadName,\n            ZooKeeperServerListener listener) {\n        super(threadName);\n        this.listener = listener;\n    }\n\n    /**\n     * This will be used by the uncaught exception handler and make the system\n     * exit.\n     * \n     * @param threadName\n     *            - thread name\n     * @param e\n     *            - exception object\n     */\n    @Override\n    protected void handleException(String threadName, Throwable e) {\n        LOG.error(\"Severe unrecoverable error, from thread : {}\", threadName, e);\n        listener.notifyStopping(threadName, ExitCode.UNEXPECTED_ERROR);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperSaslServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport javax.security.auth.Subject;\nimport javax.security.sasl.SaslException;\nimport javax.security.sasl.SaslServer;\n\nimport org.apache.zookeeper.Login;\nimport org.apache.zookeeper.util.SecurityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ZooKeeperSaslServer {\n    public static final String LOGIN_CONTEXT_NAME_KEY = \"zookeeper.sasl.serverconfig\";\n    public static final String DEFAULT_LOGIN_CONTEXT_NAME = \"Server\";\n\n    Logger LOG = LoggerFactory.getLogger(ZooKeeperSaslServer.class);\n    private SaslServer saslServer;\n\n    ZooKeeperSaslServer(final Login login) {\n        saslServer = createSaslServer(login);\n    }\n\n    private SaslServer createSaslServer(final Login login) {\n        synchronized (login) {\n            Subject subject = login.getSubject();\n            return SecurityUtils.createSaslServer(subject, \"zookeeper\",\n                    \"zk-sasl-md5\", login.callbackHandler, LOG);\n        }\n    }\n\n    public byte[] evaluateResponse(byte[] response) throws SaslException {\n        return saslServer.evaluateResponse(response);\n    }\n\n    public boolean isComplete() {\n        return saslServer.isComplete();\n    }\n\n    public String getAuthorizationID() {\n        return saslServer.getAuthorizationID();\n    }\n\n}\n\n\n\n\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.Environment;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.data.StatPersisted;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.proto.AuthPacket;\nimport org.apache.zookeeper.proto.ConnectRequest;\nimport org.apache.zookeeper.proto.ConnectResponse;\nimport org.apache.zookeeper.proto.GetSASLRequest;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.proto.SetSASLResponse;\nimport org.apache.zookeeper.server.DataTree.ProcessTxnResult;\nimport org.apache.zookeeper.server.RequestProcessor.RequestProcessorException;\nimport org.apache.zookeeper.server.ServerCnxn.CloseRequestException;\nimport org.apache.zookeeper.server.SessionTracker.Session;\nimport org.apache.zookeeper.server.SessionTracker.SessionExpirer;\nimport org.apache.zookeeper.server.auth.AuthenticationProvider;\nimport org.apache.zookeeper.server.auth.ProviderRegistry;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.ReadOnlyZooKeeperServer;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * This class implements a simple standalone ZooKeeperServer. It sets up the\n * following chain of RequestProcessors to process requests:\n * PrepRequestProcessor -> SyncRequestProcessor -> FinalRequestProcessor\n */\npublic class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {\n    protected static final Logger LOG;\n    \n    static {\n        LOG = LoggerFactory.getLogger(ZooKeeperServer.class);\n        \n        Environment.logEnv(\"Server environment:\", LOG);\n    }\n\n    protected ZooKeeperServerBean jmxServerBean;\n    protected DataTreeBean jmxDataTreeBean;\n\n \n    /**\n     * The server delegates loading of the tree to an instance of the interface\n     */\n    public interface DataTreeBuilder {\n        public DataTree build();\n    }\n\n    static public class BasicDataTreeBuilder implements DataTreeBuilder {\n        public DataTree build() {\n            return new DataTree();\n        }\n    }\n\n    public static final int DEFAULT_TICK_TIME = 3000;\n    protected int tickTime = DEFAULT_TICK_TIME;\n    /** value of -1 indicates unset, use default */\n    protected int minSessionTimeout = -1;\n    /** value of -1 indicates unset, use default */\n    protected int maxSessionTimeout = -1;\n    protected SessionTracker sessionTracker;\n    private FileTxnSnapLog txnLogFactory = null;\n    private ZKDatabase zkDb;\n    private final AtomicLong hzxid = new AtomicLong(0);\n    public final static Exception ok = new Exception(\"No prob\");\n    protected RequestProcessor firstProcessor;\n    protected volatile State state = State.INITIAL;\n\n    protected enum State {\n        INITIAL, RUNNING, SHUTDOWN, ERROR;\n    }\n\n    /**\n     * This is the secret that we use to generate passwords, for the moment it\n     * is more of a sanity check.\n     */\n    static final private long superSecret = 0XB3415C00L;\n\n    private final AtomicInteger requestsInProcess = new AtomicInteger(0);\n    final List<ChangeRecord> outstandingChanges = new ArrayList<ChangeRecord>();\n    // this data structure must be accessed under the outstandingChanges lock\n    final HashMap<String, ChangeRecord> outstandingChangesForPath =\n        new HashMap<String, ChangeRecord>();\n    \n    private ServerCnxnFactory serverCnxnFactory;\n\n    private final ServerStats serverStats;\n    private final ZooKeeperServerListener listener;\n    private ZooKeeperServerShutdownHandler zkShutdownHandler;\n\n    void removeCnxn(ServerCnxn cnxn) {\n        zkDb.removeCnxn(cnxn);\n    }\n \n    /**\n     * Creates a ZooKeeperServer instance. Nothing is setup, use the setX\n     * methods to prepare the instance (eg datadir, datalogdir, ticktime, \n     * builder, etc...)\n     * \n     * @throws IOException\n     */\n    public ZooKeeperServer() {\n        serverStats = new ServerStats(this);\n        listener = new ZooKeeperServerListenerImpl(this);\n    }\n    \n    /**\n     * Creates a ZooKeeperServer instance. It sets everything up, but doesn't\n     * actually start listening for clients until run() is invoked.\n     * \n     * @param dataDir the directory to put the data\n     */\n    public ZooKeeperServer(FileTxnSnapLog txnLogFactory, int tickTime,\n            int minSessionTimeout, int maxSessionTimeout,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb) {\n        serverStats = new ServerStats(this);\n        this.txnLogFactory = txnLogFactory;\n        this.zkDb = zkDb;\n        this.tickTime = tickTime;\n        this.minSessionTimeout = minSessionTimeout;\n        this.maxSessionTimeout = maxSessionTimeout;\n\n        listener = new ZooKeeperServerListenerImpl(this);\n\n        LOG.info(\"Created server with tickTime \" + tickTime\n                + \" minSessionTimeout \" + getMinSessionTimeout()\n                + \" maxSessionTimeout \" + getMaxSessionTimeout()\n                + \" datadir \" + txnLogFactory.getDataDir()\n                + \" snapdir \" + txnLogFactory.getSnapDir());\n    }\n\n    /**\n     * creates a zookeeperserver instance. \n     * @param txnLogFactory the file transaction snapshot logging class\n     * @param tickTime the ticktime for the server\n     * @param treeBuilder the datatree builder\n     * @throws IOException\n     */\n    public ZooKeeperServer(FileTxnSnapLog txnLogFactory, int tickTime,\n            DataTreeBuilder treeBuilder) throws IOException {\n        this(txnLogFactory, tickTime, -1, -1, treeBuilder,\n                new ZKDatabase(txnLogFactory));\n    }\n    \n    public ServerStats serverStats() {\n        return serverStats;\n    }\n\n    public void dumpConf(PrintWriter pwriter) {\n        pwriter.print(\"clientPort=\");\n        pwriter.println(getClientPort());\n        pwriter.print(\"dataDir=\");\n        pwriter.println(zkDb.snapLog.getSnapDir().getAbsolutePath());\n        pwriter.print(\"dataLogDir=\");\n        pwriter.println(zkDb.snapLog.getDataDir().getAbsolutePath());\n        pwriter.print(\"tickTime=\");\n        pwriter.println(getTickTime());\n        pwriter.print(\"maxClientCnxns=\");\n        pwriter.println(serverCnxnFactory.getMaxClientCnxnsPerHost());\n        pwriter.print(\"minSessionTimeout=\");\n        pwriter.println(getMinSessionTimeout());\n        pwriter.print(\"maxSessionTimeout=\");\n        pwriter.println(getMaxSessionTimeout());\n\n        pwriter.print(\"serverId=\");\n        pwriter.println(getServerId());\n    }\n\n    /**\n     * This constructor is for backward compatibility with the existing unit\n     * test code.\n     * It defaults to FileLogProvider persistence provider.\n     */\n    public ZooKeeperServer(File snapDir, File logDir, int tickTime)\n            throws IOException {\n        this( new FileTxnSnapLog(snapDir, logDir),\n                tickTime, new BasicDataTreeBuilder());\n    }\n\n    /**\n     * Default constructor, relies on the config for its agrument values\n     *\n     * @throws IOException\n     */\n    public ZooKeeperServer(FileTxnSnapLog txnLogFactory,\n            DataTreeBuilder treeBuilder)\n        throws IOException\n    {\n        this(txnLogFactory, DEFAULT_TICK_TIME, -1, -1, treeBuilder,\n                new ZKDatabase(txnLogFactory));\n    }\n\n    /**\n     * get the zookeeper database for this server\n     * @return the zookeeper database for this server\n     */\n    public ZKDatabase getZKDatabase() {\n        return this.zkDb;\n    }\n    \n    /**\n     * set the zkdatabase for this zookeeper server\n     * @param zkDb\n     */\n    public void setZKDatabase(ZKDatabase zkDb) {\n       this.zkDb = zkDb;\n    }\n    \n    /**\n     *  Restore sessions and data\n     */\n    public void loadData() throws IOException, InterruptedException {\n        /*\n         * When a new leader starts executing Leader#lead, it \n         * invokes this method. The database, however, has been\n         * initialized before running leader election so that\n         * the server could pick its zxid for its initial vote.\n         * It does it by invoking QuorumPeer#getLastLoggedZxid.\n         * Consequently, we don't need to initialize it once more\n         * and avoid the penalty of loading it a second time. Not \n         * reloading it is particularly important for applications\n         * that host a large database.\n         * \n         * The following if block checks whether the database has\n         * been initialized or not. Note that this method is\n         * invoked by at least one other method: \n         * ZooKeeperServer#startdata.\n         *  \n         * See ZOOKEEPER-1642 for more detail.\n         */\n        if(zkDb.isInitialized()){\n            setZxid(zkDb.getDataTreeLastProcessedZxid());\n        }\n        else {\n            setZxid(zkDb.loadDataBase());\n        }\n        \n        // Clean up dead sessions\n        LinkedList<Long> deadSessions = new LinkedList<Long>();\n        for (Long session : zkDb.getSessions()) {\n            if (zkDb.getSessionWithTimeOuts().get(session) == null) {\n                deadSessions.add(session);\n            }\n        }\n        zkDb.setDataTreeInit(true);\n        for (long session : deadSessions) {\n            // XXX: Is lastProcessedZxid really the best thing to use?\n            killSession(session, zkDb.getDataTreeLastProcessedZxid());\n        }\n    }\n\n    public void takeSnapshot(){\n\n        try {\n            txnLogFactory.save(zkDb.getDataTree(), zkDb.getSessionWithTimeOuts());\n        } catch (IOException e) {\n            LOG.error(\"Severe unrecoverable error, exiting\", e);\n            // This is a severe error that we cannot recover from,\n            // so we need to exit\n            System.exit(10);\n        }\n    }\n\n  \n    /**\n     * This should be called from a synchronized block on this!\n     */\n    public long getZxid() {\n        return hzxid.get();\n    }\n\n    long getNextZxid() {\n        return hzxid.incrementAndGet();\n    }\n\n    public void setZxid(long zxid) {\n        hzxid.set(zxid);\n    }\n\n    private void close(long sessionId) {\n        submitRequest(null, sessionId, OpCode.closeSession, 0, null, null);\n    }\n    \n    public void closeSession(long sessionId) {\n        LOG.info(\"Closing session 0x\" + Long.toHexString(sessionId));\n        \n        // we do not want to wait for a session close. send it as soon as we\n        // detect it!\n        close(sessionId);\n    }\n\n    protected void killSession(long sessionId, long zxid) {\n        zkDb.killSession(sessionId, zxid);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                                         \"ZooKeeperServer --- killSession: 0x\"\n                    + Long.toHexString(sessionId));\n        }\n        if (sessionTracker != null) {\n            sessionTracker.removeSession(sessionId);\n        }\n    }\n\n    public void expire(Session session) {\n        long sessionId = session.getSessionId();\n        LOG.info(\"Expiring session 0x\" + Long.toHexString(sessionId)\n                + \", timeout of \" + session.getTimeout() + \"ms exceeded\");\n        close(sessionId);\n    }\n\n    public static class MissingSessionException extends IOException {\n        private static final long serialVersionUID = 7467414635467261007L;\n\n        public MissingSessionException(String msg) {\n            super(msg);\n        }\n    }\n    \n    void touch(ServerCnxn cnxn) throws MissingSessionException {\n        if (cnxn == null) {\n            return;\n        }\n        long id = cnxn.getSessionId();\n        int to = cnxn.getSessionTimeout();\n        if (!sessionTracker.touchSession(id, to)) {\n            throw new MissingSessionException(\n                    \"No session with sessionid 0x\" + Long.toHexString(id)\n                    + \" exists, probably expired and removed\");\n        }\n    }\n\n    protected void registerJMX() {\n        // register with JMX\n        try {\n            jmxServerBean = new ZooKeeperServerBean(this);\n            MBeanRegistry.getInstance().register(jmxServerBean, null);\n            \n            try {\n                jmxDataTreeBean = new DataTreeBean(zkDb.getDataTree());\n                MBeanRegistry.getInstance().register(jmxDataTreeBean, jmxServerBean);\n            } catch (Exception e) {\n                LOG.warn(\"Failed to register with JMX\", e);\n                jmxDataTreeBean = null;\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxServerBean = null;\n        }\n    }\n    \n    public void startdata() \n    throws IOException, InterruptedException {\n        //check to see if zkDb is not null\n        if (zkDb == null) {\n            zkDb = new ZKDatabase(this.txnLogFactory);\n        }  \n        if (!zkDb.isInitialized()) {\n            loadData();\n        }\n    }\n    \n    public synchronized void startup() {\n        if (sessionTracker == null) {\n            createSessionTracker();\n        }\n        startSessionTracker();\n        setupRequestProcessors();\n\n        registerJMX();\n\n        setState(State.RUNNING);\n        notifyAll();\n    }\n\n    protected void setupRequestProcessors() {\n        RequestProcessor finalProcessor = new FinalRequestProcessor(this);\n        RequestProcessor syncProcessor = new SyncRequestProcessor(this,\n                finalProcessor);\n        ((SyncRequestProcessor)syncProcessor).start();\n        firstProcessor = new PrepRequestProcessor(this, syncProcessor);\n        ((PrepRequestProcessor)firstProcessor).start();\n    }\n\n    public ZooKeeperServerListener getZooKeeperServerListener() {\n        return listener;\n    }\n\n    protected void createSessionTracker() {\n        sessionTracker = new SessionTrackerImpl(this, zkDb.getSessionWithTimeOuts(),\n                tickTime, 1, getZooKeeperServerListener());\n    }\n    \n    protected void startSessionTracker() {\n        ((SessionTrackerImpl)sessionTracker).start();\n    }\n\n    /**\n     * Sets the state of ZooKeeper server. After changing the state, it notifies\n     * the server state change to a registered shutdown handler, if any.\n     * <p>\n     * The following are the server state transitions:\n     * <li>During startup the server will be in the INITIAL state.</li>\n     * <li>After successfully starting, the server sets the state to RUNNING.\n     * </li>\n     * <li>The server transitions to the ERROR state if it hits an internal\n     * error. {@link ZooKeeperServerListenerImpl} notifies any critical resource\n     * error events, e.g., SyncRequestProcessor not being able to write a txn to\n     * disk.</li>\n     * <li>During shutdown the server sets the state to SHUTDOWN, which\n     * corresponds to the server not running.</li>\n     *\n     * @param state new server state.\n     */\n    protected void setState(State state) {\n        this.state = state;\n        // Notify server state changes to the registered shutdown handler, if any.\n        if (zkShutdownHandler != null) {\n            zkShutdownHandler.handle(state);\n        } else {\n            LOG.debug(\"ZKShutdownHandler is not registered, so ZooKeeper server \"\n                    + \"won't take any action on ERROR or SHUTDOWN server state changes\");\n        }\n    }\n\n    /**\n     * This can be used while shutting down the server to see whether the server\n     * is already shutdown or not.\n     *\n     * @return true if the server is running or server hits an error, false\n     *         otherwise.\n     */\n    protected boolean canShutdown() {\n        return state == State.RUNNING || state == State.ERROR;\n    }\n\n    public boolean isRunning() {\n        return state == State.RUNNING;\n    }\n\n    public void shutdown() {\n        shutdown(false);\n    }\n\n    /**\n     * Shut down the server instance\n     * @param fullyShutDown true if another server using the same database will not replace this one in the same process\n     */\n    public synchronized void shutdown(boolean fullyShutDown) {\n        if (!canShutdown()) {\n            LOG.debug(\"ZooKeeper server is not running, so not proceeding to shutdown!\");\n            return;\n        }\n        LOG.info(\"shutting down\");\n\n        // new RuntimeException(\"Calling shutdown\").printStackTrace();\n        setState(State.SHUTDOWN);\n        // Since sessionTracker and syncThreads poll we just have to\n        // set running to false and they will detect it during the poll\n        // interval.\n        if (sessionTracker != null) {\n            sessionTracker.shutdown();\n        }\n        if (firstProcessor != null) {\n            firstProcessor.shutdown();\n        }\n\n        if (zkDb != null) {\n            if (fullyShutDown) {\n                zkDb.clear();\n            } else {\n                // else there is no need to clear the database\n                //  * When a new quorum is established we can still apply the diff\n                //    on top of the same zkDb data\n                //  * If we fetch a new snapshot from leader, the zkDb will be\n                //    cleared anyway before loading the snapshot\n                try {\n                    //This will fast forward the database to the latest recorded transactions\n                    zkDb.fastForwardDataBase();\n                } catch (IOException e) {\n                    LOG.error(\"Error updating DB\", e);\n                    zkDb.clear();\n                }\n            }\n        }\n\n        unregisterJMX();\n    }\n\n    protected void unregisterJMX() {\n        // unregister from JMX\n        try {\n            if (jmxDataTreeBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxDataTreeBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        try {\n            if (jmxServerBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxServerBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxServerBean = null;\n        jmxDataTreeBean = null;\n    }\n\n    public void incInProcess() {\n        requestsInProcess.incrementAndGet();\n    }\n\n    public void decInProcess() {\n        requestsInProcess.decrementAndGet();\n    }\n\n    public int getInProcess() {\n        return requestsInProcess.get();\n    }\n\n    /**\n     * This structure is used to facilitate information sharing between PrepRP\n     * and FinalRP.\n     */\n    static class ChangeRecord {\n        ChangeRecord(long zxid, String path, StatPersisted stat, int childCount,\n                List<ACL> acl) {\n            this.zxid = zxid;\n            this.path = path;\n            this.stat = stat;\n            this.childCount = childCount;\n            this.acl = acl;\n        }\n\n        long zxid;\n\n        String path;\n\n        StatPersisted stat; /* Make sure to create a new object when changing */\n\n        int childCount;\n\n        List<ACL> acl; /* Make sure to create a new object when changing */\n\n        @SuppressWarnings(\"unchecked\")\n        ChangeRecord duplicate(long zxid) {\n            StatPersisted stat = new StatPersisted();\n            if (this.stat != null) {\n                DataTree.copyStatPersisted(this.stat, stat);\n            }\n            return new ChangeRecord(zxid, path, stat, childCount,\n                    acl == null ? new ArrayList<ACL>() : new ArrayList<ACL>(acl));\n        }\n    }\n\n    byte[] generatePasswd(long id) {\n        Random r = new Random(id ^ superSecret);\n        byte p[] = new byte[16];\n        r.nextBytes(p);\n        return p;\n    }\n\n    protected boolean checkPasswd(long sessionId, byte[] passwd) {\n        return sessionId != 0\n                && Arrays.equals(passwd, generatePasswd(sessionId));\n    }\n\n    long createSession(ServerCnxn cnxn, byte passwd[], int timeout) {\n        long sessionId = sessionTracker.createSession(timeout);\n        Random r = new Random(sessionId ^ superSecret);\n        r.nextBytes(passwd);\n        ByteBuffer to = ByteBuffer.allocate(4);\n        to.putInt(timeout);\n        cnxn.setSessionId(sessionId);\n        submitRequest(cnxn, sessionId, OpCode.createSession, 0, to, null);\n        return sessionId;\n    }\n\n    /**\n     * set the owner of this session as owner\n     * @param id the session id\n     * @param owner the owner of the session\n     * @throws SessionExpiredException\n     */\n    public void setOwner(long id, Object owner) throws SessionExpiredException {\n        sessionTracker.setOwner(id, owner);\n    }\n\n    protected void revalidateSession(ServerCnxn cnxn, long sessionId,\n            int sessionTimeout) throws IOException {\n        boolean rc = sessionTracker.touchSession(sessionId, sessionTimeout);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG,ZooTrace.SESSION_TRACE_MASK,\n                                     \"Session 0x\" + Long.toHexString(sessionId) +\n                    \" is valid: \" + rc);\n        }\n        finishSessionInit(cnxn, rc);\n    }\n\n    public void reopenSession(ServerCnxn cnxn, long sessionId, byte[] passwd,\n            int sessionTimeout) throws IOException {\n        if (!checkPasswd(sessionId, passwd)) {\n            finishSessionInit(cnxn, false);\n        } else {\n            revalidateSession(cnxn, sessionId, sessionTimeout);\n        }\n    }\n\n    public void finishSessionInit(ServerCnxn cnxn, boolean valid) {\n        // register with JMX\n        try {\n            if (valid) {\n                serverCnxnFactory.registerConnection(cnxn);\n            }\n        } catch (Exception e) {\n                LOG.warn(\"Failed to register with JMX\", e);\n        }\n\n        try {\n            ConnectResponse rsp = new ConnectResponse(0, valid ? cnxn.getSessionTimeout()\n                    : 0, valid ? cnxn.getSessionId() : 0, // send 0 if session is no\n                            // longer valid\n                            valid ? generatePasswd(cnxn.getSessionId()) : new byte[16]);\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryOutputArchive bos = BinaryOutputArchive.getArchive(baos);\n            bos.writeInt(-1, \"len\");\n            rsp.serialize(bos, \"connect\");\n            if (!cnxn.isOldClient) {\n                bos.writeBool(\n                        this instanceof ReadOnlyZooKeeperServer, \"readOnly\");\n            }\n            baos.close();\n            ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n            bb.putInt(bb.remaining() - 4).rewind();\n            cnxn.sendBuffer(bb);    \n\n            if (!valid) {\n                LOG.info(\"Invalid session 0x\"\n                        + Long.toHexString(cnxn.getSessionId())\n                        + \" for client \"\n                        + cnxn.getRemoteSocketAddress()\n                        + \", probably expired\");\n                cnxn.sendBuffer(ServerCnxnFactory.closeConn);\n            } else {\n                LOG.info(\"Established session 0x\"\n                        + Long.toHexString(cnxn.getSessionId())\n                        + \" with negotiated timeout \" + cnxn.getSessionTimeout()\n                        + \" for client \"\n                        + cnxn.getRemoteSocketAddress());\n                cnxn.enableRecv();\n            }\n                \n        } catch (Exception e) {\n            LOG.warn(\"Exception while establishing session, closing\", e);\n            cnxn.close();\n        }\n    }\n    \n    public void closeSession(ServerCnxn cnxn, RequestHeader requestHeader) {\n        closeSession(cnxn.getSessionId());\n    }\n\n    public long getServerId() {\n        return 0;\n    }\n\n    /**\n     * @param cnxn\n     * @param sessionId\n     * @param xid\n     * @param bb\n     */\n    private void submitRequest(ServerCnxn cnxn, long sessionId, int type,\n            int xid, ByteBuffer bb, List<Id> authInfo) {\n        Request si = new Request(cnxn, sessionId, xid, type, bb, authInfo);\n        submitRequest(si);\n    }\n    \n    public void submitRequest(Request si) {\n        if (firstProcessor == null) {\n            synchronized (this) {\n                try {\n                    // Since all requests are passed to the request\n                    // processor it should wait for setting up the request\n                    // processor chain. The state will be updated to RUNNING\n                    // after the setup.\n                    while (state == State.INITIAL) {\n                        wait(1000);\n                    }\n                } catch (InterruptedException e) {\n                    LOG.warn(\"Unexpected interruption\", e);\n                }\n                if (firstProcessor == null || state != State.RUNNING) {\n                    throw new RuntimeException(\"Not started\");\n                }\n            }\n        }\n        try {\n            touch(si.cnxn);\n            boolean validpacket = Request.isValid(si.type);\n            if (validpacket) {\n                firstProcessor.processRequest(si);\n                if (si.cnxn != null) {\n                    incInProcess();\n                }\n            } else {\n                LOG.warn(\"Received packet at server of unknown type \" + si.type);\n                new UnimplementedRequestProcessor().processRequest(si);\n            }\n        } catch (MissingSessionException e) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Dropping request: \" + e.getMessage());\n            }\n        } catch (RequestProcessorException e) {\n            LOG.error(\"Unable to process request:\" + e.getMessage(), e);\n        }\n    }\n\n    public static int getSnapCount() {\n        String sc = System.getProperty(\"zookeeper.snapCount\");\n        try {\n            int snapCount = Integer.parseInt(sc);\n\n            // snapCount must be 2 or more. See org.apache.zookeeper.server.SyncRequestProcessor\n            if( snapCount < 2 ) {\n                LOG.warn(\"SnapCount should be 2 or more. Now, snapCount is reset to 2\");\n                snapCount = 2;\n            }\n            return snapCount;\n        } catch (Exception e) {\n            return 100000;\n        }\n    }\n\n    public int getGlobalOutstandingLimit() {\n        String sc = System.getProperty(\"zookeeper.globalOutstandingLimit\");\n        int limit;\n        try {\n            limit = Integer.parseInt(sc);\n        } catch (Exception e) {\n            limit = 1000;\n        }\n        return limit;\n    }\n\n    public void setServerCnxnFactory(ServerCnxnFactory factory) {\n        serverCnxnFactory = factory;\n    }\n\n    public ServerCnxnFactory getServerCnxnFactory() {\n        return serverCnxnFactory;\n    }\n\n    /**\n     * return the last proceesed id from the \n     * datatree\n     */\n    public long getLastProcessedZxid() {\n        return zkDb.getDataTreeLastProcessedZxid();\n    }\n\n    /**\n     * return the outstanding requests\n     * in the queue, which havent been \n     * processed yet\n     */\n    public long getOutstandingRequests() {\n        return getInProcess();\n    }\n\n    /**\n     * trunccate the log to get in sync with others \n     * if in a quorum\n     * @param zxid the zxid that it needs to get in sync\n     * with others\n     * @throws IOException\n     */\n    public void truncateLog(long zxid) throws IOException {\n        this.zkDb.truncateLog(zxid);\n    }\n       \n    public int getTickTime() {\n        return tickTime;\n    }\n\n    public void setTickTime(int tickTime) {\n        LOG.info(\"tickTime set to \" + tickTime);\n        this.tickTime = tickTime;\n    }\n\n    public int getMinSessionTimeout() {\n        return minSessionTimeout == -1 ? tickTime * 2 : minSessionTimeout;\n    }\n\n    public void setMinSessionTimeout(int min) {\n        LOG.info(\"minSessionTimeout set to \" + min);\n        this.minSessionTimeout = min;\n    }\n\n    public int getMaxSessionTimeout() {\n        return maxSessionTimeout == -1 ? tickTime * 20 : maxSessionTimeout;\n    }\n\n    public void setMaxSessionTimeout(int max) {\n        LOG.info(\"maxSessionTimeout set to \" + max);\n        this.maxSessionTimeout = max;\n    }\n\n    public int getClientPort() {\n        return serverCnxnFactory != null ? serverCnxnFactory.getLocalPort() : -1;\n    }\n\n    public void setTxnLogFactory(FileTxnSnapLog txnLog) {\n        this.txnLogFactory = txnLog;\n    }\n    \n    public FileTxnSnapLog getTxnLogFactory() {\n        return this.txnLogFactory;\n    }\n\n    public String getState() {\n        return \"standalone\";\n    }\n\n    public void dumpEphemerals(PrintWriter pwriter) {\n    \tzkDb.dumpEphemerals(pwriter);\n    }\n    \n    /**\n     * return the total number of client connections that are alive\n     * to this server\n     */\n    public int getNumAliveConnections() {\n        return serverCnxnFactory.getNumAliveConnections();\n    }\n    \n    public void processConnectRequest(ServerCnxn cnxn, ByteBuffer incomingBuffer) throws IOException {\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(new ByteBufferInputStream(incomingBuffer));\n        ConnectRequest connReq = new ConnectRequest();\n        connReq.deserialize(bia, \"connect\");\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Session establishment request from client \"\n                    + cnxn.getRemoteSocketAddress()\n                    + \" client's lastZxid is 0x\"\n                    + Long.toHexString(connReq.getLastZxidSeen()));\n        }\n        boolean readOnly = false;\n        try {\n            readOnly = bia.readBool(\"readOnly\");\n            cnxn.isOldClient = false;\n        } catch (IOException e) {\n            // this is ok -- just a packet from an old client which\n            // doesn't contain readOnly field\n            LOG.warn(\"Connection request from old client \"\n                    + cnxn.getRemoteSocketAddress()\n                    + \"; will be dropped if server is in r-o mode\");\n        }\n        if (readOnly == false && this instanceof ReadOnlyZooKeeperServer) {\n            String msg = \"Refusing session request for not-read-only client \"\n                + cnxn.getRemoteSocketAddress();\n            LOG.info(msg);\n            throw new CloseRequestException(msg);\n        }\n        if (connReq.getLastZxidSeen() > zkDb.dataTree.lastProcessedZxid) {\n            String msg = \"Refusing session request for client \"\n                + cnxn.getRemoteSocketAddress()\n                + \" as it has seen zxid 0x\"\n                + Long.toHexString(connReq.getLastZxidSeen())\n                + \" our last zxid is 0x\"\n                + Long.toHexString(getZKDatabase().getDataTreeLastProcessedZxid())\n                + \" client must try another server\";\n\n            LOG.info(msg);\n            throw new CloseRequestException(msg);\n        }\n        int sessionTimeout = connReq.getTimeOut();\n        byte passwd[] = connReq.getPasswd();\n        int minSessionTimeout = getMinSessionTimeout();\n        if (sessionTimeout < minSessionTimeout) {\n            sessionTimeout = minSessionTimeout;\n        }\n        int maxSessionTimeout = getMaxSessionTimeout();\n        if (sessionTimeout > maxSessionTimeout) {\n            sessionTimeout = maxSessionTimeout;\n        }\n        cnxn.setSessionTimeout(sessionTimeout);\n        // We don't want to receive any packets until we are sure that the\n        // session is setup\n        cnxn.disableRecv();\n        long sessionId = connReq.getSessionId();\n        if (sessionId != 0) {\n            long clientSessionId = connReq.getSessionId();\n            LOG.info(\"Client attempting to renew session 0x\"\n                    + Long.toHexString(clientSessionId)\n                    + \" at \" + cnxn.getRemoteSocketAddress());\n            serverCnxnFactory.closeSession(sessionId);\n            cnxn.setSessionId(sessionId);\n            reopenSession(cnxn, sessionId, passwd, sessionTimeout);\n        } else {\n            LOG.info(\"Client attempting to establish new session at \"\n                    + cnxn.getRemoteSocketAddress());\n            createSession(cnxn, passwd, sessionTimeout);\n        }\n    }\n\n    public boolean shouldThrottle(long outStandingCount) {\n        if (getGlobalOutstandingLimit() < getInProcess()) {\n            return outStandingCount > 0;\n        }\n        return false; \n    }\n\n    public void processPacket(ServerCnxn cnxn, ByteBuffer incomingBuffer) throws IOException {\n        // We have the request, now process and setup for next\n        InputStream bais = new ByteBufferInputStream(incomingBuffer);\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(bais);\n        RequestHeader h = new RequestHeader();\n        h.deserialize(bia, \"header\");\n        // Through the magic of byte buffers, txn will not be\n        // pointing\n        // to the start of the txn\n        incomingBuffer = incomingBuffer.slice();\n        if (h.getType() == OpCode.auth) {\n            LOG.info(\"got auth packet \" + cnxn.getRemoteSocketAddress());\n            AuthPacket authPacket = new AuthPacket();\n            ByteBufferInputStream.byteBuffer2Record(incomingBuffer, authPacket);\n            String scheme = authPacket.getScheme();\n            AuthenticationProvider ap = ProviderRegistry.getProvider(scheme);\n            Code authReturn = KeeperException.Code.AUTHFAILED;\n            if(ap != null) {\n                try {\n                    authReturn = ap.handleAuthentication(cnxn, authPacket.getAuth());\n                } catch(RuntimeException e) {\n                    LOG.warn(\"Caught runtime exception from AuthenticationProvider: \" + scheme + \" due to \" + e);\n                    authReturn = KeeperException.Code.AUTHFAILED;                   \n                }\n            }\n            if (authReturn!= KeeperException.Code.OK) {\n                if (ap == null) {\n                    LOG.warn(\"No authentication provider for scheme: \"\n                            + scheme + \" has \"\n                            + ProviderRegistry.listProviders());\n                } else {\n                    LOG.warn(\"Authentication failed for scheme: \" + scheme);\n                }\n                // send a response...\n                ReplyHeader rh = new ReplyHeader(h.getXid(), 0,\n                        KeeperException.Code.AUTHFAILED.intValue());\n                cnxn.sendResponse(rh, null, null);\n                // ... and close connection\n                cnxn.sendBuffer(ServerCnxnFactory.closeConn);\n                cnxn.disableRecv();\n            } else {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Authentication succeeded for scheme: \"\n                              + scheme);\n                }\n                LOG.info(\"auth success \" + cnxn.getRemoteSocketAddress());\n                ReplyHeader rh = new ReplyHeader(h.getXid(), 0,\n                        KeeperException.Code.OK.intValue());\n                cnxn.sendResponse(rh, null, null);\n            }\n            return;\n        } else {\n            if (h.getType() == OpCode.sasl) {\n                Record rsp = processSasl(incomingBuffer,cnxn);\n                ReplyHeader rh = new ReplyHeader(h.getXid(), 0, KeeperException.Code.OK.intValue());\n                cnxn.sendResponse(rh,rsp, \"response\"); // not sure about 3rd arg..what is it?\n                return;\n            }\n            else {\n                Request si = new Request(cnxn, cnxn.getSessionId(), h.getXid(),\n                  h.getType(), incomingBuffer, cnxn.getAuthInfo());\n                si.setOwner(ServerCnxn.me);\n                submitRequest(si);\n            }\n        }\n        cnxn.incrOutstandingRequests(h);\n    }\n\n    private Record processSasl(ByteBuffer incomingBuffer, ServerCnxn cnxn) throws IOException {\n        LOG.debug(\"Responding to client SASL token.\");\n        GetSASLRequest clientTokenRecord = new GetSASLRequest();\n        ByteBufferInputStream.byteBuffer2Record(incomingBuffer,clientTokenRecord);\n        byte[] clientToken = clientTokenRecord.getToken();\n        LOG.debug(\"Size of client SASL token: \" + clientToken.length);\n        byte[] responseToken = null;\n        try {\n            ZooKeeperSaslServer saslServer  = cnxn.zooKeeperSaslServer;\n            try {\n                // note that clientToken might be empty (clientToken.length == 0):\n                // if using the DIGEST-MD5 mechanism, clientToken will be empty at the beginning of the\n                // SASL negotiation process.\n                responseToken = saslServer.evaluateResponse(clientToken);\n                if (saslServer.isComplete() == true) {\n                    String authorizationID = saslServer.getAuthorizationID();\n                    LOG.info(\"adding SASL authorization for authorizationID: \" + authorizationID);\n                    cnxn.addAuthInfo(new Id(\"sasl\",authorizationID));\n                }\n            }\n            catch (SaslException e) {\n                LOG.warn(\"Client failed to SASL authenticate: \" + e, e);\n                if ((System.getProperty(\"zookeeper.allowSaslFailedClients\") != null)\n                  &&\n                  (System.getProperty(\"zookeeper.allowSaslFailedClients\").equals(\"true\"))) {\n                    LOG.warn(\"Maintaining client connection despite SASL authentication failure.\");\n                } else {\n                    LOG.warn(\"Closing client connection due to SASL authentication failure.\");\n                    cnxn.close();\n                }\n            }\n        }\n        catch (NullPointerException e) {\n            LOG.error(\"cnxn.saslServer is null: cnxn object did not initialize its saslServer properly.\");\n        }\n        if (responseToken != null) {\n            LOG.debug(\"Size of server SASL response: \" + responseToken.length);\n        }\n        // wrap SASL response token to client inside a Response object.\n        return new SetSASLResponse(responseToken);\n    }\n    \n    public ProcessTxnResult processTxn(TxnHeader hdr, Record txn) {\n        ProcessTxnResult rc;\n        int opCode = hdr.getType();\n        long sessionId = hdr.getClientId();\n        rc = getZKDatabase().processTxn(hdr, txn);\n        if (opCode == OpCode.createSession) {\n            if (txn instanceof CreateSessionTxn) {\n                CreateSessionTxn cst = (CreateSessionTxn) txn;\n                sessionTracker.addSession(sessionId, cst\n                        .getTimeOut());\n            } else {\n                LOG.warn(\"*****>>>>> Got \"\n                        + txn.getClass() + \" \"\n                        + txn.toString());\n            }\n        } else if (opCode == OpCode.closeSession) {\n            sessionTracker.removeSession(sessionId);\n        }\n        return rc;\n    }\n\n    /**\n     * This method is used to register the ZooKeeperServerShutdownHandler to get\n     * server's error or shutdown state change notifications.\n     * {@link ZooKeeperServerShutdownHandler#handle(State)} will be called for\n     * every server state changes {@link #setState(State)}.\n     *\n     * @param zkShutdownHandler shutdown handler\n     */\n    void registerServerShutdownHandler(ZooKeeperServerShutdownHandler zkShutdownHandler) {\n        this.zkShutdownHandler = zkShutdownHandler;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.Date;\n\nimport org.apache.zookeeper.Version;\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\n\n/**\n * This class implements the ZooKeeper server MBean interface.\n */\npublic class ZooKeeperServerBean implements ZooKeeperServerMXBean, ZKMBeanInfo {\n    private final Date startTime;\n    private final String name;\n    \n    protected final ZooKeeperServer zks;\n    \n    public ZooKeeperServerBean(ZooKeeperServer zks) {\n        startTime = new Date();\n        this.zks = zks;\n        name = \"StandaloneServer_port\" + zks.getClientPort();\n    }\n    \n    public String getClientPort() {\n        try {\n            return InetAddress.getLocalHost().getHostAddress() + \":\"\n                + zks.getClientPort();\n        } catch (UnknownHostException e) {\n            return \"localhost:\" + zks.getClientPort();\n        }\n    }\n    \n    public String getName() {\n        return name;\n    }\n    \n    public boolean isHidden() {\n        return false;\n    }\n    \n    public String getStartTime() {\n        return startTime.toString();\n    }\n    \n    public String getVersion() {\n        return Version.getFullVersion();\n    }\n    \n    public long getAvgRequestLatency() {\n        return zks.serverStats().getAvgLatency();\n    }\n    \n    public long getMaxRequestLatency() {\n        return zks.serverStats().getMaxLatency();\n    }\n    \n    public long getMinRequestLatency() {\n        return zks.serverStats().getMinLatency();\n    }\n    \n    public long getOutstandingRequests() {\n        return zks.serverStats().getOutstandingRequests();\n    }\n\n    public int getTickTime() {\n        return zks.getTickTime();\n    }\n\n    public void setTickTime(int tickTime) {\n        zks.setTickTime(tickTime);\n    }\n\n    public int getMaxClientCnxnsPerHost() {\n        ServerCnxnFactory fac = zks.getServerCnxnFactory();\n        if (fac == null) {\n            return -1;\n        }\n        return fac.getMaxClientCnxnsPerHost();\n    }\n\n    public void setMaxClientCnxnsPerHost(int max) {\n        // if fac is null the exception will be propagated to the client\n        zks.getServerCnxnFactory().setMaxClientCnxnsPerHost(max);\n    }\n\n    public int getMinSessionTimeout() {\n        return zks.getMinSessionTimeout();\n    }\n\n    public void setMinSessionTimeout(int min) {\n        zks.setMinSessionTimeout(min);\n    }\n\n    public int getMaxSessionTimeout() {\n        return zks.getMaxSessionTimeout();\n    }\n\n    public void setMaxSessionTimeout(int max) {\n        zks.setMaxSessionTimeout(max);\n    }\n\n    \n    public long getPacketsReceived() {\n        return zks.serverStats().getPacketsReceived();\n    }\n    \n    public long getPacketsSent() {\n        return zks.serverStats().getPacketsSent();\n    }\n    \n    public void resetLatency() {\n        zks.serverStats().resetLatency();\n    }\n    \n    public void resetMaxLatency() {\n        zks.serverStats().resetMaxLatency();\n    }\n\n    public void resetStatistics() {\n        ServerStats serverStats = zks.serverStats();\n        serverStats.resetRequestCounters();\n        serverStats.resetLatency();\n    }\n\n    public long getNumAliveConnections() {\n        return zks.getNumAliveConnections();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerListener.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\n/**\n * Listener for the critical resource events.\n */\npublic interface ZooKeeperServerListener {\n\n    /**\n     * This will notify the server that some critical thread has stopped. It\n     * usually takes place when fatal error occurred.\n     * \n     * @param threadName\n     *            - name of the thread\n     * @param errorCode\n     *            - error code\n     */\n    void notifyStopping(String threadName, int errorCode);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerListenerImpl.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport org.apache.zookeeper.server.ZooKeeperServer.State;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Default listener implementation, which will be used to notify internal\n * errors. For example, if some critical thread has stopped due to fatal errors,\n * then it will get notifications and will change the state of ZooKeeper server\n * to ERROR representing an error status.\n */\nclass ZooKeeperServerListenerImpl implements ZooKeeperServerListener {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(ZooKeeperServerListenerImpl.class);\n\n    private final ZooKeeperServer zkServer;\n\n    ZooKeeperServerListenerImpl(ZooKeeperServer zkServer) {\n        this.zkServer = zkServer;\n    }\n\n    @Override\n    public void notifyStopping(String threadName, int exitCode) {\n        LOG.info(\"Thread {} exits, error code {}\", threadName, exitCode);\n        zkServer.setState(State.ERROR);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\n/**\n * ZooKeeper server MBean.\n */\npublic interface ZooKeeperServerMXBean {\n    /**\n     * @return the server socket port number\n     */\n    public String getClientPort();\n    /**\n     * @return the zookeeper server version\n     */\n    public String getVersion();\n    /**\n     * @return time the server was started\n     */\n    public String getStartTime();\n    /**\n     * @return min request latency in ms\n     */\n    public long getMinRequestLatency();\n    /**\n     * @return average request latency in ms\n     */\n    public long getAvgRequestLatency();\n    /**\n     * @return max request latency in ms\n     */\n    public long getMaxRequestLatency();\n    /**\n     * @return number of packets received so far\n     */\n    public long getPacketsReceived();\n    /**\n     * @return number of packets sent so far\n     */\n    public long getPacketsSent();\n    /**\n     * @return number of outstanding requests.\n     */\n    public long getOutstandingRequests();\n    /**\n     * Current TickTime of server in milliseconds\n     */\n    public int getTickTime();\n    /**\n     * Set TickTime of server in milliseconds\n     */\n    public void setTickTime(int tickTime);\n\n    /** Current maxClientCnxns allowed from a particular host */\n    public int getMaxClientCnxnsPerHost();\n\n    /** Set maxClientCnxns allowed from a particular host */\n    public void setMaxClientCnxnsPerHost(int max);\n\n    /**\n     * Current minSessionTimeout of the server in milliseconds\n     */\n    public int getMinSessionTimeout();\n    /**\n     * Set minSessionTimeout of server in milliseconds\n     */\n    public void setMinSessionTimeout(int min);\n\n    /**\n     * Current maxSessionTimeout of the server in milliseconds\n     */\n    public int getMaxSessionTimeout();\n    /**\n     * Set maxSessionTimeout of server in milliseconds\n     */\n    public void setMaxSessionTimeout(int max);\n\n    /**\n     * Reset packet and latency statistics \n     */\n    public void resetStatistics();\n    /**\n     * Reset min/avg/max latency statistics\n     */\n    public void resetLatency();\n    /**\n     * Reset max latency statistics only.\n     */\n    public void resetMaxLatency();\n    /**\n     * @return number of alive client connections\n     */\n    public long getNumAliveConnections();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\n\nimport javax.management.JMException;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.jmx.ManagedUtil;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;\n\n/**\n * This class starts and runs a standalone ZooKeeperServer.\n */\n@InterfaceAudience.Public\npublic class ZooKeeperServerMain {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(ZooKeeperServerMain.class);\n\n    private static final String USAGE =\n        \"Usage: ZooKeeperServerMain configfile | port datadir [ticktime] [maxcnxns]\";\n\n    private ServerCnxnFactory cnxnFactory;\n\n    /*\n     * Start up the ZooKeeper server.\n     *\n     * @param args the configfile or the port datadir [ticktime]\n     */\n    public static void main(String[] args) {\n        ZooKeeperServerMain main = new ZooKeeperServerMain();\n        try {\n            main.initializeAndRun(args);\n        } catch (IllegalArgumentException e) {\n            LOG.error(\"Invalid arguments, exiting abnormally\", e);\n            LOG.info(USAGE);\n            System.err.println(USAGE);\n            System.exit(2);\n        } catch (ConfigException e) {\n            LOG.error(\"Invalid config, exiting abnormally\", e);\n            System.err.println(\"Invalid config, exiting abnormally\");\n            System.exit(2);\n        } catch (Exception e) {\n            LOG.error(\"Unexpected exception, exiting abnormally\", e);\n            System.exit(1);\n        }\n        LOG.info(\"Exiting normally\");\n        System.exit(0);\n    }\n\n    protected void initializeAndRun(String[] args)\n        throws ConfigException, IOException\n    {\n        try {\n            ManagedUtil.registerLog4jMBeans();\n        } catch (JMException e) {\n            LOG.warn(\"Unable to register log4j JMX control\", e);\n        }\n\n        ServerConfig config = new ServerConfig();\n        if (args.length == 1) {\n            config.parse(args[0]);\n        } else {\n            config.parse(args);\n        }\n\n        runFromConfig(config);\n    }\n\n    /**\n     * Run from a ServerConfig.\n     * @param config ServerConfig to use.\n     * @throws IOException\n     */\n    public void runFromConfig(ServerConfig config) throws IOException {\n        LOG.info(\"Starting server\");\n        FileTxnSnapLog txnLog = null;\n        try {\n            // Note that this thread isn't going to be doing anything else,\n            // so rather than spawning another thread, we will just call\n            // run() in this thread.\n            // create a file logger url from the command line args\n            final ZooKeeperServer zkServer = new ZooKeeperServer();\n            // Registers shutdown handler which will be used to know the\n            // server error or shutdown state changes.\n            final CountDownLatch shutdownLatch = new CountDownLatch(1);\n            zkServer.registerServerShutdownHandler(\n                    new ZooKeeperServerShutdownHandler(shutdownLatch));\n\n            txnLog = new FileTxnSnapLog(new File(config.dataLogDir), new File(\n                    config.dataDir));\n            zkServer.setTxnLogFactory(txnLog);\n            zkServer.setTickTime(config.tickTime);\n            zkServer.setMinSessionTimeout(config.minSessionTimeout);\n            zkServer.setMaxSessionTimeout(config.maxSessionTimeout);\n            cnxnFactory = ServerCnxnFactory.createFactory();\n            cnxnFactory.configure(config.getClientPortAddress(),\n                    config.getMaxClientCnxns());\n            cnxnFactory.startup(zkServer);\n            // Watch status of ZooKeeper server. It will do a graceful shutdown\n            // if the server is not running or hits an internal error.\n            shutdownLatch.await();\n            shutdown();\n\n            cnxnFactory.join();\n            if (zkServer.canShutdown()) {\n                zkServer.shutdown(true);\n            }\n        } catch (InterruptedException e) {\n            // warn, but generally this is ok\n            LOG.warn(\"Server interrupted\", e);\n        } finally {\n            if (txnLog != null) {\n                txnLog.close();\n            }\n        }\n    }\n\n    /**\n     * Shutdown the serving instance\n     */\n    protected void shutdown() {\n        if (cnxnFactory != null) {\n            cnxnFactory.shutdown();\n        }\n    }\n\n    // VisibleForTesting\n    ServerCnxnFactory getCnxnFactory() {\n        return cnxnFactory;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperServerShutdownHandler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.zookeeper.server.ZooKeeperServer.State;\n\n/**\n * ZooKeeper server shutdown handler which will be used to handle ERROR or\n * SHUTDOWN server state transitions, which in turn releases the associated\n * shutdown latch.\n */\nclass ZooKeeperServerShutdownHandler {\n    private final CountDownLatch shutdownLatch;\n\n    ZooKeeperServerShutdownHandler(CountDownLatch shutdownLatch) {\n        this.shutdownLatch = shutdownLatch;\n    }\n\n    /**\n     * This will be invoked when the server transition to a new server state.\n     *\n     * @param state new server state\n     */\n    void handle(State state) {\n        if (state == State.ERROR || state == State.SHUTDOWN) {\n            shutdownLatch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooKeeperThread.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This is the main class for catching all the uncaught exceptions thrown by the\n * threads.\n */\npublic class ZooKeeperThread extends Thread {\n\n    private static final Logger LOG = LoggerFactory\n            .getLogger(ZooKeeperThread.class);\n\n    private UncaughtExceptionHandler uncaughtExceptionalHandler = new UncaughtExceptionHandler() {\n\n        @Override\n        public void uncaughtException(Thread t, Throwable e) {\n            handleException(t.getName(), e);\n        }\n    };\n\n    public ZooKeeperThread(Runnable thread, String threadName) {\n        super(thread, threadName);\n        setUncaughtExceptionHandler(uncaughtExceptionalHandler);\n    }\n\n    public ZooKeeperThread(String threadName) {\n        super(threadName);\n        setUncaughtExceptionHandler(uncaughtExceptionalHandler);\n    }\n\n    /**\n     * This will be used by the uncaught exception handler and just log a\n     * warning message and return.\n     * \n     * @param thName\n     *            - thread name\n     * @param e\n     *            - exception object\n     */\n    protected void handleException(String thName, Throwable e) {\n        LOG.warn(\"Exception occurred from thread {}\", thName, e);\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/ZooTrace.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.quorum.LearnerHandler;\nimport org.apache.zookeeper.server.quorum.QuorumPacket;\n\n/**\n * This class encapsulates and centralizes tracing for the ZooKeeper server.\n * Trace messages go to the log with TRACE level.\n * <p>\n * Log4j must be correctly configured to capture the TRACE messages.\n */\npublic class ZooTrace {\n    final static public long CLIENT_REQUEST_TRACE_MASK = 1 << 1;\n\n    final static public long CLIENT_DATA_PACKET_TRACE_MASK = 1 << 2;\n\n    final static public long CLIENT_PING_TRACE_MASK = 1 << 3;\n\n    final static public long SERVER_PACKET_TRACE_MASK = 1 << 4;\n\n    final static public long SESSION_TRACE_MASK = 1 << 5;\n\n    final static public long EVENT_DELIVERY_TRACE_MASK = 1 << 6;\n\n    final static public long SERVER_PING_TRACE_MASK = 1 << 7;\n\n    final static public long WARNING_TRACE_MASK = 1 << 8;\n\n    final static public long JMX_TRACE_MASK = 1 << 9;\n\n    private static long traceMask = CLIENT_REQUEST_TRACE_MASK\n            | SERVER_PACKET_TRACE_MASK | SESSION_TRACE_MASK\n            | WARNING_TRACE_MASK;\n\n    public static long getTextTraceLevel() {\n        return traceMask;\n    }\n\n    public static void setTextTraceLevel(long mask) {\n        traceMask = mask;\n        Logger LOG = LoggerFactory.getLogger(ZooTrace.class);\n        LOG.info(\"Set text trace mask to 0x\" + Long.toHexString(mask));\n    }\n\n    public static boolean isTraceEnabled(Logger log, long mask) {\n        return log.isTraceEnabled() && (mask & traceMask) != 0;\n    }\n\n    public static void logTraceMessage(Logger log, long mask, String msg) {\n        if (isTraceEnabled(log, mask)) {\n            log.trace(msg);\n        }\n    }\n\n    static public void logQuorumPacket(Logger log, long mask,\n            char direction, QuorumPacket qp)\n    {\n        if (isTraceEnabled(log, mask)) { \n            logTraceMessage(log, mask, direction +\n                    \" \" + LearnerHandler.packetToString(qp));\n         }\n    }\n\n    static public void logRequest(Logger log, long mask,\n            char rp, Request request, String header)\n    {\n        if (isTraceEnabled(log, mask)) {\n            log.trace(header + \":\" + rp + request.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/AuthenticationProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.server.ServerCnxn;\n\n/**\n * This interface is implemented by authentication providers to add new kinds of\n * authentication schemes to ZooKeeper.\n */\npublic interface AuthenticationProvider {\n    /**\n     * The String used to represent this provider. This will correspond to the\n     * scheme field of an Id.\n     * \n     * @return the scheme of this provider.\n     */\n    String getScheme();\n\n    /**\n     * This method is called when a client passes authentication data for this\n     * scheme. The authData is directly from the authentication packet. The\n     * implementor may attach new ids to the authInfo field of cnxn or may use\n     * cnxn to send packets back to the client.\n     * \n     * @param cnxn\n     *                the cnxn that received the authentication information.\n     * @param authData\n     *                the authentication data received.\n     * @return TODO\n     */\n    KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte authData[]);\n\n    /**\n     * This method is called to see if the given id matches the given id\n     * expression in the ACL. This allows schemes to use application specific\n     * wild cards.\n     * \n     * @param id\n     *                the id to check.\n     * @param aclExpr\n     *                the expression to match ids against.\n     * @return true if the id can be matched by the expression.\n     */\n    boolean matches(String id, String aclExpr);\n\n    /**\n     * This method is used to check if the authentication done by this provider\n     * should be used to identify the creator of a node. Some ids such as hosts\n     * and ip addresses are rather transient and in general don't really\n     * identify a client even though sometimes they do.\n     * \n     * @return true if this provider identifies creators.\n     */\n    boolean isAuthenticated();\n\n    /**\n     * Validates the syntax of an id.\n     * \n     * @param id\n     *                the id to validate.\n     * @return true if id is well formed.\n     */\n    boolean isValid(String id);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/DigestAuthenticationProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.server.ServerCnxn;\n\npublic class DigestAuthenticationProvider implements AuthenticationProvider {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(DigestAuthenticationProvider.class);\n\n    /** specify a command line property with key of \n     * \"zookeeper.DigestAuthenticationProvider.superDigest\"\n     * and value of \"super:<base64encoded(SHA1(password))>\" to enable\n     * super user access (i.e. acls disabled)\n     */\n    private final static String superDigest = System.getProperty(\n        \"zookeeper.DigestAuthenticationProvider.superDigest\");\n\n    public String getScheme() {\n        return \"digest\";\n    }\n\n    static final private String base64Encode(byte b[]) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < b.length;) {\n            int pad = 0;\n            int v = (b[i++] & 0xff) << 16;\n            if (i < b.length) {\n                v |= (b[i++] & 0xff) << 8;\n            } else {\n                pad++;\n            }\n            if (i < b.length) {\n                v |= (b[i++] & 0xff);\n            } else {\n                pad++;\n            }\n            sb.append(encode(v >> 18));\n            sb.append(encode(v >> 12));\n            if (pad < 2) {\n                sb.append(encode(v >> 6));\n            } else {\n                sb.append('=');\n            }\n            if (pad < 1) {\n                sb.append(encode(v));\n            } else {\n                sb.append('=');\n            }\n        }\n        return sb.toString();\n    }\n\n    static final private char encode(int i) {\n        i &= 0x3f;\n        if (i < 26) {\n            return (char) ('A' + i);\n        }\n        if (i < 52) {\n            return (char) ('a' + i - 26);\n        }\n        if (i < 62) {\n            return (char) ('0' + i - 52);\n        }\n        return i == 62 ? '+' : '/';\n    }\n\n    static public String generateDigest(String idPassword)\n            throws NoSuchAlgorithmException {\n        String parts[] = idPassword.split(\":\", 2);\n        byte digest[] = MessageDigest.getInstance(\"SHA1\").digest(\n                idPassword.getBytes());\n        return parts[0] + \":\" + base64Encode(digest);\n    }\n\n    public KeeperException.Code \n        handleAuthentication(ServerCnxn cnxn, byte[] authData)\n    {\n        String id = new String(authData);\n        try {\n            String digest = generateDigest(id);\n            if (digest.equals(superDigest)) {\n                cnxn.addAuthInfo(new Id(\"super\", \"\"));\n            }\n            cnxn.addAuthInfo(new Id(getScheme(), digest));\n            return KeeperException.Code.OK;\n        } catch (NoSuchAlgorithmException e) {\n            LOG.error(\"Missing algorithm\",e);\n        }\n        return KeeperException.Code.AUTHFAILED;\n    }\n\n    public boolean isAuthenticated() {\n        return true;\n    }\n\n    public boolean isValid(String id) {\n        String parts[] = id.split(\":\");\n        return parts.length == 2;\n    }\n\n    public boolean matches(String id, String aclExpr) {\n        return id.equals(aclExpr);\n    }\n\n    /** Call with a single argument of user:pass to generate authdata.\n     * Authdata output can be used when setting superDigest for example. \n     * @param args single argument of user:pass\n     * @throws NoSuchAlgorithmException\n     */\n    public static void main(String args[]) throws NoSuchAlgorithmException {\n        for (int i = 0; i < args.length; i++) {\n            System.out.println(args[i] + \"->\" + generateDigest(args[i]));\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/DigestLoginModule.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport javax.security.auth.Subject;\nimport javax.security.auth.callback.CallbackHandler;\nimport javax.security.auth.spi.LoginModule;\nimport java.util.Map;\n\npublic class DigestLoginModule implements LoginModule {\n    private Subject subject;\n\n    public boolean abort() {\n        return false;\n    }\n\n    public boolean commit() {\n        return true;\n    }\n\n    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,?> sharedState, Map<String,?> options) {\n        if (options.containsKey(\"username\")) {\n            // Zookeeper client: get username and password from JAAS conf (only used if using DIGEST-MD5).\n            this.subject = subject;\n            String username = (String)options.get(\"username\");\n            this.subject.getPublicCredentials().add((Object)username);\n            String password = (String)options.get(\"password\");\n            this.subject.getPrivateCredentials().add((Object)password);\n        }\n        return;\n    }\n\n    public boolean logout() {\n        return true;\n    }\n\n    public boolean login() {\n        // Unlike with Krb5LoginModule, we don't do any actual login or credential passing here: authentication to Zookeeper\n        // is done later, through the SASLClient object.\n        return true;\n    }\n\n}\n\n\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/IPAuthenticationProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.server.ServerCnxn;\n\npublic class IPAuthenticationProvider implements AuthenticationProvider {\n\n    public String getScheme() {\n        return \"ip\";\n    }\n\n    public KeeperException.Code\n        handleAuthentication(ServerCnxn cnxn, byte[] authData)\n    {\n        String id = cnxn.getRemoteSocketAddress().getAddress().getHostAddress();\n        cnxn.addAuthInfo(new Id(getScheme(), id));\n        return KeeperException.Code.OK;\n    }\n\n    // This is a bit weird but we need to return the address and the number of\n    // bytes (to distinguish between IPv4 and IPv6\n    private byte[] addr2Bytes(String addr) {\n        byte b[] = v4addr2Bytes(addr);\n        // TODO Write the v6addr2Bytes\n        return b;\n    }\n\n    private byte[] v4addr2Bytes(String addr) {\n        String parts[] = addr.split(\"\\\\.\", -1);\n        if (parts.length != 4) {\n            return null;\n        }\n        byte b[] = new byte[4];\n        for (int i = 0; i < 4; i++) {\n            try {\n                int v = Integer.parseInt(parts[i]);\n                if (v >= 0 && v <= 255) {\n                    b[i] = (byte) v;\n                } else {\n                    return null;\n                }\n            } catch (NumberFormatException e) {\n                return null;\n            }\n        }\n        return b;\n    }\n\n    private void mask(byte b[], int bits) {\n        int start = bits / 8;\n        int startMask = (1 << (8 - (bits % 8))) - 1;\n        startMask = ~startMask;\n        while (start < b.length) {\n            b[start] &= startMask;\n            startMask = 0;\n            start++;\n        }\n    }\n\n    public boolean matches(String id, String aclExpr) {\n        String parts[] = aclExpr.split(\"/\", 2);\n        byte aclAddr[] = addr2Bytes(parts[0]);\n        if (aclAddr == null) {\n            return false;\n        }\n        int bits = aclAddr.length * 8;\n        if (parts.length == 2) {\n            try {\n                bits = Integer.parseInt(parts[1]);\n                if (bits < 0 || bits > aclAddr.length * 8) {\n                    return false;\n                }\n            } catch (NumberFormatException e) {\n                return false;\n            }\n        }\n        mask(aclAddr, bits);\n        byte remoteAddr[] = addr2Bytes(id);\n        if (remoteAddr == null) {\n            return false;\n        }\n        mask(remoteAddr, bits);\n        for (int i = 0; i < remoteAddr.length; i++) {\n            if (remoteAddr[i] != aclAddr[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public boolean isAuthenticated() {\n        return false;\n    }\n\n    public boolean isValid(String id) {\n        return addr2Bytes(id) != null;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/KerberosName.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n /* This file copied from Hadoop's security branch,\n  * with the following changes:\n  * 1. package changed from org.apache.hadoop.security to\n  *    org.apache.zookeeper.server.auth.\n  * 2. Usage of Hadoop's Configuration class removed since\n  *    it is not available in Zookeeper: instead, system property\n  *    \"zookeeper.security.auth_to_local\" is used.\n  */\n\npackage org.apache.zookeeper.server.auth;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.zookeeper.server.util.KerberosUtil;\n\n/**\n * This class implements parsing and handling of Kerberos principal names. In \n * particular, it splits them apart and translates them down into local\n * operating system names.\n */\npublic class KerberosName {\n  /** The first component of the name */\n  private final String serviceName;\n  /** The second component of the name. It may be null. */\n  private final String hostName;\n  /** The realm of the name. */\n  private final String realm;\n\n  /**\n   * A pattern that matches a Kerberos name with at most 2 components.\n   */\n  private static final Pattern nameParser = \n    Pattern.compile(\"([^/@]*)(/([^/@]*))?@([^/@]*)\");\n\n  /** \n   * A pattern that matches a string with out '$' and then a single\n   * parameter with $n.\n   */\n  private static Pattern parameterPattern = \n    Pattern.compile(\"([^$]*)(\\\\$(\\\\d*))?\");\n\n  /**\n   * A pattern for parsing a auth_to_local rule.\n   */\n  private static final Pattern ruleParser =\n    Pattern.compile(\"\\\\s*((DEFAULT)|(RULE:\\\\[(\\\\d*):([^\\\\]]*)](\\\\(([^)]*)\\\\))?\"+\n                    \"(s/([^/]*)/([^/]*)/(g)?)?))\");\n  \n  /**\n   * A pattern that recognizes simple/non-simple names.\n   */\n  private static final Pattern nonSimplePattern = Pattern.compile(\"[/@]\");\n  \n  /**\n   * The list of translation rules.\n   */\n  private static List<Rule> rules;\n\n  private static String defaultRealm;\n  \n  static {\n    try {\n      defaultRealm = KerberosUtil.getDefaultRealm();\n    } catch (Exception ke) {\n      if ((System.getProperty(\"zookeeper.requireKerberosConfig\") != null) &&\n          (System.getProperty(\"zookeeper.requireKerberosConfig\").equals(\"true\"))) {\n        throw new IllegalArgumentException(\"Can't get Kerberos configuration\",ke);\n      }\n      else\n        defaultRealm=\"\";\n    }\n    try {\n      // setConfiguration() will work even if the above try() fails due\n      // to a missing Kerberos configuration (unless zookeeper.requireKerberosConfig\n      // is set to true, which would not allow execution to reach here due to the\n      // throwing of an IllegalArgumentException above).\n      setConfiguration();\n    }\n    catch (IOException e) {\n      throw new IllegalArgumentException(\"Could not configure Kerberos principal name mapping.\");\n    }\n  }\n\n  /**\n   * Create a name from the full Kerberos principal name.\n   * @param name\n   */\n  public KerberosName(String name) {\n    Matcher match = nameParser.matcher(name);\n    if (!match.matches()) {\n      if (name.contains(\"@\")) {\n        throw new IllegalArgumentException(\"Malformed Kerberos name: \" + name);\n      } else {\n        serviceName = name;\n        hostName = null;\n        realm = null;\n      }\n    } else {\n      serviceName = match.group(1);\n      hostName = match.group(3);\n      realm = match.group(4);\n    }\n  }\n\n  /**\n   * Get the configured default realm.\n   * @return the default realm from the krb5.conf\n   */\n  public String getDefaultRealm() {\n    return defaultRealm;\n  }\n\n  /**\n   * Put the name back together from the parts.\n   */\n  @Override\n  public String toString() {\n    StringBuilder result = new StringBuilder();\n    result.append(serviceName);\n    if (hostName != null) {\n      result.append('/');\n      result.append(hostName);\n    }\n    if (realm != null) {\n      result.append('@');\n      result.append(realm);\n    }\n    return result.toString();\n  }\n\n  /**\n   * Get the first component of the name.\n   * @return the first section of the Kerberos principal name\n   */\n  public String getServiceName() {\n    return serviceName;\n  }\n\n  /**\n   * Get the second component of the name.\n   * @return the second section of the Kerberos principal name, and may be null\n   */\n  public String getHostName() {\n    return hostName;\n  }\n  \n  /**\n   * Get the realm of the name.\n   * @return the realm of the name, may be null\n   */\n  public String getRealm() {\n    return realm;\n  }\n  \n  /**\n   * An encoding of a rule for translating kerberos names.\n   */\n  private static class Rule {\n    private final boolean isDefault;\n    private final int numOfComponents;\n    private final String format;\n    private final Pattern match;\n    private final Pattern fromPattern;\n    private final String toPattern;\n    private final boolean repeat;\n\n    Rule() {\n      isDefault = true;\n      numOfComponents = 0;\n      format = null;\n      match = null;\n      fromPattern = null;\n      toPattern = null;\n      repeat = false;\n    }\n\n    Rule(int numOfComponents, String format, String match, String fromPattern,\n         String toPattern, boolean repeat) {\n      isDefault = false;\n      this.numOfComponents = numOfComponents;\n      this.format = format;\n      this.match = match == null ? null : Pattern.compile(match);\n      this.fromPattern = \n        fromPattern == null ? null : Pattern.compile(fromPattern);\n      this.toPattern = toPattern;\n      this.repeat = repeat;\n    }\n    \n    @Override\n    public String toString() {\n      StringBuilder buf = new StringBuilder();\n      if (isDefault) {\n        buf.append(\"DEFAULT\");\n      } else {\n        buf.append(\"RULE:[\");\n        buf.append(numOfComponents);\n        buf.append(':');\n        buf.append(format);\n        buf.append(']');\n        if (match != null) {\n          buf.append('(');\n          buf.append(match);\n          buf.append(')');\n        }\n        if (fromPattern != null) {\n          buf.append(\"s/\");\n          buf.append(fromPattern);\n          buf.append('/');\n          buf.append(toPattern);\n          buf.append('/');\n          if (repeat) {\n            buf.append('g');\n          }\n        }\n      }\n      return buf.toString();\n    }\n    \n    /**\n     * Replace the numbered parameters of the form $n where n is from 1 to \n     * the length of params. Normal text is copied directly and $n is replaced\n     * by the corresponding parameter.\n     * @param format the string to replace parameters again\n     * @param params the list of parameters\n     * @return the generated string with the parameter references replaced.\n     * @throws BadFormatString\n     */\n    static String replaceParameters(String format, \n                                    String[] params) throws BadFormatString {\n      Matcher match = parameterPattern.matcher(format);\n      int start = 0;\n      StringBuilder result = new StringBuilder();\n      while (start < format.length() && match.find(start)) {\n        result.append(match.group(1));\n        String paramNum = match.group(3);\n        if (paramNum != null) {\n          try {\n            int num = Integer.parseInt(paramNum);\n            if (num < 0 || num > params.length) {\n              throw new BadFormatString(\"index \" + num + \" from \" + format +\n                                        \" is outside of the valid range 0 to \" +\n                                        (params.length - 1));\n            }\n            result.append(params[num]);\n          } catch (NumberFormatException nfe) {\n            throw new BadFormatString(\"bad format in username mapping in \" + \n                                      paramNum, nfe);\n          }\n          \n        }\n        start = match.end();\n      }\n      return result.toString();\n    }\n\n    /**\n     * Replace the matches of the from pattern in the base string with the value\n     * of the to string.\n     * @param base the string to transform\n     * @param from the pattern to look for in the base string\n     * @param to the string to replace matches of the pattern with\n     * @param repeat whether the substitution should be repeated\n     * @return\n     */\n    static String replaceSubstitution(String base, Pattern from, String to, \n                                      boolean repeat) {\n      Matcher match = from.matcher(base);\n      if (repeat) {\n        return match.replaceAll(to);\n      } else {\n        return match.replaceFirst(to);\n      }\n    }\n\n    /**\n     * Try to apply this rule to the given name represented as a parameter\n     * array.\n     * @param params first element is the realm, second and later elements are\n     *        are the components of the name \"a/b@FOO\" -> {\"FOO\", \"a\", \"b\"}\n     * @return the short name if this rule applies or null\n     * @throws IOException throws if something is wrong with the rules\n     */\n    String apply(String[] params) throws IOException {\n      String result = null;\n      if (isDefault) {\n        if (defaultRealm.equals(params[0])) {\n          result = params[1];\n        }\n      } else if (params.length - 1 == numOfComponents) {\n        String base = replaceParameters(format, params);\n        if (match == null || match.matcher(base).matches()) {\n          if (fromPattern == null) {\n            result = base;\n          } else {\n            result = replaceSubstitution(base, fromPattern, toPattern,  repeat);\n          }\n        }\n      }\n      if (result != null && nonSimplePattern.matcher(result).find()) {\n        throw new NoMatchingRule(\"Non-simple name \" + result +\n                                 \" after auth_to_local rule \" + this);\n      }\n      return result;\n    }\n  }\n\n  static List<Rule> parseRules(String rules) {\n    List<Rule> result = new ArrayList<Rule>();\n    String remaining = rules.trim();\n    while (remaining.length() > 0) {\n      Matcher matcher = ruleParser.matcher(remaining);\n      if (!matcher.lookingAt()) {\n        throw new IllegalArgumentException(\"Invalid rule: \" + remaining);\n      }\n      if (matcher.group(2) != null) {\n        result.add(new Rule());\n      } else {\n        result.add(new Rule(Integer.parseInt(matcher.group(4)),\n                            matcher.group(5),\n                            matcher.group(7),\n                            matcher.group(9),\n                            matcher.group(10),\n                            \"g\".equals(matcher.group(11))));\n      }\n      remaining = remaining.substring(matcher.end());\n    }\n    return result;\n  }\n\n  /**\n   * Set the static configuration to get the rules.\n   * @param conf the new configuration\n   * @throws IOException\n   */\n  public static void setConfiguration() throws IOException {\n    String ruleString = System.getProperty(\"zookeeper.security.auth_to_local\", \"DEFAULT\");\n    rules = parseRules(ruleString);\n  }\n\n  @SuppressWarnings(\"serial\")\n  public static class BadFormatString extends IOException {\n    BadFormatString(String msg) {\n      super(msg);\n    }\n    BadFormatString(String msg, Throwable err) {\n      super(msg, err);\n    }\n  }\n\n  @SuppressWarnings(\"serial\")\n  public static class NoMatchingRule extends IOException {\n    NoMatchingRule(String msg) {\n      super(msg);\n    }\n  }\n\n  /**\n   * Get the translation of the principal name into an operating system\n   * user name.\n   * @return the short name\n   * @throws IOException\n   */\n  public String getShortName() throws IOException {\n    String[] params;\n    if (hostName == null) {\n      // if it is already simple, just return it\n      if (realm == null) {\n        return serviceName;\n      }\n      params = new String[]{realm, serviceName};\n    } else {\n      params = new String[]{realm, serviceName, hostName};\n    }\n    for(Rule r: rules) {\n      String result = r.apply(params);\n      if (result != null) {\n        return result;\n      }\n    }\n    throw new NoMatchingRule(\"No rules applied to \" + toString());\n  }\n\n  static void printRules() throws IOException {\n    int i = 0;\n    for(Rule r: rules) {\n      System.out.println(++i + \" \" + r);\n    }\n  }\n\n  public static void main(String[] args) throws Exception {\n    for(String arg: args) {\n      KerberosName name = new KerberosName(arg);\n      System.out.println(\"Name: \" + name + \" to \" + name.getShortName());\n    }\n  }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/ProviderRegistry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport java.util.Enumeration;\nimport java.util.HashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.ZooKeeperServer;\n\npublic class ProviderRegistry {\n    private static final Logger LOG = LoggerFactory.getLogger(ProviderRegistry.class);\n\n    private static boolean initialized = false;\n    private static HashMap<String, AuthenticationProvider> authenticationProviders =\n        new HashMap<String, AuthenticationProvider>();\n\n    public static void initialize() {\n        synchronized (ProviderRegistry.class) {\n            if (initialized)\n                return;\n            IPAuthenticationProvider ipp = new IPAuthenticationProvider();\n            DigestAuthenticationProvider digp = new DigestAuthenticationProvider();\n            authenticationProviders.put(ipp.getScheme(), ipp);\n            authenticationProviders.put(digp.getScheme(), digp);\n            Enumeration<Object> en = System.getProperties().keys();\n            while (en.hasMoreElements()) {\n                String k = (String) en.nextElement();\n                if (k.startsWith(\"zookeeper.authProvider.\")) {\n                    String className = System.getProperty(k);\n                    try {\n                        Class<?> c = ZooKeeperServer.class.getClassLoader()\n                                .loadClass(className);\n                        AuthenticationProvider ap = (AuthenticationProvider) c\n                                .getDeclaredConstructor().newInstance();\n                        authenticationProviders.put(ap.getScheme(), ap);\n                    } catch (Exception e) {\n                        LOG.warn(\"Problems loading \" + className,e);\n                    }\n                }\n            }\n            initialized = true;\n        }\n    }\n\n    public static AuthenticationProvider getProvider(String scheme) {\n        if(!initialized)\n            initialize();\n        return authenticationProviders.get(scheme);\n    }\n\n    public static String listProviders() {\n        StringBuilder sb = new StringBuilder();\n        for(String s: authenticationProviders.keySet()) {\n        sb.append(s + \" \");\n}\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/SASLAuthenticationProvider.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.server.ServerCnxn;\n\npublic class SASLAuthenticationProvider implements AuthenticationProvider {\n\n    public String getScheme() {\n        return \"sasl\";\n    }\n\n    public KeeperException.Code\n        handleAuthentication(ServerCnxn cnxn, byte[] authData)\n    {\n        // Should never call this: SASL authentication is negotiated at session initiation.\n        // TODO: consider substituting current implementation of direct ClientCnxn manipulation with\n        // a call to this method (SASLAuthenticationProvider:handleAuthentication()) at session initiation.\n        return KeeperException.Code.AUTHFAILED;\n\n    }\n\n    public boolean matches(String id,String aclExpr) {\n        if (System.getProperty(\"zookeeper.superUser\") != null) {\n            return (id.equals(System.getProperty(\"zookeeper.superUser\")) || id.equals(aclExpr));\n        }\n        return (id.equals(\"super\") || id.equals(aclExpr));\n    }\n\n    public boolean isAuthenticated() {\n        return true;\n    }\n\n    public boolean isValid(String id) {\n        // Since the SASL authenticator will usually be used with Kerberos authentication,\n        // it should enforce that these names are valid according to Kerberos's\n        // syntax for principals.\n        //\n        // Use the KerberosName(id) constructor to define validity:\n        // if KerberosName(id) throws IllegalArgumentException, then id is invalid.\n        // otherwise, it is valid.\n        //\n        try {\n            new KerberosName(id);\n            return true;\n        }\n        catch (IllegalArgumentException e) {\n            return false;\n        }\n   }\n\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/auth/SaslServerCallbackHandler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.auth;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport javax.security.auth.callback.Callback;\nimport javax.security.auth.callback.CallbackHandler;\nimport javax.security.auth.callback.NameCallback;\nimport javax.security.auth.callback.PasswordCallback;\nimport javax.security.auth.callback.UnsupportedCallbackException;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.sasl.AuthorizeCallback;\nimport javax.security.sasl.RealmCallback;\n\nimport org.apache.zookeeper.server.ZooKeeperSaslServer;\n\npublic class SaslServerCallbackHandler implements CallbackHandler {\n    private static final String USER_PREFIX = \"user_\";\n    private static final Logger LOG = LoggerFactory.getLogger(SaslServerCallbackHandler.class);\n    private static final String SYSPROP_SUPER_PASSWORD = \"zookeeper.SASLAuthenticationProvider.superPassword\";\n    private static final String SYSPROP_REMOVE_HOST = \"zookeeper.kerberos.removeHostFromPrincipal\";\n    private static final String SYSPROP_REMOVE_REALM = \"zookeeper.kerberos.removeRealmFromPrincipal\";\n\n    private String userName;\n    private final Map<String,String> credentials = new HashMap<String,String>();\n\n    public SaslServerCallbackHandler(Configuration configuration)\n            throws IOException {\n        String serverSection = System.getProperty(\n                ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY,\n                ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME);\n        AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(serverSection);\n\n        if (configurationEntries == null) {\n            String errorMessage = \"Could not find a '\" + serverSection + \"' entry in this configuration: Server cannot start.\";\n            LOG.error(errorMessage);\n            throw new IOException(errorMessage);\n        }\n        credentials.clear();\n        for(AppConfigurationEntry entry: configurationEntries) {\n            Map<String,?> options = entry.getOptions();\n            // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the \"Server\" section.\n            // Usernames are distinguished from other options by prefixing the username with a \"user_\" prefix.\n            for(Map.Entry<String, ?> pair : options.entrySet()) {\n                String key = pair.getKey();\n                if (key.startsWith(USER_PREFIX)) {\n                    String userName = key.substring(USER_PREFIX.length());\n                    credentials.put(userName,(String)pair.getValue());\n                }\n            }\n        }\n    }\n\n    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {\n        for (Callback callback : callbacks) {\n            if (callback instanceof NameCallback) {\n                handleNameCallback((NameCallback) callback);\n            } else if (callback instanceof PasswordCallback) {\n                handlePasswordCallback((PasswordCallback) callback);\n            } else if (callback instanceof RealmCallback) {\n                handleRealmCallback((RealmCallback) callback);\n            } else if (callback instanceof AuthorizeCallback) {\n                handleAuthorizeCallback((AuthorizeCallback) callback);\n            }\n        }\n    }\n\n    private void handleNameCallback(NameCallback nc) {\n        // check to see if this user is in the user password database.\n        if (credentials.get(nc.getDefaultName()) == null) {\n            LOG.warn(\"User '\" + nc.getDefaultName() + \"' not found in list of DIGEST-MD5 authenticateable users.\");\n            return;\n        }\n        nc.setName(nc.getDefaultName());\n        userName = nc.getDefaultName();\n    }\n\n    private void handlePasswordCallback(PasswordCallback pc) {\n        if (\"super\".equals(this.userName) && System.getProperty(SYSPROP_SUPER_PASSWORD) != null) {\n            // superuser: use Java system property for password, if available.\n            pc.setPassword(System.getProperty(SYSPROP_SUPER_PASSWORD).toCharArray());\n        } else if (credentials.containsKey(userName) ) {\n            pc.setPassword(credentials.get(userName).toCharArray());\n        } else {\n            LOG.warn(\"No password found for user: \" + userName);\n        }\n    }\n\n    private void handleRealmCallback(RealmCallback rc) {\n        LOG.debug(\"client supplied realm: \" + rc.getDefaultText());\n        rc.setText(rc.getDefaultText());\n    }\n\n    private void handleAuthorizeCallback(AuthorizeCallback ac) {\n        String authenticationID = ac.getAuthenticationID();\n        String authorizationID = ac.getAuthorizationID();\n\n        LOG.info(\"Successfully authenticated client: authenticationID=\" + authenticationID\n                + \";  authorizationID=\" + authorizationID + \".\");\n        ac.setAuthorized(true);\n\n        // canonicalize authorization id according to system properties:\n        // zookeeper.kerberos.removeRealmFromPrincipal(={true,false})\n        // zookeeper.kerberos.removeHostFromPrincipal(={true,false})\n        KerberosName kerberosName = new KerberosName(authenticationID);\n        try {\n            StringBuilder userNameBuilder = new StringBuilder(kerberosName.getShortName());\n            if (shouldAppendHost(kerberosName)) {\n                userNameBuilder.append(\"/\").append(kerberosName.getHostName());\n            }\n            if (shouldAppendRealm(kerberosName)) {\n                userNameBuilder.append(\"@\").append(kerberosName.getRealm());\n            }\n            LOG.info(\"Setting authorizedID: \" + userNameBuilder);\n            ac.setAuthorizedID(userNameBuilder.toString());\n        } catch (IOException e) {\n            LOG.error(\"Failed to set name based on Kerberos authentication rules.\", e);\n        }\n    }\n\n    private boolean shouldAppendRealm(KerberosName kerberosName) {\n        return !isSystemPropertyTrue(SYSPROP_REMOVE_REALM) && kerberosName.getRealm() != null;\n    }\n\n    private boolean shouldAppendHost(KerberosName kerberosName) {\n        return !isSystemPropertyTrue(SYSPROP_REMOVE_HOST) && kerberosName.getHostName() != null;\n    }\n\n    private boolean isSystemPropertyTrue(String propertyName) {\n        return \"true\".equals(System.getProperty(propertyName));\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/package.html",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<html>\n<body>\n<h1>ZooKeeper server theory of operation</h1>\nZooKeeperServer is designed to work in standalone mode and also\nbe extensible so that it can be used to implement the quorum based\nversion of ZooKeeper.\n<p>\nZooKeeper maintains a order when processing requests:\n<ul>\n<li>All requests will be processed in order.\n<li>All responses will return in order.\n<li>All watches will be sent in the order that the update takes place.\n</ul>\n<p>\nWe will explain the three aspects of ZooKeeperServer: request processing, data\nstructure maintenance, and session tracking.\n\n<h2>Request processing</h2>\n\nRequests are received by the ServerCnxn. Demarshalling of a request is\ndone by ClientRequestHandler. After a request has been demarshalled,\nClientRequestHandler invokes the relevant method in ZooKeeper and marshals\nthe result.\n<p>\nIf the request is just a query, it will be processed by ZooKeeper and returned.\nOtherwise, the request will be validated and a transaction will be generated\nand logged. This the request will then wait until the request has been logged\nbefore continuing processing.\n<p>\nRequests are logged as a group. Transactions are queued up and the SyncThread\nwill process them at predefined intervals. (Currently 20ms) The SyncThread\ninteracts with ZooKeeperServer the txnQueue. Transactions are added to the\ntxnQueue of SyncThread via queueItem. When the transaction has been synced to\ndisk, its callback will be invoked which will cause the request processing to\nbe completed.\n\n<h2>Data structure maintenance</h2>\n\nZooKeeper data is stored in-memory. Each znode is stored in a DataNode object.\nThis object is accessed through a hash table that maps paths to DataNodes.\nDataNodes also organize themselves into a tree. This tree is only used for\nserializing nodes.\n<p>\nWe guarantee that changes to nodes are stored to non-volatile media before\nresponding to a client. We do this quickly by writing changes as a sequence\nof transactions in a log file. Even though we flush transactions as a group,\nwe need to avoid seeks as much as possible. Also, since the server can fail\nat any point, we need to be careful of partial records.\n<p>\nWe address the above problems by\n<ul>\n<li>Pre-allocating 1M chunks of file space. This allows us to append to the\nfile without causing seeks to update file size. It also means that we need\nto check for the end of the log by looking for a zero length transaction\nrather than simply end of file.\n<li>Writing a signature at the end of each transaction. When processing\ntransactions, we only use transactions that have a valid signature at the end.\n</ul>\n<p>\nAs the server runs, the log file will grow quite large. To avoid long startup\ntimes we periodically take a snapshot of the tree of DataNodes. We cannot\ntake the snapshot synchronously as the data takes a while to write out, so\ninstead we asynchronously write out the tree. This means that we end up\nwith a \"corrupt\" snapshot of the data tree. More formally if we define T\nto be the real snapshot of the tree at the time we begin taking the snapshot\nand l as the sequence of transactions that are applied to the tree between\nthe time the snapshot begins and the time the snapshot completes, we write\nto disk T+l' where l' is a subset of the transactions in l. While we do not\nhave a way of figuring out which transactions make up l', it doesn't really\nmatter. T+l'+l = T+l since the transactions we log are idempotent (applying\nthe transaction multiple times has the same result as applying the transaction\nonce). So when we restore the snapshot we also play all transactions in the log\nthat occur after the snapshot was begun. We can easily figure out where to\nstart the replay because we start a new logfile when we start a snapshot. Both\nthe snapshot file and log file have a numeric suffix that represent the\ntransaction id that created the respective files.\n\n<h2>Session tracking</h2>\nRather than tracking sessions exactly, we track them in batches. That are\nprocessed at fixed intervals. This is easier to implement than exact\nsession tracking and it is more efficient in terms of performance. It also \nprovides a small grace period for session renewal.\n</body>\n</html>"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/FileSnap.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.zip.Adler32;\nimport java.util.zip.CheckedInputStream;\nimport java.util.zip.CheckedOutputStream;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.util.SerializeUtils;\n\n/**\n * This class implements the snapshot interface.\n * it is responsible for storing, serializing\n * and deserializing the right snapshot.\n * and provides access to the snapshots.\n */\npublic class FileSnap implements SnapShot {\n    File snapDir;\n    private volatile boolean close = false;\n    private static final int VERSION=2;\n    private static final long dbId=-1;\n    private static final Logger LOG = LoggerFactory.getLogger(FileSnap.class);\n    public final static int SNAP_MAGIC\n        = ByteBuffer.wrap(\"ZKSN\".getBytes()).getInt();\n\n    public static final String SNAPSHOT_FILE_PREFIX = \"snapshot\";\n\n    public FileSnap(File snapDir) {\n        this.snapDir = snapDir;\n    }\n\n    /**\n     * deserialize a data tree from the most recent snapshot\n     * @return the zxid of the snapshot\n     */ \n    public long deserialize(DataTree dt, Map<Long, Integer> sessions)\n            throws IOException {\n        // we run through 100 snapshots (not all of them)\n        // if we cannot get it running within 100 snapshots\n        // we should  give up\n        List<File> snapList = findNValidSnapshots(100);\n        if (snapList.size() == 0) {\n            return -1L;\n        }\n        File snap = null;\n        boolean foundValid = false;\n        for (int i = 0; i < snapList.size(); i++) {\n            snap = snapList.get(i);\n            InputStream snapIS = null;\n            CheckedInputStream crcIn = null;\n            try {\n                LOG.info(\"Reading snapshot \" + snap);\n                snapIS = new BufferedInputStream(new FileInputStream(snap));\n                crcIn = new CheckedInputStream(snapIS, new Adler32());\n                InputArchive ia = BinaryInputArchive.getArchive(crcIn);\n                deserialize(dt,sessions, ia);\n                long checkSum = crcIn.getChecksum().getValue();\n                long val = ia.readLong(\"val\");\n                if (val != checkSum) {\n                    throw new IOException(\"CRC corruption in snapshot :  \" + snap);\n                }\n                foundValid = true;\n                break;\n            } catch(IOException e) {\n                LOG.warn(\"problem reading snap file \" + snap, e);\n            } finally {\n                if (snapIS != null) \n                    snapIS.close();\n                if (crcIn != null) \n                    crcIn.close();\n            } \n        }\n        if (!foundValid) {\n            throw new IOException(\"Not able to find valid snapshots in \" + snapDir);\n        }\n        dt.lastProcessedZxid = Util.getZxidFromName(snap.getName(), SNAPSHOT_FILE_PREFIX);\n        return dt.lastProcessedZxid;\n    }\n\n    /**\n     * deserialize the datatree from an inputarchive\n     * @param dt the datatree to be serialized into\n     * @param sessions the sessions to be filled up\n     * @param ia the input archive to restore from\n     * @throws IOException\n     */\n    public void deserialize(DataTree dt, Map<Long, Integer> sessions,\n            InputArchive ia) throws IOException {\n        FileHeader header = new FileHeader();\n        header.deserialize(ia, \"fileheader\");\n        if (header.getMagic() != SNAP_MAGIC) {\n            throw new IOException(\"mismatching magic headers \"\n                    + header.getMagic() + \n                    \" !=  \" + FileSnap.SNAP_MAGIC);\n        }\n        SerializeUtils.deserializeSnapshot(dt,ia,sessions);\n    }\n\n    /**\n     * find the most recent snapshot in the database.\n     * @return the file containing the most recent snapshot\n     */\n    public File findMostRecentSnapshot() throws IOException {\n        List<File> files = findNValidSnapshots(1);\n        if (files.size() == 0) {\n            return null;\n        }\n        return files.get(0);\n    }\n    \n    /**\n     * find the last (maybe) valid n snapshots. this does some \n     * minor checks on the validity of the snapshots. It just\n     * checks for / at the end of the snapshot. This does\n     * not mean that the snapshot is truly valid but is\n     * valid with a high probability. also, the most recent \n     * will be first on the list. \n     * @param n the number of most recent snapshots\n     * @return the last n snapshots (the number might be\n     * less than n in case enough snapshots are not available).\n     * @throws IOException\n     */\n    private List<File> findNValidSnapshots(int n) throws IOException {\n        List<File> files = Util.sortDataDir(snapDir.listFiles(), SNAPSHOT_FILE_PREFIX, false);\n        int count = 0;\n        List<File> list = new ArrayList<File>();\n        for (File f : files) {\n            // we should catch the exceptions\n            // from the valid snapshot and continue\n            // until we find a valid one\n            try {\n                if (Util.isValidSnapshot(f)) {\n                    list.add(f);\n                    count++;\n                    if (count == n) {\n                        break;\n                    }\n                }\n            } catch (IOException e) {\n                LOG.info(\"invalid snapshot \" + f, e);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * find the last n snapshots. this does not have\n     * any checks if the snapshot might be valid or not\n     * @param the number of most recent snapshots\n     * @return the last n snapshots\n     * @throws IOException\n     */\n    public List<File> findNRecentSnapshots(int n) throws IOException {\n        List<File> files = Util.sortDataDir(snapDir.listFiles(), SNAPSHOT_FILE_PREFIX, false);\n        int count = 0;\n        List<File> list = new ArrayList<File>();\n        for (File f: files) {\n            if (count == n)\n                break;\n            if (Util.getZxidFromName(f.getName(), SNAPSHOT_FILE_PREFIX) != -1) {\n                count++;\n                list.add(f);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * serialize the datatree and sessions\n     * @param dt the datatree to be serialized\n     * @param sessions the sessions to be serialized\n     * @param oa the output archive to serialize into\n     * @param header the header of this snapshot\n     * @throws IOException\n     */\n    protected void serialize(DataTree dt,Map<Long, Integer> sessions,\n            OutputArchive oa, FileHeader header) throws IOException {\n        // this is really a programmatic error and not something that can\n        // happen at runtime\n        if(header==null)\n            throw new IllegalStateException(\n                    \"Snapshot's not open for writing: uninitialized header\");\n        header.serialize(oa, \"fileheader\");\n        SerializeUtils.serializeSnapshot(dt,oa,sessions);\n    }\n\n    /**\n     * serialize the datatree and session into the file snapshot\n     * @param dt the datatree to be serialized\n     * @param sessions the sessions to be serialized\n     * @param snapShot the file to store snapshot into\n     */\n    public synchronized void serialize(DataTree dt, Map<Long, Integer> sessions, File snapShot)\n            throws IOException {\n        if (!close) {\n            OutputStream sessOS = new BufferedOutputStream(new FileOutputStream(snapShot));\n            CheckedOutputStream crcOut = new CheckedOutputStream(sessOS, new Adler32());\n            //CheckedOutputStream cout = new CheckedOutputStream()\n            OutputArchive oa = BinaryOutputArchive.getArchive(crcOut);\n            FileHeader header = new FileHeader(SNAP_MAGIC, VERSION, dbId);\n            serialize(dt,sessions,oa, header);\n            long val = crcOut.getChecksum().getValue();\n            oa.writeLong(val, \"val\");\n            oa.writeString(\"/\", \"path\");\n            sessOS.flush();\n            crcOut.close();\n            sessOS.close();\n        }\n    }\n\n    /**\n     * synchronized close just so that if serialize is in place\n     * the close operation will block and will wait till serialize\n     * is done and will set the close flag\n     */\n    @Override\n    public synchronized void close() throws IOException {\n        close = true;\n    }\n\n }\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/FileTxnLog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.persistence;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.zip.Adler32;\nimport java.util.zip.Checksum;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class implements the TxnLog interface. It provides api's\n * to access the txnlogs and add entries to it.\n * <p>\n * The format of a Transactional log is as follows:\n * <blockquote><pre>\n * LogFile:\n *     FileHeader TxnList ZeroPad\n * \n * FileHeader: {\n *     magic 4bytes (ZKLG)\n *     version 4bytes\n *     dbid 8bytes\n *   }\n * \n * TxnList:\n *     Txn || Txn TxnList\n *     \n * Txn:\n *     checksum Txnlen TxnHeader Record 0x42\n * \n * checksum: 8bytes Adler32 is currently used\n *   calculated across payload -- Txnlen, TxnHeader, Record and 0x42\n * \n * Txnlen:\n *     len 4bytes\n * \n * TxnHeader: {\n *     sessionid 8bytes\n *     cxid 4bytes\n *     zxid 8bytes\n *     time 8bytes\n *     type 4bytes\n *   }\n *     \n * Record:\n *     See Jute definition file for details on the various record types\n *      \n * ZeroPad:\n *     0 padded to EOF (filled during preallocation stage)\n * </pre></blockquote> \n */\npublic class FileTxnLog implements TxnLog {\n    private static final Logger LOG;\n\n    static long preAllocSize =  65536 * 1024;\n    private static final ByteBuffer fill = ByteBuffer.allocateDirect(1);\n\n    public final static int TXNLOG_MAGIC =\n        ByteBuffer.wrap(\"ZKLG\".getBytes()).getInt();\n\n    public final static int VERSION = 2;\n\n    public static final String LOG_FILE_PREFIX = \"log\";\n\n    /** Maximum time we allow for elapsed fsync before WARNing */\n    private final static long fsyncWarningThresholdMS;\n\n    static {\n        LOG = LoggerFactory.getLogger(FileTxnLog.class);\n\n        String size = System.getProperty(\"zookeeper.preAllocSize\");\n        if (size != null) {\n            try {\n                preAllocSize = Long.parseLong(size) * 1024;\n            } catch (NumberFormatException e) {\n                LOG.warn(size + \" is not a valid value for preAllocSize\");\n            }\n        }\n        /** Local variable to read fsync.warningthresholdms into */\n        Long fsyncWarningThreshold;\n        if ((fsyncWarningThreshold = Long.getLong(\"zookeeper.fsync.warningthresholdms\")) == null)\n            fsyncWarningThreshold = Long.getLong(\"fsync.warningthresholdms\", 1000);\n        fsyncWarningThresholdMS = fsyncWarningThreshold;\n    }\n\n    long lastZxidSeen;\n    volatile BufferedOutputStream logStream = null;\n    volatile OutputArchive oa;\n    volatile FileOutputStream fos = null;\n\n    File logDir;\n    private final boolean forceSync = !System.getProperty(\"zookeeper.forceSync\", \"yes\").equals(\"no\");;\n    long dbId;\n    private LinkedList<FileOutputStream> streamsToFlush =\n        new LinkedList<FileOutputStream>();\n    long currentSize;\n    File logFileWrite = null;\n\n    /**\n     * constructor for FileTxnLog. Take the directory\n     * where the txnlogs are stored\n     * @param logDir the directory where the txnlogs are stored\n     */\n    public FileTxnLog(File logDir) {\n        this.logDir = logDir;\n    }\n\n    /**\n     * method to allow setting preallocate size\n     * of log file to pad the file.\n     * @param size the size to set to in bytes\n     */\n    public static void setPreallocSize(long size) {\n        preAllocSize = size;\n    }\n\n    /**\n     * creates a checksum alogrithm to be used\n     * @return the checksum used for this txnlog\n     */\n    protected Checksum makeChecksumAlgorithm(){\n        return new Adler32();\n    }\n\n\n    /**\n     * rollover the current log file to a new one.\n     * @throws IOException\n     */\n    public synchronized void rollLog() throws IOException {\n        if (logStream != null) {\n            this.logStream.flush();\n            this.logStream = null;\n            oa = null;\n        }\n    }\n\n    /**\n     * close all the open file handles\n     * @throws IOException\n     */\n    public synchronized void close() throws IOException {\n        if (logStream != null) {\n            logStream.close();\n        }\n        for (FileOutputStream log : streamsToFlush) {\n            log.close();\n        }\n    }\n    \n    /**\n     * append an entry to the transaction log\n     * @param hdr the header of the transaction\n     * @param txn the transaction part of the entry\n     * returns true iff something appended, otw false \n     */\n    public synchronized boolean append(TxnHeader hdr, Record txn)\n        throws IOException\n    {\n        if (hdr == null) {\n            return false;\n        }\n\n        if (hdr.getZxid() <= lastZxidSeen) {\n            LOG.warn(\"Current zxid \" + hdr.getZxid()\n                    + \" is <= \" + lastZxidSeen + \" for \"\n                    + hdr.getType());\n        } else {\n            lastZxidSeen = hdr.getZxid();\n        }\n\n        if (logStream==null) {\n           if(LOG.isInfoEnabled()){\n                LOG.info(\"Creating new log file: \" + Util.makeLogName(hdr.getZxid()));\n           }\n\n            logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));\n            fos = new FileOutputStream(logFileWrite);\n            logStream=new BufferedOutputStream(fos);\n            oa = BinaryOutputArchive.getArchive(logStream);\n            FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);\n            fhdr.serialize(oa, \"fileheader\");\n            // Make sure that the magic number is written before padding.\n            logStream.flush();\n            currentSize = fos.getChannel().position();\n            streamsToFlush.add(fos);\n        }\n        currentSize = padFile(fos.getChannel());\n        byte[] buf = Util.marshallTxnEntry(hdr, txn);\n        if (buf == null || buf.length == 0) {\n            throw new IOException(\"Faulty serialization for header \" +\n                    \"and txn\");\n        }\n        Checksum crc = makeChecksumAlgorithm();\n        crc.update(buf, 0, buf.length);\n        oa.writeLong(crc.getValue(), \"txnEntryCRC\");\n        Util.writeTxnBytes(oa, buf);\n\n        return true;\n    }\n\n    /**\n     * pad the current file to increase its size to the next multiple of preAllocSize greater than the current size and position\n     * @param fileChannel the fileChannel of the file to be padded\n     * @throws IOException\n     */\n    private long padFile(FileChannel fileChannel) throws IOException {\n        long newFileSize = calculateFileSizeWithPadding(fileChannel.position(), currentSize, preAllocSize);\n        if (currentSize != newFileSize) {\n            fileChannel.write((ByteBuffer) fill.position(0), newFileSize - fill.remaining());\n            currentSize = newFileSize;\n        }\n        return currentSize;\n    }\n\n    /**\n     * Calculates a new file size with padding. We only return a new size if\n     * the current file position is sufficiently close (less than 4K) to end of\n     * file and preAllocSize is > 0.\n     *\n     * @param position the point in the file we have written to\n     * @param fileSize application keeps track of the current file size\n     * @param preAllocSize how many bytes to pad\n     * @return the new file size. It can be the same as fileSize if no\n     * padding was done.\n     * @throws IOException\n     */\n    // VisibleForTesting\n    public static long calculateFileSizeWithPadding(long position, long fileSize, long preAllocSize) {\n        // If preAllocSize is positive and we are within 4KB of the known end of the file calculate a new file size\n        if (preAllocSize > 0 && position + 4096 >= fileSize) {\n            // If we have written more than we have previously preallocated we need to make sure the new\n            // file size is larger than what we already have\n            if (position > fileSize){\n                fileSize = position + preAllocSize;\n                fileSize -= fileSize % preAllocSize;\n            } else {\n                fileSize += preAllocSize;\n            }\n        }\n\n        return fileSize;\n    }\n\n    /**\n     * Find the log file that starts at, or just before, the snapshot. Return\n     * this and all subsequent logs. Results are ordered by zxid of file,\n     * ascending order.\n     * @param logDirList array of files\n     * @param snapshotZxid return files at, or before this zxid\n     * @return\n     */\n    public static File[] getLogFiles(File[] logDirList,long snapshotZxid) {\n        List<File> files = Util.sortDataDir(logDirList, LOG_FILE_PREFIX, true);\n        long logZxid = 0;\n        // Find the log file that starts before or at the same time as the\n        // zxid of the snapshot\n        for (File f : files) {\n            long fzxid = Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX);\n            if (fzxid > snapshotZxid) {\n                continue;\n            }\n            // the files\n            // are sorted with zxid's\n            if (fzxid > logZxid) {\n                logZxid = fzxid;\n            }\n        }\n        List<File> v=new ArrayList<File>(5);\n        for (File f : files) {\n            long fzxid = Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX);\n            if (fzxid < logZxid) {\n                continue;\n            }\n            v.add(f);\n        }\n        return v.toArray(new File[0]);\n\n    }\n\n    /**\n     * get the last zxid that was logged in the transaction logs\n     * @return the last zxid logged in the transaction logs\n     */\n    public long getLastLoggedZxid() {\n        File[] files = getLogFiles(logDir.listFiles(), 0);\n        long maxLog=files.length>0?\n                Util.getZxidFromName(files[files.length-1].getName(),LOG_FILE_PREFIX):-1;\n\n        // if a log file is more recent we must scan it to find\n        // the highest zxid\n        long zxid = maxLog;\n        TxnIterator itr = null;\n        try {\n            FileTxnLog txn = new FileTxnLog(logDir);\n            itr = txn.read(maxLog);\n            while (true) {\n                if(!itr.next())\n                    break;\n                TxnHeader hdr = itr.getHeader();\n                zxid = hdr.getZxid();\n            }\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected exception\", e);\n        } finally {\n            close(itr);\n        }\n        return zxid;\n    }\n\n    private void close(TxnIterator itr) {\n        if (itr != null) {\n            try {\n                itr.close();\n            } catch (IOException ioe) {\n                LOG.warn(\"Error closing file iterator\", ioe);\n            }\n        }\n    }\n\n    /**\n     * commit the logs. make sure that evertyhing hits the\n     * disk\n     */\n    public synchronized void commit() throws IOException {\n        if (logStream != null) {\n            logStream.flush();\n        }\n        for (FileOutputStream log : streamsToFlush) {\n            log.flush();\n            if (forceSync) {\n                long startSyncNS = System.nanoTime();\n\n                log.getChannel().force(false);\n\n                long syncElapsedMS =\n                    TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startSyncNS);\n                if (syncElapsedMS > fsyncWarningThresholdMS) {\n                    LOG.warn(\"fsync-ing the write ahead log in \"\n                            + Thread.currentThread().getName()\n                            + \" took \" + syncElapsedMS\n                            + \"ms which will adversely effect operation latency. \"\n                            + \"See the ZooKeeper troubleshooting guide\");\n                }\n            }\n        }\n        while (streamsToFlush.size() > 1) {\n            streamsToFlush.removeFirst().close();\n        }\n    }\n\n    /**\n     * start reading all the transactions from the given zxid\n     * @param zxid the zxid to start reading transactions from\n     * @return returns an iterator to iterate through the transaction\n     * logs\n     */\n    public TxnIterator read(long zxid) throws IOException {\n        return new FileTxnIterator(logDir, zxid);\n    }\n\n    /**\n     * truncate the current transaction logs\n     * @param zxid the zxid to truncate the logs to\n     * @return true if successful false if not\n     */\n    public boolean truncate(long zxid) throws IOException {\n        FileTxnIterator itr = null;\n        try {\n            itr = new FileTxnIterator(this.logDir, zxid);\n            PositionInputStream input = itr.inputStream;\n            if(input == null) {\n                throw new IOException(\"No log files found to truncate! This could \" +\n                        \"happen if you still have snapshots from an old setup or \" +\n                        \"log files were deleted accidentally or dataLogDir was changed in zoo.cfg.\");\n            }\n            long pos = input.getPosition();\n            // now, truncate at the current position\n            RandomAccessFile raf = new RandomAccessFile(itr.logFile, \"rw\");\n            raf.setLength(pos);\n            raf.close();\n            while (itr.goToNextLog()) {\n                if (!itr.logFile.delete()) {\n                    LOG.warn(\"Unable to truncate {}\", itr.logFile);\n                }\n            }\n        } finally {\n            close(itr);\n        }\n        return true;\n    }\n\n    /**\n     * read the header of the transaction file\n     * @param file the transaction file to read\n     * @return header that was read fomr the file\n     * @throws IOException\n     */\n    private static FileHeader readHeader(File file) throws IOException {\n        InputStream is =null;\n        try {\n            is = new BufferedInputStream(new FileInputStream(file));\n            InputArchive ia=BinaryInputArchive.getArchive(is);\n            FileHeader hdr = new FileHeader();\n            hdr.deserialize(ia, \"fileheader\");\n            return hdr;\n         } finally {\n             try {\n                 if (is != null) is.close();\n             } catch (IOException e) {\n                 LOG.warn(\"Ignoring exception during close\", e);\n             }\n         }\n    }\n\n    /**\n     * the dbid of this transaction database\n     * @return the dbid of this database\n     */\n    public long getDbId() throws IOException {\n        FileTxnIterator itr = new FileTxnIterator(logDir, 0);\n        FileHeader fh=readHeader(itr.logFile);\n        itr.close();\n        if(fh==null)\n            throw new IOException(\"Unsupported Format.\");\n        return fh.getDbid();\n    }\n\n    /**\n     * the forceSync value. true if forceSync is enabled, false otherwise.\n     * @return the forceSync value\n     */\n    public boolean isForceSync() {\n        return forceSync;\n    }\n\n    /**\n     * a class that keeps track of the position \n     * in the input stream. The position points to offset\n     * that has been consumed by the applications. It can \n     * wrap buffered input streams to provide the right offset \n     * for the application.\n     */\n    static class PositionInputStream extends FilterInputStream {\n        long position;\n        protected PositionInputStream(InputStream in) {\n            super(in);\n            position = 0;\n        }\n        \n        @Override\n        public int read() throws IOException {\n            int rc = super.read();\n            if (rc > -1) {\n                position++;\n            }\n            return rc;\n        }\n\n        public int read(byte[] b) throws IOException {\n            int rc = super.read(b);\n            if (rc > 0) {\n                position += rc;\n            }\n            return rc;            \n        }\n        \n        @Override\n        public int read(byte[] b, int off, int len) throws IOException {\n            int rc = super.read(b, off, len);\n            if (rc > 0) {\n                position += rc;\n            }\n            return rc;\n        }\n        \n        @Override\n        public long skip(long n) throws IOException {\n            long rc = super.skip(n);\n            if (rc > 0) {\n                position += rc;\n            }\n            return rc;\n        }\n        public long getPosition() {\n            return position;\n        }\n\n        @Override\n        public boolean markSupported() {\n            return false;\n        }\n\n        @Override\n        public void mark(int readLimit) {\n            throw new UnsupportedOperationException(\"mark\");\n        }\n\n        @Override\n        public void reset() {\n            throw new UnsupportedOperationException(\"reset\");\n        }\n    }\n    \n    /**\n     * this class implements the txnlog iterator interface\n     * which is used for reading the transaction logs\n     */\n    public static class FileTxnIterator implements TxnLog.TxnIterator {\n        File logDir;\n        long zxid;\n        TxnHeader hdr;\n        Record record;\n        File logFile;\n        InputArchive ia;\n        static final String CRC_ERROR=\"CRC check failed\";\n       \n        PositionInputStream inputStream=null;\n        //stored files is the list of files greater than\n        //the zxid we are looking for.\n        private ArrayList<File> storedFiles;\n\n        /**\n         * create an iterator over a transaction database directory\n         * @param logDir the transaction database directory\n         * @param zxid the zxid to start reading from\n         * @throws IOException\n         */\n        public FileTxnIterator(File logDir, long zxid) throws IOException {\n          this.logDir = logDir;\n          this.zxid = zxid;\n          init();\n        }\n\n        /**\n         * initialize to the zxid specified\n         * this is inclusive of the zxid\n         * @throws IOException\n         */\n        void init() throws IOException {\n            storedFiles = new ArrayList<File>();\n            List<File> files = Util.sortDataDir(FileTxnLog.getLogFiles(logDir.listFiles(), 0), LOG_FILE_PREFIX, false);\n            for (File f: files) {\n                if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) >= zxid) {\n                    storedFiles.add(f);\n                }\n                // add the last logfile that is less than the zxid\n                else if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) < zxid) {\n                    storedFiles.add(f);\n                    break;\n                }\n            }\n            goToNextLog();\n            if (!next())\n                return;\n            while (hdr.getZxid() < zxid) {\n                if (!next())\n                    return;\n            }\n        }\n\n        /**\n         * go to the next logfile\n         * @return true if there is one and false if there is no\n         * new file to be read\n         * @throws IOException\n         */\n        private boolean goToNextLog() throws IOException {\n            if (storedFiles.size() > 0) {\n                this.logFile = storedFiles.remove(storedFiles.size()-1);\n                ia = createInputArchive(this.logFile);\n                return true;\n            }\n            return false;\n        }\n\n        /**\n         * read the header from the inputarchive\n         * @param ia the inputarchive to be read from\n         * @param is the inputstream\n         * @throws IOException\n         */\n        protected void inStreamCreated(InputArchive ia, InputStream is)\n            throws IOException{\n            FileHeader header= new FileHeader();\n            header.deserialize(ia, \"fileheader\");\n            if (header.getMagic() != FileTxnLog.TXNLOG_MAGIC) {\n                throw new IOException(\"Transaction log: \" + this.logFile + \" has invalid magic number \" \n                        + header.getMagic()\n                        + \" != \" + FileTxnLog.TXNLOG_MAGIC);\n            }\n        }\n\n        /**\n         * Invoked to indicate that the input stream has been created.\n         * @param ia input archive\n         * @param is file input stream associated with the input archive.\n         * @throws IOException\n         **/\n        protected InputArchive createInputArchive(File logFile) throws IOException {\n            if(inputStream==null){\n                inputStream= new PositionInputStream(new BufferedInputStream(new FileInputStream(logFile)));\n                LOG.debug(\"Created new input stream \" + logFile);\n                ia  = BinaryInputArchive.getArchive(inputStream);\n                inStreamCreated(ia,inputStream);\n                LOG.debug(\"Created new input archive \" + logFile);\n            }\n            return ia;\n        }\n\n        /**\n         * create a checksum algorithm\n         * @return the checksum algorithm\n         */\n        protected Checksum makeChecksumAlgorithm(){\n            return new Adler32();\n        }\n\n        /**\n         * the iterator that moves to the next transaction\n         * @return true if there is more transactions to be read\n         * false if not.\n         */\n        public boolean next() throws IOException {\n            if (ia == null) {\n                return false;\n            }\n            try {\n                long crcValue = ia.readLong(\"crcvalue\");\n                byte[] bytes = Util.readTxnBytes(ia);\n                // Since we preallocate, we define EOF to be an\n                if (bytes == null || bytes.length==0) {\n                    throw new EOFException(\"Failed to read \" + logFile);\n                }\n                // EOF or corrupted record\n                // validate CRC\n                Checksum crc = makeChecksumAlgorithm();\n                crc.update(bytes, 0, bytes.length);\n                if (crcValue != crc.getValue())\n                    throw new IOException(CRC_ERROR);\n                hdr = new TxnHeader();\n                record = SerializeUtils.deserializeTxn(bytes, hdr);\n            } catch (EOFException e) {\n                LOG.debug(\"EOF excepton \" + e);\n                inputStream.close();\n                inputStream = null;\n                ia = null;\n                hdr = null;\n                // this means that the file has ended\n                // we should go to the next file\n                if (!goToNextLog()) {\n                    return false;\n                }\n                // if we went to the next log file, we should call next() again\n                return next();\n            } catch (IOException e) {\n                inputStream.close();\n                throw e;\n            }\n            return true;\n        }\n\n        /**\n         * reutrn the current header\n         * @return the current header that\n         * is read\n         */\n        public TxnHeader getHeader() {\n            return hdr;\n        }\n\n        /**\n         * return the current transaction\n         * @return the current transaction\n         * that is read\n         */\n        public Record getTxn() {\n            return record;\n        }\n\n        /**\n         * close the iterator\n         * and release the resources.\n         */\n        public void close() throws IOException {\n            if (inputStream != null) {\n                inputStream.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/FileTxnSnapLog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\n\nimport java.io.File;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.DataTree.ProcessTxnResult;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.persistence.TxnLog.TxnIterator;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This is a helper class \n * above the implementations \n * of txnlog and snapshot \n * classes\n */\npublic class FileTxnSnapLog {\n    //the direcotry containing the \n    //the transaction logs\n    private final File dataDir;\n    //the directory containing the\n    //the snapshot directory\n    private final File snapDir;\n    private TxnLog txnLog;\n    private SnapShot snapLog;\n    public final static int VERSION = 2;\n    public final static String version = \"version-\";\n    \n    private static final Logger LOG = LoggerFactory.getLogger(FileTxnSnapLog.class);\n    \n    /**\n     * This listener helps\n     * the external apis calling\n     * restore to gather information\n     * while the data is being \n     * restored.\n     */\n    public interface PlayBackListener {\n        void onTxnLoaded(TxnHeader hdr, Record rec);\n    }\n    \n    /**\n     * the constructor which takes the datadir and \n     * snapdir.\n     * @param dataDir the trasaction directory\n     * @param snapDir the snapshot directory\n     */\n    public FileTxnSnapLog(File dataDir, File snapDir) throws IOException {\n        LOG.debug(\"Opening datadir:{} snapDir:{}\", dataDir, snapDir);\n\n        this.dataDir = new File(dataDir, version + VERSION);\n        this.snapDir = new File(snapDir, version + VERSION);\n        if (!this.dataDir.exists()) {\n            if (!this.dataDir.mkdirs()) {\n                throw new IOException(\"Unable to create data directory \"\n                        + this.dataDir);\n            }\n        }\n        if (!this.dataDir.canWrite()) {\n            throw new IOException(\"Cannot write to data directory \" + this.dataDir);\n        }\n\n        if (!this.snapDir.exists()) {\n            if (!this.snapDir.mkdirs()) {\n                throw new IOException(\"Unable to create snap directory \"\n                        + this.snapDir);\n            }\n        }\n        if (!this.snapDir.canWrite()) {\n            throw new IOException(\"Cannot write to snap directory \" + this.snapDir);\n        }\n\n        // check content of transaction log and snapshot dirs if they are two different directories\n        // See ZOOKEEPER-2967 for more details\n        if(!this.dataDir.getPath().equals(this.snapDir.getPath())){\n            checkLogDir();\n            checkSnapDir();\n        }\n\n        txnLog = new FileTxnLog(this.dataDir);\n        snapLog = new FileSnap(this.snapDir);\n    }\n\n    private void checkLogDir() throws LogDirContentCheckException {\n        File[] files = this.dataDir.listFiles(new FilenameFilter() {\n            @Override\n            public boolean accept(File dir, String name) {\n                return Util.isSnapshotFileName(name);\n            }\n        });\n        if (files != null && files.length > 0) {\n            throw new LogDirContentCheckException(\"Log directory has snapshot files. Check if dataLogDir and dataDir configuration is correct.\");\n        }\n    }\n\n    private void checkSnapDir() throws SnapDirContentCheckException {\n        File[] files = this.snapDir.listFiles(new FilenameFilter() {\n            @Override\n            public boolean accept(File dir, String name) {\n                return Util.isLogFileName(name);\n            }\n        });\n        if (files != null && files.length > 0) {\n            throw new SnapDirContentCheckException(\"Snapshot directory has log files. Check if dataLogDir and dataDir configuration is correct.\");\n        }\n    }\n\n    /**\n     * get the datadir used by this filetxn\n     * snap log\n     * @return the data dir\n     */\n    public File getDataDir() {\n        return this.dataDir;\n    }\n    \n    /**\n     * get the snap dir used by this \n     * filetxn snap log\n     * @return the snap dir\n     */\n    public File getSnapDir() {\n        return this.snapDir;\n    }\n    \n    /**\n     * this function restores the server \n     * database after reading from the \n     * snapshots and transaction logs\n     * @param dt the datatree to be restored\n     * @param sessions the sessions to be restored\n     * @param listener the playback listener to run on the \n     * database restoration\n     * @return the highest zxid restored\n     * @throws IOException\n     */\n    public long restore(DataTree dt, Map<Long, Integer> sessions, \n            PlayBackListener listener) throws IOException {\n        snapLog.deserialize(dt, sessions);\n        return fastForwardFromEdits(dt, sessions, listener);\n    }\n\n    /**\n     * This function will fast forward the server database to have the latest\n     * transactions in it.  This is the same as restore, but only reads from\n     * the transaction logs and not restores from a snapshot.\n     * @param dt the datatree to write transactions to.\n     * @param sessions the sessions to be restored.\n     * @param listener the playback listener to run on the\n     * database transactions.\n     * @return the highest zxid restored.\n     * @throws IOException\n     */\n    public long fastForwardFromEdits(DataTree dt, Map<Long, Integer> sessions,\n                                     PlayBackListener listener) throws IOException {\n        FileTxnLog txnLog = new FileTxnLog(dataDir);\n        TxnIterator itr = txnLog.read(dt.lastProcessedZxid+1);\n        long highestZxid = dt.lastProcessedZxid;\n        TxnHeader hdr;\n        try {\n            while (true) {\n                // iterator points to \n                // the first valid txn when initialized\n                hdr = itr.getHeader();\n                if (hdr == null) {\n                    //empty logs \n                    return dt.lastProcessedZxid;\n                }\n                if (hdr.getZxid() < highestZxid && highestZxid != 0) {\n                    LOG.error(\"{}(higestZxid) > {}(next log) for type {}\",\n                            new Object[] { highestZxid, hdr.getZxid(),\n                                    hdr.getType() });\n                } else {\n                    highestZxid = hdr.getZxid();\n                }\n                try {\n                    processTransaction(hdr,dt,sessions, itr.getTxn());\n                } catch(KeeperException.NoNodeException e) {\n                   throw new IOException(\"Failed to process transaction type: \" +\n                         hdr.getType() + \" error: \" + e.getMessage(), e);\n                }\n                listener.onTxnLoaded(hdr, itr.getTxn());\n                if (!itr.next()) \n                    break;\n            }\n        } finally {\n            if (itr != null) {\n                itr.close();\n            }\n        }\n        return highestZxid;\n    }\n    \n    /**\n     * process the transaction on the datatree\n     * @param hdr the hdr of the transaction\n     * @param dt the datatree to apply transaction to\n     * @param sessions the sessions to be restored\n     * @param txn the transaction to be applied\n     */\n    public void processTransaction(TxnHeader hdr,DataTree dt,\n            Map<Long, Integer> sessions, Record txn)\n        throws KeeperException.NoNodeException {\n        ProcessTxnResult rc;\n        switch (hdr.getType()) {\n        case OpCode.createSession:\n            sessions.put(hdr.getClientId(),\n                    ((CreateSessionTxn) txn).getTimeOut());\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG,ZooTrace.SESSION_TRACE_MASK,\n                        \"playLog --- create session in log: 0x\"\n                                + Long.toHexString(hdr.getClientId())\n                                + \" with timeout: \"\n                                + ((CreateSessionTxn) txn).getTimeOut());\n            }\n            // give dataTree a chance to sync its lastProcessedZxid\n            rc = dt.processTxn(hdr, txn);\n            break;\n        case OpCode.closeSession:\n            sessions.remove(hdr.getClientId());\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG,ZooTrace.SESSION_TRACE_MASK,\n                        \"playLog --- close session in log: 0x\"\n                                + Long.toHexString(hdr.getClientId()));\n            }\n            rc = dt.processTxn(hdr, txn);\n            break;\n        default:\n            rc = dt.processTxn(hdr, txn);\n        }\n\n        /**\n         * Snapshots are lazily created. So when a snapshot is in progress,\n         * there is a chance for later transactions to make into the\n         * snapshot. Then when the snapshot is restored, NONODE/NODEEXISTS\n         * errors could occur. It should be safe to ignore these.\n         */\n        if (rc.err != Code.OK.intValue()) {\n            LOG.debug(\"Ignoring processTxn failure hdr:\" + hdr.getType()\n                    + \", error: \" + rc.err + \", path: \" + rc.path);\n        }\n    }\n\n    /**\n     * the last logged zxid on the transaction logs\n     * @return the last logged zxid\n     */\n    public long getLastLoggedZxid() {\n        FileTxnLog txnLog = new FileTxnLog(dataDir);\n        return txnLog.getLastLoggedZxid();\n    }\n\n    /**\n     * save the datatree and the sessions into a snapshot\n     * @param dataTree the datatree to be serialized onto disk\n     * @param sessionsWithTimeouts the sesssion timeouts to be\n     * serialized onto disk\n     * @throws IOException\n     */\n    public void save(DataTree dataTree,\n            ConcurrentHashMap<Long, Integer> sessionsWithTimeouts)\n        throws IOException {\n        long lastZxid = dataTree.lastProcessedZxid;\n        File snapshotFile = new File(snapDir, Util.makeSnapshotName(lastZxid));\n        LOG.info(\"Snapshotting: 0x{} to {}\", Long.toHexString(lastZxid),\n                snapshotFile);\n        snapLog.serialize(dataTree, sessionsWithTimeouts, snapshotFile);\n        \n    }\n\n    /**\n     * truncate the transaction logs the zxid\n     * specified\n     * @param zxid the zxid to truncate the logs to\n     * @return true if able to truncate the log, false if not\n     * @throws IOException\n     */\n    public boolean truncateLog(long zxid) throws IOException {\n        // close the existing txnLog and snapLog\n        close();\n\n        // truncate it\n        FileTxnLog truncLog = new FileTxnLog(dataDir);\n        boolean truncated = truncLog.truncate(zxid);\n        truncLog.close();\n\n        // re-open the txnLog and snapLog\n        // I'd rather just close/reopen this object itself, however that \n        // would have a big impact outside ZKDatabase as there are other\n        // objects holding a reference to this object.\n        txnLog = new FileTxnLog(dataDir);\n        snapLog = new FileSnap(snapDir);\n\n        return truncated;\n    }\n    \n    /**\n     * the most recent snapshot in the snapshot\n     * directory\n     * @return the file that contains the most \n     * recent snapshot\n     * @throws IOException\n     */\n    public File findMostRecentSnapshot() throws IOException {\n        FileSnap snaplog = new FileSnap(snapDir);\n        return snaplog.findMostRecentSnapshot();\n    }\n    \n    /**\n     * the n most recent snapshots\n     * @param n the number of recent snapshots\n     * @return the list of n most recent snapshots, with\n     * the most recent in front\n     * @throws IOException\n     */\n    public List<File> findNRecentSnapshots(int n) throws IOException {\n        FileSnap snaplog = new FileSnap(snapDir);\n        return snaplog.findNRecentSnapshots(n);\n    }\n\n    /**\n     * get the snapshot logs which may contain transactions newer than the given zxid.\n     * This includes logs with starting zxid greater than given zxid, as well as the\n     * newest transaction log with starting zxid less than given zxid.  The latter log\n     * file may contain transactions beyond given zxid.\n     * @param zxid the zxid that contains logs greater than\n     * zxid\n     * @return\n     */\n    public File[] getSnapshotLogs(long zxid) {\n        return FileTxnLog.getLogFiles(dataDir.listFiles(), zxid);\n    }\n\n    /**\n     * append the request to the transaction logs\n     * @param si the request to be appended\n     * returns true iff something appended, otw false \n     * @throws IOException\n     */\n    public boolean append(Request si) throws IOException {\n        return txnLog.append(si.hdr, si.txn);\n    }\n\n    /**\n     * commit the transaction of logs\n     * @throws IOException\n     */\n    public void commit() throws IOException {\n        txnLog.commit();\n    }\n\n    /**\n     * roll the transaction logs\n     * @throws IOException \n     */\n    public void rollLog() throws IOException {\n        txnLog.rollLog();\n    }\n    \n    /**\n     * close the transaction log files\n     * @throws IOException\n     */\n    public void close() throws IOException {\n        txnLog.close();\n        snapLog.close();\n    }\n\n    @SuppressWarnings(\"serial\")\n    public static class DatadirException extends IOException {\n        public DatadirException(String msg) {\n            super(msg);\n        }\n        public DatadirException(String msg, Exception e) {\n            super(msg, e);\n        }\n    }\n\n    @SuppressWarnings(\"serial\")\n    public static class LogDirContentCheckException extends DatadirException {\n        public LogDirContentCheckException(String msg) {\n            super(msg);\n        }\n    }\n\n    @SuppressWarnings(\"serial\")\n    public static class SnapDirContentCheckException extends DatadirException {\n        public SnapDirContentCheckException(String msg) {\n            super(msg);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/SnapShot.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.apache.zookeeper.server.DataTree;\n\n/**\n * snapshot interface for the persistence layer.\n * implement this interface for implementing \n * snapshots.\n */\npublic interface SnapShot {\n    \n    /**\n     * deserialize a data tree from the last valid snapshot and \n     * return the last zxid that was deserialized\n     * @param dt the datatree to be deserialized into\n     * @param sessions the sessions to be deserialized into\n     * @return the last zxid that was deserialized from the snapshot\n     * @throws IOException\n     */\n    long deserialize(DataTree dt, Map<Long, Integer> sessions) \n        throws IOException;\n    \n    /**\n     * persist the datatree and the sessions into a persistence storage\n     * @param dt the datatree to be serialized\n     * @param sessions \n     * @throws IOException\n     */\n    void serialize(DataTree dt, Map<Long, Integer> sessions, \n            File name) \n        throws IOException;\n    \n    /**\n     * find the most recent snapshot file\n     * @return the most recent snapshot file\n     * @throws IOException\n     */\n    File findMostRecentSnapshot() throws IOException;\n    \n    /**\n     * free resources from this snapshot immediately\n     * @throws IOException\n     */\n    void close() throws IOException;\n} \n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/TxnLog.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\n\nimport java.io.IOException;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * Interface for reading transaction logs.\n *\n */\npublic interface TxnLog {\n    \n    /**\n     * roll the current\n     * log being appended to\n     * @throws IOException \n     */\n    void rollLog() throws IOException;\n    /**\n     * Append a request to the transaction log\n     * @param hdr the transaction header\n     * @param r the transaction itself\n     * returns true iff something appended, otw false \n     * @throws IOException\n     */\n    boolean append(TxnHeader hdr, Record r) throws IOException;\n\n    /**\n     * Start reading the transaction logs\n     * from a given zxid\n     * @param zxid\n     * @return returns an iterator to read the \n     * next transaction in the logs.\n     * @throws IOException\n     */\n    TxnIterator read(long zxid) throws IOException;\n    \n    /**\n     * the last zxid of the logged transactions.\n     * @return the last zxid of the logged transactions.\n     * @throws IOException\n     */\n    long getLastLoggedZxid() throws IOException;\n    \n    /**\n     * truncate the log to get in sync with the \n     * leader.\n     * @param zxid the zxid to truncate at.\n     * @throws IOException \n     */\n    boolean truncate(long zxid) throws IOException;\n    \n    /**\n     * the dbid for this transaction log. \n     * @return the dbid for this transaction log.\n     * @throws IOException\n     */\n    long getDbId() throws IOException;\n    \n    /**\n     * commmit the trasaction and make sure\n     * they are persisted\n     * @throws IOException\n     */\n    void commit() throws IOException;\n   \n    /** \n     * close the transactions logs\n     */\n    void close() throws IOException;\n    /**\n     * an iterating interface for reading \n     * transaction logs. \n     */\n    public interface TxnIterator {\n        /**\n         * return the transaction header.\n         * @return return the transaction header.\n         */\n        TxnHeader getHeader();\n        \n        /**\n         * return the transaction record.\n         * @return return the transaction record.\n         */\n        Record getTxn();\n     \n        /**\n         * go to the next transaction record.\n         * @throws IOException\n         */\n        boolean next() throws IOException;\n        \n        /**\n         * close files and release the \n         * resources\n         * @throws IOException\n         */\n        void close() throws IOException;\n    }\n}\n\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/persistence/Util.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.io.Serializable;\nimport java.net.URI;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * A collection of utility methods for dealing with file name parsing, \n * low level I/O file operations and marshalling/unmarshalling.\n */\npublic class Util {\n    private static final Logger LOG = LoggerFactory.getLogger(Util.class);\n    private static final String SNAP_DIR=\"snapDir\";\n    private static final String LOG_DIR=\"logDir\";\n    private static final String DB_FORMAT_CONV=\"dbFormatConversion\";\n    \n    public static String makeURIString(String dataDir, String dataLogDir, \n            String convPolicy){\n        String uri=\"file:\"+SNAP_DIR+\"=\"+dataDir+\";\"+LOG_DIR+\"=\"+dataLogDir;\n        if(convPolicy!=null)\n            uri+=\";\"+DB_FORMAT_CONV+\"=\"+convPolicy;\n        return uri.replace('\\\\', '/');\n    }\n    /**\n     * Given two directory files the method returns a well-formed \n     * logfile provider URI. This method is for backward compatibility with the\n     * existing code that only supports logfile persistence and expects these two\n     * parameters passed either on the command-line or in the configuration file.\n     * \n     * @param dataDir snapshot directory\n     * @param dataLogDir transaction log directory\n     * @return logfile provider URI\n     */\n    public static URI makeFileLoggerURL(File dataDir, File dataLogDir){\n        return URI.create(makeURIString(dataDir.getPath(),dataLogDir.getPath(),null));\n    }\n    \n    public static URI makeFileLoggerURL(File dataDir, File dataLogDir,String convPolicy){\n        return URI.create(makeURIString(dataDir.getPath(),dataLogDir.getPath(),convPolicy));\n    }\n\n    /**\n     * Creates a valid transaction log file name. \n     * \n     * @param zxid used as a file name suffix (extention)\n     * @return file name\n     */\n    public static String makeLogName(long zxid) {\n        return FileTxnLog.LOG_FILE_PREFIX + \".\" + Long.toHexString(zxid);\n    }\n\n    /**\n     * Creates a snapshot file name.\n     * \n     * @param zxid used as a suffix\n     * @return file name\n     */\n    public static String makeSnapshotName(long zxid) {\n        return FileSnap.SNAPSHOT_FILE_PREFIX + \".\" + Long.toHexString(zxid);\n    }\n    \n    /**\n     * Extracts snapshot directory property value from the container.\n     * \n     * @param props properties container\n     * @return file representing the snapshot directory\n     */\n    public static File getSnapDir(Properties props){\n        return new File(props.getProperty(SNAP_DIR));\n    }\n\n    /**\n     * Extracts transaction log directory property value from the container.\n     * \n     * @param props properties container\n     * @return file representing the txn log directory\n     */\n    public static File getLogDir(Properties props){\n        return new File(props.getProperty(LOG_DIR));\n    }\n    \n    /**\n     * Extracts the value of the dbFormatConversion attribute.\n     * \n     * @param props properties container\n     * @return value of the dbFormatConversion attribute\n     */\n    public static String getFormatConversionPolicy(Properties props){\n        return props.getProperty(DB_FORMAT_CONV);\n    }\n   \n    /**\n     * Extracts zxid from the file name. The file name should have been created\n     * using one of the {@link makeLogName} or {@link makeSnapshotName}.\n     * \n     * @param name the file name to parse\n     * @param prefix the file name prefix (snapshot or log)\n     * @return zxid\n     */\n    public static long getZxidFromName(String name, String prefix) {\n        long zxid = -1;\n        String nameParts[] = name.split(\"\\\\.\");\n        if (nameParts.length == 2 && nameParts[0].equals(prefix)) {\n            try {\n                zxid = Long.parseLong(nameParts[1], 16);\n            } catch (NumberFormatException e) {\n            }\n        }\n        return zxid;\n    }\n\n    /**\n     * Verifies that the file is a valid snapshot. Snapshot may be invalid if \n     * it's incomplete as in a situation when the server dies while in the process\n     * of storing a snapshot. Any file that is not a snapshot is also \n     * an invalid snapshot. \n     * \n     * @param f file to verify\n     * @return true if the snapshot is valid\n     * @throws IOException\n     */\n    public static boolean isValidSnapshot(File f) throws IOException {\n        if (f==null || Util.getZxidFromName(f.getName(), FileSnap.SNAPSHOT_FILE_PREFIX) == -1)\n            return false;\n\n        // Check for a valid snapshot\n        RandomAccessFile raf = new RandomAccessFile(f, \"r\");\n        try {\n            // including the header and the last / bytes\n            // the snapshot should be atleast 10 bytes\n            if (raf.length() < 10) {\n                return false;\n            }\n            raf.seek(raf.length() - 5);\n            byte bytes[] = new byte[5];\n            int readlen = 0;\n            int l;\n            while(readlen < 5 &&\n                  (l = raf.read(bytes, readlen, bytes.length - readlen)) >= 0) {\n                readlen += l;\n            }\n            if (readlen != bytes.length) {\n                LOG.info(\"Invalid snapshot \" + f\n                        + \" too short, len = \" + readlen);\n                return false;\n            }\n            ByteBuffer bb = ByteBuffer.wrap(bytes);\n            int len = bb.getInt();\n            byte b = bb.get();\n            if (len != 1 || b != '/') {\n                LOG.info(\"Invalid snapshot \" + f + \" len = \" + len\n                        + \" byte = \" + (b & 0xff));\n                return false;\n            }\n        } finally {\n            raf.close();\n        }\n\n        return true;\n    }\n\n    /**\n     * Reads a transaction entry from the input archive.\n     * @param ia archive to read from\n     * @return null if the entry is corrupted or EOF has been reached; a buffer\n     * (possible empty) containing serialized transaction record.\n     * @throws IOException\n     */\n    public static byte[] readTxnBytes(InputArchive ia) throws IOException {\n        try{\n            byte[] bytes = ia.readBuffer(\"txtEntry\");\n            // Since we preallocate, we define EOF to be an\n            // empty transaction\n            if (bytes.length == 0)\n                return bytes;\n            if (ia.readByte(\"EOF\") != 'B') {\n                LOG.error(\"Last transaction was partial.\");\n                return null;\n            }\n            return bytes;\n        }catch(EOFException e){}\n        return null;\n    }\n    \n\n    /**\n     * Serializes transaction header and transaction data into a byte buffer.\n     *  \n     * @param hdr transaction header\n     * @param txn transaction data\n     * @return serialized transaction record\n     * @throws IOException\n     */\n    public static byte[] marshallTxnEntry(TxnHeader hdr, Record txn)\n            throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        OutputArchive boa = BinaryOutputArchive.getArchive(baos);\n\n        hdr.serialize(boa, \"hdr\");\n        if (txn != null) {\n            txn.serialize(boa, \"txn\");\n        }\n        return baos.toByteArray();\n    }\n\n    /**\n     * Write the serialized transaction record to the output archive.\n     *  \n     * @param oa output archive\n     * @param bytes serialized trasnaction record\n     * @throws IOException\n     */\n    public static void writeTxnBytes(OutputArchive oa, byte[] bytes)\n            throws IOException {\n        oa.writeBuffer(bytes, \"txnEntry\");\n        oa.writeByte((byte) 0x42, \"EOR\"); // 'B'\n    }\n    \n    \n    /**\n     * Compare file file names of form \"prefix.version\". Sort order result\n     * returned in order of version.\n     */\n    private static class DataDirFileComparator\n        implements Comparator<File>, Serializable\n    {\n        private static final long serialVersionUID = -2648639884525140318L;\n\n        private String prefix;\n        private boolean ascending;\n        public DataDirFileComparator(String prefix, boolean ascending) {\n            this.prefix = prefix;\n            this.ascending = ascending;\n        }\n\n        public int compare(File o1, File o2) {\n            long z1 = Util.getZxidFromName(o1.getName(), prefix);\n            long z2 = Util.getZxidFromName(o2.getName(), prefix);\n            int result = z1 < z2 ? -1 : (z1 > z2 ? 1 : 0);\n            return ascending ? result : -result;\n        }\n    }\n    \n    /**\n     * Sort the list of files. Recency as determined by the version component\n     * of the file name.\n     *\n     * @param files array of files\n     * @param prefix files not matching this prefix are assumed to have a\n     * version = -1)\n     * @param ascending true sorted in ascending order, false results in\n     * descending order\n     * @return sorted input files\n     */\n    public static List<File> sortDataDir(File[] files, String prefix, boolean ascending)\n    {\n        if(files==null)\n            return new ArrayList<File>(0);\n        List<File> filelist = Arrays.asList(files);\n        Collections.sort(filelist, new DataDirFileComparator(prefix, ascending));\n        return filelist;\n    }\n\n    /**\n     * Returns true if fileName is a log file name.\n     *\n     * @param fileName\n     * @return\n     */\n    public static boolean isLogFileName(String fileName) {\n        return fileName.startsWith(FileTxnLog.LOG_FILE_PREFIX + \".\");\n    }\n\n    /**\n     * Returns true if fileName is a snapshot file name.\n     *\n     * @param fileName\n     * @return\n     */\n    public static boolean isSnapshotFileName(String fileName) {\n        return fileName.startsWith(FileSnap.SNAPSHOT_FILE_PREFIX + \".\");\n    }\n    \n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/AckRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\n\n\n/**\n * This is a very simple RequestProcessor that simply forwards a request from a\n * previous stage to the leader as an ACK.\n */\nclass AckRequestProcessor implements RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(AckRequestProcessor.class);\n    Leader leader;\n\n    AckRequestProcessor(Leader leader) {\n        this.leader = leader;\n    }\n\n    /**\n     * Forward the request as an ACK to the leader\n     */\n    public void processRequest(Request request) {\n        QuorumPeer self = leader.self;\n        if(self != null)\n            leader.processAck(self.getId(), request.zxid, null);\n        else\n            LOG.error(\"Null QuorumPeer\");\n    }\n\n    public void shutdown() {\n        // XXX No need to do anything\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/AuthFastLeaderElection.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetSocketAddress;\nimport java.net.SocketException;\nimport java.nio.ByteBuffer;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.Semaphore;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.Random;\n\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.quorum.Election;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\n\n/**\n * @deprecated This class has been deprecated as of release 3.4.0. \n */\n@Deprecated\npublic class AuthFastLeaderElection implements Election {\n    private static final Logger LOG = LoggerFactory.getLogger(AuthFastLeaderElection.class);\n\n    /* Sequence numbers for messages */\n    static int sequencer = 0;\n    static int maxTag = 0;\n\n    /*\n     * Determine how much time a process has to wait once it believes that it\n     * has reached the end of leader election.\n     */\n    static int finalizeWait = 100;\n\n    /*\n     * Challenge counter to avoid replay attacks\n     */\n\n    static int challengeCounter = 0;\n\n    /*\n     * Flag to determine whether to authenticate or not\n     */\n\n    private boolean authEnabled = false;\n\n    static public class Notification {\n        /*\n         * Proposed leader\n         */\n        long leader;\n\n        /*\n         * zxid of the proposed leader\n         */\n        long zxid;\n\n        /*\n         * Epoch\n         */\n        long epoch;\n\n        /*\n         * current state of sender\n         */\n        QuorumPeer.ServerState state;\n\n        /*\n         * Address of the sender\n         */\n        InetSocketAddress addr;\n    }\n\n    /*\n     * Messages to send, both Notifications and Acks\n     */\n    static public class ToSend {\n        static enum mType {\n            crequest, challenge, notification, ack\n        }\n\n        ToSend(mType type, long tag, long leader, long zxid, long epoch,\n                ServerState state, InetSocketAddress addr) {\n\n            switch (type) {\n            case crequest:\n                this.type = 0;\n                this.tag = tag;\n                this.leader = leader;\n                this.zxid = zxid;\n                this.epoch = epoch;\n                this.state = state;\n                this.addr = addr;\n\n                break;\n            case challenge:\n                this.type = 1;\n                this.tag = tag;\n                this.leader = leader;\n                this.zxid = zxid;\n                this.epoch = epoch;\n                this.state = state;\n                this.addr = addr;\n\n                break;\n            case notification:\n                this.type = 2;\n                this.leader = leader;\n                this.zxid = zxid;\n                this.epoch = epoch;\n                this.state = QuorumPeer.ServerState.LOOKING;\n                this.tag = tag;\n                this.addr = addr;\n\n                break;\n            case ack:\n                this.type = 3;\n                this.tag = tag;\n                this.leader = leader;\n                this.zxid = zxid;\n                this.epoch = epoch;\n                this.state = state;\n                this.addr = addr;\n\n                break;\n            default:\n                break;\n            }\n        }\n\n        /*\n         * Message type: 0 notification, 1 acknowledgement\n         */\n        int type;\n\n        /*\n         * Proposed leader in the case of notification\n         */\n        long leader;\n\n        /*\n         * id contains the tag for acks, and zxid for notifications\n         */\n        long zxid;\n\n        /*\n         * Epoch\n         */\n        long epoch;\n\n        /*\n         * Current state;\n         */\n        QuorumPeer.ServerState state;\n\n        /*\n         * Message tag\n         */\n        long tag;\n\n        InetSocketAddress addr;\n    }\n\n    LinkedBlockingQueue<ToSend> sendqueue;\n\n    LinkedBlockingQueue<Notification> recvqueue;\n\n    private class Messenger {\n\n        final DatagramSocket mySocket;\n        long lastProposedLeader;\n        long lastProposedZxid;\n        long lastEpoch;\n        final Set<Long> ackset;\n        final ConcurrentHashMap<Long, Long> challengeMap;\n        final ConcurrentHashMap<Long, Semaphore> challengeMutex;\n        final ConcurrentHashMap<Long, Semaphore> ackMutex;\n        final ConcurrentHashMap<InetSocketAddress, ConcurrentHashMap<Long, Long>> addrChallengeMap;\n\n        class WorkerReceiver implements Runnable {\n\n            DatagramSocket mySocket;\n            Messenger myMsg;\n\n            WorkerReceiver(DatagramSocket s, Messenger msg) {\n                mySocket = s;\n                myMsg = msg;\n            }\n\n            boolean saveChallenge(long tag, long challenge) {\n                Semaphore s = challengeMutex.get(tag);\n                if (s != null) {\n                        synchronized (Messenger.this) {\n                            challengeMap.put(tag, challenge);\n                            challengeMutex.remove(tag);\n                        }\n\n                \n                        s.release();\n                } else {\n                    LOG.error(\"No challenge mutex object\");\n                }\n                \n\n                return true;\n            }\n\n            public void run() {\n                byte responseBytes[] = new byte[48];\n                ByteBuffer responseBuffer = ByteBuffer.wrap(responseBytes);\n                DatagramPacket responsePacket = new DatagramPacket(\n                        responseBytes, responseBytes.length);\n                while (true) {\n                    // Sleeps on receive\n                    try {\n                        responseBuffer.clear();\n                        mySocket.receive(responsePacket);\n                    } catch (IOException e) {\n                        LOG.warn(\"Ignoring exception receiving\", e);\n                    }\n                    // Receive new message\n                    if (responsePacket.getLength() != responseBytes.length) {\n                        LOG.warn(\"Got a short response: \"\n                                + responsePacket.getLength() + \" \"\n                                + responsePacket.toString());\n                        continue;\n                    }\n                    responseBuffer.clear();\n                    int type = responseBuffer.getInt();\n                    if ((type > 3) || (type < 0)) {\n                        LOG.warn(\"Got bad Msg type: \" + type);\n                        continue;\n                    }\n                    long tag = responseBuffer.getLong();\n\n                    QuorumPeer.ServerState ackstate = QuorumPeer.ServerState.LOOKING;\n                    switch (responseBuffer.getInt()) {\n                    case 0:\n                        ackstate = QuorumPeer.ServerState.LOOKING;\n                        break;\n                    case 1:\n                        ackstate = QuorumPeer.ServerState.LEADING;\n                        break;\n                    case 2:\n                        ackstate = QuorumPeer.ServerState.FOLLOWING;\n                        break;\n                    }\n\n                    Vote current = self.getCurrentVote();\n\n                    switch (type) {\n                    case 0:\n                        // Receive challenge request\n                        ToSend c = new ToSend(ToSend.mType.challenge, tag,\n                                current.getId(), current.getZxid(),\n                                logicalclock, self.getPeerState(),\n                                (InetSocketAddress) responsePacket\n                                        .getSocketAddress());\n                        sendqueue.offer(c);\n                        break;\n                    case 1:\n                        // Receive challenge and store somewhere else\n                        long challenge = responseBuffer.getLong();\n                        saveChallenge(tag, challenge);\n\n                        break;\n                    case 2:\n                        Notification n = new Notification();\n                        n.leader = responseBuffer.getLong();\n                        n.zxid = responseBuffer.getLong();\n                        n.epoch = responseBuffer.getLong();\n                        n.state = ackstate;\n                        n.addr = (InetSocketAddress) responsePacket\n                                .getSocketAddress();\n\n                        if ((myMsg.lastEpoch <= n.epoch)\n                                && ((n.zxid > myMsg.lastProposedZxid) \n                                || ((n.zxid == myMsg.lastProposedZxid) \n                                && (n.leader > myMsg.lastProposedLeader)))) {\n                            myMsg.lastProposedZxid = n.zxid;\n                            myMsg.lastProposedLeader = n.leader;\n                            myMsg.lastEpoch = n.epoch;\n                        }\n\n                        long recChallenge;\n                        InetSocketAddress addr = (InetSocketAddress) responsePacket\n                                .getSocketAddress();\n                        if (authEnabled) {\n                            ConcurrentHashMap<Long, Long> tmpMap = addrChallengeMap.get(addr);\n                            if(tmpMap != null){\n                                if (tmpMap.get(tag) != null) {\n                                    recChallenge = responseBuffer.getLong();\n\n                                    if (tmpMap.get(tag) == recChallenge) {\n                                        recvqueue.offer(n);\n\n                                        ToSend a = new ToSend(ToSend.mType.ack,\n                                                tag, current.getId(),\n                                                current.getZxid(),\n                                                logicalclock, self.getPeerState(),\n                                                addr);\n\n                                        sendqueue.offer(a);\n                                    } else {\n                                        LOG.warn(\"Incorrect challenge: \"\n                                                + recChallenge + \", \"\n                                                + addrChallengeMap.toString());\n                                    }\n                                } else {\n                                    LOG.warn(\"No challenge for host: \" + addr\n                                            + \" \" + tag);\n                                }\n                            }\n                        } else {\n                            recvqueue.offer(n);\n\n                            ToSend a = new ToSend(ToSend.mType.ack, tag,\n                                    current.getId(), current.getZxid(),\n                                    logicalclock, self.getPeerState(),\n                                    (InetSocketAddress) responsePacket\n                                            .getSocketAddress());\n\n                            sendqueue.offer(a);\n                        }\n                        break;\n\n                    // Upon reception of an ack message, remove it from the\n                    // queue\n                    case 3:\n                        Semaphore s = ackMutex.get(tag);\n                        \n                        if(s != null)\n                            s.release();\n                        else LOG.error(\"Empty ack semaphore\");\n                        \n                        ackset.add(tag);\n\n                        if (authEnabled) {\n                            ConcurrentHashMap<Long, Long> tmpMap = addrChallengeMap.get(responsePacket\n                                    .getSocketAddress());\n                            if(tmpMap != null) {\n                                tmpMap.remove(tag);\n                            } else {\n                                LOG.warn(\"No such address in the ensemble configuration \" + responsePacket\n                                    .getSocketAddress());\n                            }\n                        }\n\n                        if (ackstate != QuorumPeer.ServerState.LOOKING) {\n                            Notification outofsync = new Notification();\n                            outofsync.leader = responseBuffer.getLong();\n                            outofsync.zxid = responseBuffer.getLong();\n                            outofsync.epoch = responseBuffer.getLong();\n                            outofsync.state = ackstate;\n                            outofsync.addr = (InetSocketAddress) responsePacket\n                                    .getSocketAddress();\n\n                            recvqueue.offer(outofsync);\n                        }\n\n                        break;\n                    // Default case\n                    default:\n                        LOG.warn(\"Received message of incorrect type \" + type);\n                        break;\n                    }\n                }\n            }\n        }\n\n        class WorkerSender implements Runnable {\n\n            Random rand;\n            int maxAttempts;\n            int ackWait = finalizeWait;\n\n            /*\n             * Receives a socket and max number of attempts as input\n             */\n\n            WorkerSender(int attempts) {\n                maxAttempts = attempts;\n                rand = new Random(java.lang.Thread.currentThread().getId()\n                        + Time.currentElapsedTime());\n            }\n\n            long genChallenge() {\n                byte buf[] = new byte[8];\n\n                buf[0] = (byte) ((challengeCounter & 0xff000000) >>> 24);\n                buf[1] = (byte) ((challengeCounter & 0x00ff0000) >>> 16);\n                buf[2] = (byte) ((challengeCounter & 0x0000ff00) >>> 8);\n                buf[3] = (byte) ((challengeCounter & 0x000000ff));\n\n                challengeCounter++;\n                int secret = rand.nextInt(java.lang.Integer.MAX_VALUE);\n\n                buf[4] = (byte) ((secret & 0xff000000) >>> 24);\n                buf[5] = (byte) ((secret & 0x00ff0000) >>> 16);\n                buf[6] = (byte) ((secret & 0x0000ff00) >>> 8);\n                buf[7] = (byte) ((secret & 0x000000ff));\n\n                return (((long)(buf[0] & 0xFF)) << 56)  \n                        + (((long)(buf[1] & 0xFF)) << 48)\n                        + (((long)(buf[2] & 0xFF)) << 40) \n                        + (((long)(buf[3] & 0xFF)) << 32)\n                        + (((long)(buf[4] & 0xFF)) << 24) \n                        + (((long)(buf[5] & 0xFF)) << 16)\n                        + (((long)(buf[6] & 0xFF)) << 8) \n                        + ((long)(buf[7] & 0xFF));\n            }\n\n            public void run() {\n                while (true) {\n                    try {\n                        ToSend m = sendqueue.take();\n                        process(m);\n                    } catch (InterruptedException e) {\n                        break;\n                    }\n\n                }\n            }\n\n            private void process(ToSend m) {\n                int attempts = 0;\n                byte zeroes[];\n                byte requestBytes[] = new byte[48];\n                DatagramPacket requestPacket = new DatagramPacket(requestBytes,\n                        requestBytes.length);\n                ByteBuffer requestBuffer = ByteBuffer.wrap(requestBytes);\n\n                switch (m.type) {\n                case 0:\n                    /*\n                     * Building challenge request packet to send\n                     */\n                    requestBuffer.clear();\n                    requestBuffer.putInt(ToSend.mType.crequest.ordinal());\n                    requestBuffer.putLong(m.tag);\n                    requestBuffer.putInt(m.state.ordinal());\n                    zeroes = new byte[32];\n                    requestBuffer.put(zeroes);\n\n                    requestPacket.setLength(48);\n                    try {\n                        requestPacket.setSocketAddress(m.addr);\n                    } catch (IllegalArgumentException e) {\n                        // Sun doesn't include the address that causes this\n                        // exception to be thrown, so we wrap the exception\n                        // in order to capture this critical detail.\n                        throw new IllegalArgumentException(\n                                \"Unable to set socket address on packet, msg:\"\n                                + e.getMessage() + \" with addr:\" + m.addr,\n                                e);\n                    }\n\n                    try {\n                        if (challengeMap.get(m.tag) == null) {\n                            mySocket.send(requestPacket);\n                        }\n                    } catch (IOException e) {\n                        LOG.warn(\"Exception while sending challenge: \", e);\n                    }\n\n                    break;\n                case 1:\n                    /*\n                     * Building challenge packet to send\n                     */\n\n                    long newChallenge;\n                    ConcurrentHashMap<Long, Long> tmpMap = addrChallengeMap.get(m.addr); \n                    if(tmpMap != null){\n                        Long tmpLong = tmpMap.get(m.tag);\n                        if (tmpLong != null) {\n                            newChallenge = tmpLong;\n                        } else {\n                            newChallenge = genChallenge();\n                        }\n\n                        tmpMap.put(m.tag, newChallenge);\n\n                        requestBuffer.clear();\n                        requestBuffer.putInt(ToSend.mType.challenge.ordinal());\n                        requestBuffer.putLong(m.tag);\n                        requestBuffer.putInt(m.state.ordinal());\n                        requestBuffer.putLong(newChallenge);\n                        zeroes = new byte[24];\n                        requestBuffer.put(zeroes);\n\n                        requestPacket.setLength(48);\n                        try {\n                            requestPacket.setSocketAddress(m.addr);\n                        } catch (IllegalArgumentException e) {\n                            // Sun doesn't include the address that causes this\n                            // exception to be thrown, so we wrap the exception\n                            // in order to capture this critical detail.\n                            throw new IllegalArgumentException(\n                                    \"Unable to set socket address on packet, msg:\"\n                                    + e.getMessage() + \" with addr:\" + m.addr,\n                                    e);\n                        }\n\n\n                        try {\n                            mySocket.send(requestPacket);\n                        } catch (IOException e) {\n                            LOG.warn(\"Exception while sending challenge: \", e);\n                        }\n                    } else {\n                        LOG.error(\"Address is not in the configuration: \" + m.addr);\n                    }\n\n                    break;\n                case 2:\n\n                    /*\n                     * Building notification packet to send\n                     */\n\n                    requestBuffer.clear();\n                    requestBuffer.putInt(m.type);\n                    requestBuffer.putLong(m.tag);\n                    requestBuffer.putInt(m.state.ordinal());\n                    requestBuffer.putLong(m.leader);\n                    requestBuffer.putLong(m.zxid);\n                    requestBuffer.putLong(m.epoch);\n                    zeroes = new byte[8];\n                    requestBuffer.put(zeroes);\n\n                    requestPacket.setLength(48);\n                    try {\n                        requestPacket.setSocketAddress(m.addr);\n                    } catch (IllegalArgumentException e) {\n                        // Sun doesn't include the address that causes this\n                        // exception to be thrown, so we wrap the exception\n                        // in order to capture this critical detail.\n                        throw new IllegalArgumentException(\n                                \"Unable to set socket address on packet, msg:\"\n                                + e.getMessage() + \" with addr:\" + m.addr,\n                                e);\n                    }\n\n\n                    boolean myChallenge = false;\n                    boolean myAck = false;\n\n                    while (attempts < maxAttempts) {\n                        try {\n                            /*\n                             * Try to obtain a challenge only if does not have\n                             * one yet\n                             */\n\n                            if (!myChallenge && authEnabled) {\n                                ToSend crequest = new ToSend(\n                                        ToSend.mType.crequest, m.tag, m.leader,\n                                        m.zxid, m.epoch,\n                                        QuorumPeer.ServerState.LOOKING, m.addr);\n                                sendqueue.offer(crequest);\n\n                                try {\n                                    double timeout = ackWait\n                                            * java.lang.Math.pow(2, attempts);\n\n                                    Semaphore s = new Semaphore(0);\n                                    synchronized(Messenger.this) {\n                                        challengeMutex.put(m.tag, s);\n                                        s.tryAcquire((long) timeout, TimeUnit.MILLISECONDS);\n                                        myChallenge = challengeMap\n                                                .containsKey(m.tag);\n                                    }\n                                } catch (InterruptedException e) {\n                                    LOG.warn(\"Challenge request exception: \", e);\n                                } \n                            }\n\n                            /*\n                             * If don't have challenge yet, skip sending\n                             * notification\n                             */\n\n                            if (authEnabled && !myChallenge) {\n                                attempts++;\n                                continue;\n                            }\n\n                            if (authEnabled) {\n                                requestBuffer.position(40);\n                                Long tmpLong = challengeMap.get(m.tag);\n                                if(tmpLong != null){\n                                    requestBuffer.putLong(tmpLong);\n                                } else {\n                                    LOG.warn(\"No challenge with tag: \" + m.tag);\n                                }\n                            }\n                            mySocket.send(requestPacket);\n                            try {\n                                Semaphore s = new Semaphore(0);\n                                double timeout = ackWait\n                                        * java.lang.Math.pow(10, attempts);\n                                ackMutex.put(m.tag, s);\n                                s.tryAcquire((int) timeout, TimeUnit.MILLISECONDS);\n                            } catch (InterruptedException e) {\n                                LOG.warn(\"Ack exception: \", e);\n                            }\n                            \n                            if(ackset.remove(m.tag)){\n                                myAck = true;\n                            } \n                        \n                        } catch (IOException e) {\n                            LOG.warn(\"Sending exception: \", e);\n                            /*\n                             * Do nothing, just try again\n                             */\n                        }\n                        if (myAck) {\n                            /*\n                             * Received ack successfully, so return\n                             */\n                            challengeMap.remove(m.tag);\n                            \n                            return;\n                        } else\n                            attempts++;\n                    }\n                    /*\n                     * Return message to queue for another attempt later if\n                     * epoch hasn't changed.\n                     */\n                    if (m.epoch == logicalclock) {\n                        challengeMap.remove(m.tag);\n                        sendqueue.offer(m);\n                    }\n                    break;\n                case 3:\n\n                    requestBuffer.clear();\n                    requestBuffer.putInt(m.type);\n                    requestBuffer.putLong(m.tag);\n                    requestBuffer.putInt(m.state.ordinal());\n                    requestBuffer.putLong(m.leader);\n                    requestBuffer.putLong(m.zxid);\n                    requestBuffer.putLong(m.epoch);\n\n                    requestPacket.setLength(48);\n                    try {\n                        requestPacket.setSocketAddress(m.addr);\n                    } catch (IllegalArgumentException e) {\n                        // Sun doesn't include the address that causes this\n                        // exception to be thrown, so we wrap the exception\n                        // in order to capture this critical detail.\n                        throw new IllegalArgumentException(\n                                \"Unable to set socket address on packet, msg:\"\n                                + e.getMessage() + \" with addr:\" + m.addr,\n                                e);\n                    }\n\n\n                    try {\n                        mySocket.send(requestPacket);\n                    } catch (IOException e) {\n                        LOG.warn(\"Exception while sending ack: \", e);\n                    }\n                    break;\n                }\n            }\n        }\n\n        public boolean queueEmpty() {\n            return (sendqueue.isEmpty() || ackset.isEmpty() || recvqueue\n                    .isEmpty());\n        }\n\n        Messenger(int threads, DatagramSocket s) {\n            mySocket = s;\n            ackset =  Collections.<Long>newSetFromMap(new ConcurrentHashMap<Long, Boolean>());\n            challengeMap = new ConcurrentHashMap<Long, Long>();\n            challengeMutex = new ConcurrentHashMap<Long, Semaphore>();\n            ackMutex = new ConcurrentHashMap<Long, Semaphore>();\n            addrChallengeMap = new ConcurrentHashMap<InetSocketAddress, ConcurrentHashMap<Long, Long>>();\n            lastProposedLeader = 0;\n            lastProposedZxid = 0;\n            lastEpoch = 0;\n\n            for (int i = 0; i < threads; ++i) {\n                Thread t = new ZooKeeperThread(new WorkerSender(3),\n                        \"WorkerSender Thread: \" + (i + 1));\n                t.setDaemon(true);\n                t.start();\n            }\n\n            for (QuorumServer server : self.getVotingView().values()) {\n                InetSocketAddress saddr = new InetSocketAddress(server.addr\n                        .getAddress(), port);\n                addrChallengeMap.put(saddr, new ConcurrentHashMap<Long, Long>());\n            }\n\n            Thread t = new ZooKeeperThread(new WorkerReceiver(s, this),\n                    \"WorkerReceiver-\" + s.getRemoteSocketAddress());\n            t.start();\n        }\n\n    }\n\n    QuorumPeer self;\n    int port;\n    volatile long logicalclock; /* Election instance */\n    DatagramSocket mySocket;\n    long proposedLeader;\n    long proposedZxid;\n\n    public AuthFastLeaderElection(QuorumPeer self,\n            boolean auth) {\n        this.authEnabled = auth;\n        starter(self);\n    }\n\n    public AuthFastLeaderElection(QuorumPeer self) {\n        starter(self);\n    }\n\n    private void starter(QuorumPeer self) {\n        this.self = self;\n        port = self.getVotingView().get(self.getId()).electionAddr.getPort();\n        proposedLeader = -1;\n        proposedZxid = -1;\n\n        try {\n            mySocket = new DatagramSocket(port);\n            // mySocket.setSoTimeout(20000);\n        } catch (SocketException e1) {\n            e1.printStackTrace();\n            throw new RuntimeException();\n        }\n        sendqueue = new LinkedBlockingQueue<ToSend>(2 * self.getVotingView().size());\n        recvqueue = new LinkedBlockingQueue<Notification>(2 * self.getVotingView()\n                .size());\n        new Messenger(self.getVotingView().size() * 2, mySocket);\n    }\n\n    private void leaveInstance() {\n        logicalclock++;\n    }\n\n    private void sendNotifications() {\n        for (QuorumServer server : self.getView().values()) {\n\n            ToSend notmsg = new ToSend(ToSend.mType.notification,\n                    AuthFastLeaderElection.sequencer++, proposedLeader,\n                    proposedZxid, logicalclock, QuorumPeer.ServerState.LOOKING,\n                    self.getView().get(server.id).electionAddr);\n\n            sendqueue.offer(notmsg);\n        }\n    }\n\n    private boolean totalOrderPredicate(long id, long zxid) {\n        if ((zxid > proposedZxid)\n                || ((zxid == proposedZxid) && (id > proposedLeader)))\n            return true;\n        else\n            return false;\n\n    }\n\n    private boolean termPredicate(HashMap<InetSocketAddress, Vote> votes,\n            long l, long zxid) {\n\n\n        Collection<Vote> votesCast = votes.values();\n        int count = 0;\n        /*\n         * First make the views consistent. Sometimes peers will have different\n         * zxids for a server depending on timing.\n         */\n        for (Vote v : votesCast) {\n            if ((v.getId() == l) && (v.getZxid() == zxid))\n                count++;\n        }\n\n        if (count > (self.getVotingView().size() / 2))\n            return true;\n        else\n            return false;\n\n    }\n\n    /**\n     * There is nothing to shutdown in this implementation of\n     * leader election, so we simply have an empty method.\n     */\n    public void shutdown(){}\n    \n    /**\n     * Invoked in QuorumPeer to find or elect a new leader.\n     * \n     * @throws InterruptedException\n     */\n    public Vote lookForLeader() throws InterruptedException {\n        try {\n            self.jmxLeaderElectionBean = new LeaderElectionBean();\n            MBeanRegistry.getInstance().register(\n                    self.jmxLeaderElectionBean, self.jmxLocalPeerBean);        \n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            self.jmxLeaderElectionBean = null;\n        }\n\n        try {\n            HashMap<InetSocketAddress, Vote> recvset = \n                new HashMap<InetSocketAddress, Vote>();\n    \n            HashMap<InetSocketAddress, Vote> outofelection = \n                new HashMap<InetSocketAddress, Vote>();\n    \n            logicalclock++;\n    \n            proposedLeader = self.getId();\n            proposedZxid = self.getLastLoggedZxid();\n    \n            LOG.info(\"Election tally\");\n            sendNotifications();\n    \n            /*\n             * Loop in which we exchange notifications until we find a leader\n             */\n    \n            while (self.getPeerState() == ServerState.LOOKING) {\n                /*\n                 * Remove next notification from queue, times out after 2 times\n                 * the termination time\n                 */\n                Notification n = recvqueue.poll(2 * finalizeWait,\n                        TimeUnit.MILLISECONDS);\n    \n                /*\n                 * Sends more notifications if haven't received enough.\n                 * Otherwise processes new notification.\n                 */\n                if (n == null) {\n                    if (((!outofelection.isEmpty()) || (recvset.size() > 1)))\n                        sendNotifications();\n                } else\n                    switch (n.state) {\n                    case LOOKING:\n                        if (n.epoch > logicalclock) {\n                            logicalclock = n.epoch;\n                            recvset.clear();\n                            if (totalOrderPredicate(n.leader, n.zxid)) {\n                                proposedLeader = n.leader;\n                                proposedZxid = n.zxid;\n                            }\n                            sendNotifications();\n                        } else if (n.epoch < logicalclock) {\n                            break;\n                        } else if (totalOrderPredicate(n.leader, n.zxid)) {\n                            proposedLeader = n.leader;\n                            proposedZxid = n.zxid;\n    \n                            sendNotifications();\n                        }\n    \n                        recvset.put(n.addr, new Vote(n.leader, n.zxid));\n    \n                        // If have received from all nodes, then terminate\n                        if (self.getVotingView().size() == recvset.size()) {\n                            self.setPeerState((proposedLeader == self.getId()) ? \n                                    ServerState.LEADING: ServerState.FOLLOWING);\n                            // if (self.state == ServerState.FOLLOWING) {\n                            // Thread.sleep(100);\n                            // }\n                            leaveInstance();\n                            return new Vote(proposedLeader, proposedZxid);\n    \n                        } else if (termPredicate(recvset, proposedLeader,\n                                proposedZxid)) {\n                            // Otherwise, wait for a fixed amount of time\n                            LOG.info(\"Passed predicate\");\n                            Thread.sleep(finalizeWait);\n    \n                            // Notification probe = recvqueue.peek();\n    \n                            // Verify if there is any change in the proposed leader\n                            while ((!recvqueue.isEmpty())\n                                    && !totalOrderPredicate(\n                                            recvqueue.peek().leader, recvqueue\n                                                    .peek().zxid)) {\n                                recvqueue.poll();\n                            }\n                            if (recvqueue.isEmpty()) {\n                                // LOG.warn(\"Proposed leader: \" +\n                                // proposedLeader);\n                                self.setPeerState(\n                                        (proposedLeader == self.getId()) ? \n                                         ServerState.LEADING :\n                                         ServerState.FOLLOWING);\n    \n                                leaveInstance();\n                                return new Vote(proposedLeader, proposedZxid);\n                            }\n                        }\n                        break;\n                    case LEADING:\n                        outofelection.put(n.addr, new Vote(n.leader, n.zxid));\n    \n                        if (termPredicate(outofelection, n.leader, n.zxid)) {\n    \n                            self.setPeerState((n.leader == self.getId()) ? \n                                    ServerState.LEADING: ServerState.FOLLOWING);\n    \n                            leaveInstance();\n                            return new Vote(n.leader, n.zxid);\n                        }\n                        break;\n                    case FOLLOWING:\n                        outofelection.put(n.addr, new Vote(n.leader, n.zxid));\n    \n                        if (termPredicate(outofelection, n.leader, n.zxid)) {\n    \n                            self.setPeerState((n.leader == self.getId()) ? \n                                    ServerState.LEADING: ServerState.FOLLOWING);\n    \n                            leaveInstance();\n                            return new Vote(n.leader, n.zxid);\n                        }\n                        break;\n                    default:\n                        break;\n                    }\n            }\n    \n            return null;\n        } finally {\n            try {\n                if(self.jmxLeaderElectionBean != null){\n                    MBeanRegistry.getInstance().unregister(\n                            self.jmxLeaderElectionBean);\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Failed to unregister with JMX\", e);\n            }\n            self.jmxLeaderElectionBean = null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/CommitProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperCriticalThread;\nimport org.apache.zookeeper.server.ZooKeeperServerListener;\n\n/**\n * This RequestProcessor matches the incoming committed requests with the\n * locally submitted requests. The trick is that locally submitted requests that\n * change the state of the system will come back as incoming committed requests,\n * so we need to match them up.\n */\npublic class CommitProcessor extends ZooKeeperCriticalThread implements RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(CommitProcessor.class);\n\n    /**\n     * Requests that we are holding until the commit comes in.\n     */\n    LinkedList<Request> queuedRequests = new LinkedList<Request>();\n\n    /**\n     * Requests that have been committed.\n     */\n    LinkedList<Request> committedRequests = new LinkedList<Request>();\n\n    RequestProcessor nextProcessor;\n    ArrayList<Request> toProcess = new ArrayList<Request>();\n\n    /**\n     * This flag indicates whether we need to wait for a response to come back from the\n     * leader or we just let the sync operation flow through like a read. The flag will\n     * be false if the CommitProcessor is in a Leader pipeline.\n     */\n    boolean matchSyncs;\n\n    public CommitProcessor(RequestProcessor nextProcessor, String id,\n            boolean matchSyncs, ZooKeeperServerListener listener) {\n        super(\"CommitProcessor:\" + id, listener);\n        this.nextProcessor = nextProcessor;\n        this.matchSyncs = matchSyncs;\n    }\n\n    volatile boolean finished = false;\n\n    @Override\n    public void run() {\n        try {\n            Request nextPending = null;            \n            while (!finished) {\n                int len = toProcess.size();\n                for (int i = 0; i < len; i++) {\n                    nextProcessor.processRequest(toProcess.get(i));\n                }\n                toProcess.clear();\n                synchronized (this) {\n                    if ((queuedRequests.size() == 0 || nextPending != null)\n                            && committedRequests.size() == 0) {\n                        wait();\n                        continue;\n                    }\n                    // First check and see if the commit came in for the pending\n                    // request\n                    if ((queuedRequests.size() == 0 || nextPending != null)\n                            && committedRequests.size() > 0) {\n                        Request r = committedRequests.remove();\n                        /*\n                         * We match with nextPending so that we can move to the\n                         * next request when it is committed. We also want to\n                         * use nextPending because it has the cnxn member set\n                         * properly.\n                         */\n                        if (nextPending != null\n                                && nextPending.sessionId == r.sessionId\n                                && nextPending.cxid == r.cxid) {\n                            // we want to send our version of the request.\n                            // the pointer to the connection in the request\n                            nextPending.hdr = r.hdr;\n                            nextPending.txn = r.txn;\n                            nextPending.zxid = r.zxid;\n                            toProcess.add(nextPending);\n                            nextPending = null;\n                        } else {\n                            // this request came from someone else so just\n                            // send the commit packet\n                            toProcess.add(r);\n                        }\n                    }\n                }\n\n                // We haven't matched the pending requests, so go back to\n                // waiting\n                if (nextPending != null) {\n                    continue;\n                }\n\n                synchronized (this) {\n                    // Process the next requests in the queuedRequests\n                    while (nextPending == null && queuedRequests.size() > 0) {\n                        Request request = queuedRequests.remove();\n                        switch (request.type) {\n                        case OpCode.create:\n                        case OpCode.delete:\n                        case OpCode.setData:\n                        case OpCode.multi:\n                        case OpCode.setACL:\n                        case OpCode.createSession:\n                        case OpCode.closeSession:\n                            nextPending = request;\n                            break;\n                        case OpCode.sync:\n                            if (matchSyncs) {\n                                nextPending = request;\n                            } else {\n                                toProcess.add(request);\n                            }\n                            break;\n                        default:\n                            toProcess.add(request);\n                        }\n                    }\n                }\n            }\n        } catch (InterruptedException e) {\n            LOG.warn(\"Interrupted exception while waiting\", e);\n        } catch (Throwable e) {\n            LOG.error(\"Unexpected exception causing CommitProcessor to exit\", e);\n        }\n        LOG.info(\"CommitProcessor exited loop!\");\n    }\n\n    synchronized public void commit(Request request) {\n        if (!finished) {\n            if (request == null) {\n                LOG.warn(\"Committed a null!\",\n                         new Exception(\"committing a null! \"));\n                return;\n            }\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Committing request:: \" + request);\n            }\n            committedRequests.add(request);\n            notifyAll();\n        }\n    }\n\n    synchronized public void processRequest(Request request) {\n        // request.addRQRec(\">commit\");\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Processing request:: \" + request);\n        }\n        \n        if (!finished) {\n            queuedRequests.add(request);\n            notifyAll();\n        }\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        synchronized (this) {\n            finished = true;\n            queuedRequests.clear();\n            notifyAll();\n        }\n        if (nextProcessor != null) {\n            nextProcessor.shutdown();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Election.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n\nimport org.apache.zookeeper.server.quorum.Vote;\n\npublic interface Election {\n    public Vote lookForLeader() throws InterruptedException;\n    public void shutdown();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager.Message;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * Implementation of leader election using TCP. It uses an object of the class\n * QuorumCnxManager to manage connections. Otherwise, the algorithm is push-based\n * as with the other UDP implementations.\n *\n * There are a few parameters that can be tuned to change its behavior. First,\n * finalizeWait determines the amount of time to wait until deciding upon a leader.\n * This is part of the leader election algorithm.\n */\n\n\npublic class FastLeaderElection implements Election {\n    private static final Logger LOG = LoggerFactory.getLogger(FastLeaderElection.class);\n\n    /**\n     * Determine how much time a process has to wait\n     * once it believes that it has reached the end of\n     * leader election.\n     */\n    final static int finalizeWait = 200;\n\n\n    /**\n     * Upper bound on the amount of time between two consecutive\n     * notification checks. This impacts the amount of time to get\n     * the system up again after long partitions. Currently 60 seconds.\n     */\n\n    final static int maxNotificationInterval = 60000;\n\n    /**\n     * Connection manager. Fast leader election uses TCP for\n     * communication between peers, and QuorumCnxManager manages\n     * such connections.\n     */\n\n    QuorumCnxManager manager;\n\n\n    /**\n     * Notifications are messages that let other peers know that\n     * a given peer has changed its vote, either because it has\n     * joined leader election or because it learned of another\n     * peer with higher zxid or same zxid and higher server id\n     */\n\n    static public class Notification {\n        /*\n         * Format version, introduced in 3.4.6\n         */\n        \n        public final static int CURRENTVERSION = 0x1; \n        int version;\n                \n        /*\n         * Proposed leader\n         */\n        long leader;\n\n        /*\n         * zxid of the proposed leader\n         */\n        long zxid;\n\n        /*\n         * Epoch\n         */\n        long electionEpoch;\n\n        /*\n         * current state of sender\n         */\n        QuorumPeer.ServerState state;\n\n        /*\n         * Address of sender\n         */\n        long sid;\n\n        /*\n         * epoch of the proposed leader\n         */\n        long peerEpoch;\n\n        @Override\n        public String toString() {\n            return Long.toHexString(version) + \" (message format version), \"\n                    + leader + \" (n.leader), 0x\"\n                    + Long.toHexString(zxid) + \" (n.zxid), 0x\"\n                    + Long.toHexString(electionEpoch) + \" (n.round), \" + state\n                    + \" (n.state), \" + sid + \" (n.sid), 0x\"\n                    + Long.toHexString(peerEpoch) + \" (n.peerEpoch) \";\n        }\n    }\n    \n    static ByteBuffer buildMsg(int state,\n            long leader,\n            long zxid,\n            long electionEpoch,\n            long epoch) {\n        byte requestBytes[] = new byte[40];\n        ByteBuffer requestBuffer = ByteBuffer.wrap(requestBytes);\n\n        /*\n         * Building notification packet to send \n         */\n\n        requestBuffer.clear();\n        requestBuffer.putInt(state);\n        requestBuffer.putLong(leader);\n        requestBuffer.putLong(zxid);\n        requestBuffer.putLong(electionEpoch);\n        requestBuffer.putLong(epoch);\n        requestBuffer.putInt(Notification.CURRENTVERSION);\n        \n        return requestBuffer;\n    }\n\n    /**\n     * Messages that a peer wants to send to other peers.\n     * These messages can be both Notifications and Acks\n     * of reception of notification.\n     */\n    static public class ToSend {\n        static enum mType {crequest, challenge, notification, ack}\n\n        ToSend(mType type,\n                long leader,\n                long zxid,\n                long electionEpoch,\n                ServerState state,\n                long sid,\n                long peerEpoch) {\n\n            this.leader = leader;\n            this.zxid = zxid;\n            this.electionEpoch = electionEpoch;\n            this.state = state;\n            this.sid = sid;\n            this.peerEpoch = peerEpoch;\n        }\n\n        /*\n         * Proposed leader in the case of notification\n         */\n        long leader;\n\n        /*\n         * id contains the tag for acks, and zxid for notifications\n         */\n        long zxid;\n\n        /*\n         * Epoch\n         */\n        long electionEpoch;\n\n        /*\n         * Current state;\n         */\n        QuorumPeer.ServerState state;\n\n        /*\n         * Address of recipient\n         */\n        long sid;\n        \n        /*\n         * Leader epoch\n         */\n        long peerEpoch;\n    }\n\n    LinkedBlockingQueue<ToSend> sendqueue;\n    LinkedBlockingQueue<Notification> recvqueue;\n\n    /**\n     * Multi-threaded implementation of message handler. Messenger\n     * implements two sub-classes: WorkReceiver and  WorkSender. The\n     * functionality of each is obvious from the name. Each of these\n     * spawns a new thread.\n     */\n\n    protected class Messenger {\n\n        /**\n         * Receives messages from instance of QuorumCnxManager on\n         * method run(), and processes such messages.\n         */\n\n        class WorkerReceiver extends ZooKeeperThread {\n            volatile boolean stop;\n            QuorumCnxManager manager;\n\n            WorkerReceiver(QuorumCnxManager manager) {\n                super(\"WorkerReceiver\");\n                this.stop = false;\n                this.manager = manager;\n            }\n\n            public void run() {\n\n                Message response;\n                while (!stop) {\n                    // Sleeps on receive\n                    try{\n                        response = manager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n                        if(response == null) continue;\n\n                        /*\n                         * If it is from an observer, respond right away.\n                         * Note that the following predicate assumes that\n                         * if a server is not a follower, then it must be\n                         * an observer. If we ever have any other type of\n                         * learner in the future, we'll have to change the\n                         * way we check for observers.\n                         */\n                        if(!self.getVotingView().containsKey(response.sid)){\n                            Vote current = self.getCurrentVote();\n                            ToSend notmsg = new ToSend(ToSend.mType.notification,\n                                    current.getId(),\n                                    current.getZxid(),\n                                    logicalclock.get(),\n                                    self.getPeerState(),\n                                    response.sid,\n                                    current.getPeerEpoch());\n\n                            sendqueue.offer(notmsg);\n                        } else {\n                            // Receive new message\n                            if (LOG.isDebugEnabled()) {\n                                LOG.debug(\"Receive new notification message. My id = \"\n                                        + self.getId());\n                            }\n\n                            /*\n                             * We check for 28 bytes for backward compatibility\n                             */\n                            if (response.buffer.capacity() < 28) {\n                                LOG.error(\"Got a short response: \"\n                                        + response.buffer.capacity());\n                                continue;\n                            }\n                            boolean backCompatibility = (response.buffer.capacity() == 28);\n                            response.buffer.clear();\n\n                            // Instantiate Notification and set its attributes\n                            Notification n = new Notification();\n                            \n                            // State of peer that sent this message\n                            QuorumPeer.ServerState ackstate = QuorumPeer.ServerState.LOOKING;\n                            switch (response.buffer.getInt()) {\n                            case 0:\n                                ackstate = QuorumPeer.ServerState.LOOKING;\n                                break;\n                            case 1:\n                                ackstate = QuorumPeer.ServerState.FOLLOWING;\n                                break;\n                            case 2:\n                                ackstate = QuorumPeer.ServerState.LEADING;\n                                break;\n                            case 3:\n                                ackstate = QuorumPeer.ServerState.OBSERVING;\n                                break;\n                            default:\n                                continue;\n                            }\n                            \n                            n.leader = response.buffer.getLong();\n                            n.zxid = response.buffer.getLong();\n                            n.electionEpoch = response.buffer.getLong();\n                            n.state = ackstate;\n                            n.sid = response.sid;\n                            if(!backCompatibility){\n                                n.peerEpoch = response.buffer.getLong();\n                            } else {\n                                if(LOG.isInfoEnabled()){\n                                    LOG.info(\"Backward compatibility mode, server id=\" + n.sid);\n                                }\n                                n.peerEpoch = ZxidUtils.getEpochFromZxid(n.zxid);\n                            }\n\n                            /*\n                             * Version added in 3.4.6\n                             */\n\n                            n.version = (response.buffer.remaining() >= 4) ? \n                                         response.buffer.getInt() : 0x0;\n\n                            /*\n                             * Print notification info\n                             */\n                            if(LOG.isInfoEnabled()){\n                                printNotification(n);\n                            }\n\n                            /*\n                             * If this server is looking, then send proposed leader\n                             */\n\n                            if(self.getPeerState() == QuorumPeer.ServerState.LOOKING){\n                                recvqueue.offer(n);\n\n                                /*\n                                 * Send a notification back if the peer that sent this\n                                 * message is also looking and its logical clock is\n                                 * lagging behind.\n                                 */\n                                if((ackstate == QuorumPeer.ServerState.LOOKING)\n                                        && (n.electionEpoch < logicalclock.get())){\n                                    Vote v = getVote();\n                                    ToSend notmsg = new ToSend(ToSend.mType.notification,\n                                            v.getId(),\n                                            v.getZxid(),\n                                            logicalclock.get(),\n                                            self.getPeerState(),\n                                            response.sid,\n                                            v.getPeerEpoch());\n                                    sendqueue.offer(notmsg);\n                                }\n                            } else {\n                                /*\n                                 * If this server is not looking, but the one that sent the ack\n                                 * is looking, then send back what it believes to be the leader.\n                                 */\n                                Vote current = self.getCurrentVote();\n                                if(ackstate == QuorumPeer.ServerState.LOOKING){\n                                    if(LOG.isDebugEnabled()){\n                                        LOG.debug(\"Sending new notification. My id =  \" +\n                                                self.getId() + \" recipient=\" +\n                                                response.sid + \" zxid=0x\" +\n                                                Long.toHexString(current.getZxid()) +\n                                                \" leader=\" + current.getId());\n                                    }\n                                    \n                                    ToSend notmsg;\n                                    if(n.version > 0x0) {\n                                        notmsg = new ToSend(\n                                                ToSend.mType.notification,\n                                                current.getId(),\n                                                current.getZxid(),\n                                                current.getElectionEpoch(),\n                                                self.getPeerState(),\n                                                response.sid,\n                                                current.getPeerEpoch());\n                                        \n                                    } else {\n                                        Vote bcVote = self.getBCVote();\n                                        notmsg = new ToSend(\n                                                ToSend.mType.notification,\n                                                bcVote.getId(),\n                                                bcVote.getZxid(),\n                                                bcVote.getElectionEpoch(),\n                                                self.getPeerState(),\n                                                response.sid,\n                                                bcVote.getPeerEpoch());\n                                    }\n                                    sendqueue.offer(notmsg);\n                                }\n                            }\n                        }\n                    } catch (InterruptedException e) {\n                        System.out.println(\"Interrupted Exception while waiting for new message\" +\n                                e.toString());\n                    }\n                }\n                LOG.info(\"WorkerReceiver is down\");\n            }\n        }\n\n\n        /**\n         * This worker simply dequeues a message to send and\n         * and queues it on the manager's queue.\n         */\n\n        class WorkerSender extends ZooKeeperThread {\n            volatile boolean stop;\n            QuorumCnxManager manager;\n\n            WorkerSender(QuorumCnxManager manager){\n                super(\"WorkerSender\");\n                this.stop = false;\n                this.manager = manager;\n            }\n\n            public void run() {\n                while (!stop) {\n                    try {\n                        ToSend m = sendqueue.poll(3000, TimeUnit.MILLISECONDS);\n                        if(m == null) continue;\n\n                        process(m);\n                    } catch (InterruptedException e) {\n                        break;\n                    }\n                }\n                LOG.info(\"WorkerSender is down\");\n            }\n\n            /**\n             * Called by run() once there is a new message to send.\n             *\n             * @param m     message to send\n             */\n            void process(ToSend m) {\n                ByteBuffer requestBuffer = buildMsg(m.state.ordinal(), \n                                                        m.leader,\n                                                        m.zxid, \n                                                        m.electionEpoch, \n                                                        m.peerEpoch);\n                manager.toSend(m.sid, requestBuffer);\n            }\n        }\n\n\n        WorkerSender ws;\n        WorkerReceiver wr;\n\n        /**\n         * Constructor of class Messenger.\n         *\n         * @param manager   Connection manager\n         */\n        Messenger(QuorumCnxManager manager) {\n\n            this.ws = new WorkerSender(manager);\n\n            Thread t = new Thread(this.ws,\n                    \"WorkerSender[myid=\" + self.getId() + \"]\");\n            t.setDaemon(true);\n            t.start();\n\n            this.wr = new WorkerReceiver(manager);\n\n            t = new Thread(this.wr,\n                    \"WorkerReceiver[myid=\" + self.getId() + \"]\");\n            t.setDaemon(true);\n            t.start();\n        }\n\n        /**\n         * Stops instances of WorkerSender and WorkerReceiver\n         */\n        void halt(){\n            this.ws.stop = true;\n            this.wr.stop = true;\n        }\n\n    }\n\n    QuorumPeer self;\n    Messenger messenger;\n    AtomicLong logicalclock = new AtomicLong(); /* Election instance */\n    long proposedLeader;\n    long proposedZxid;\n    long proposedEpoch;\n\n\n    /**\n     * Returns the current vlue of the logical clock counter\n     */\n    public long getLogicalClock(){\n        return logicalclock.get();\n    }\n\n    /**\n     * Constructor of FastLeaderElection. It takes two parameters, one\n     * is the QuorumPeer object that instantiated this object, and the other\n     * is the connection manager. Such an object should be created only once\n     * by each peer during an instance of the ZooKeeper service.\n     *\n     * @param self  QuorumPeer that created this object\n     * @param manager   Connection manager\n     */\n    public FastLeaderElection(QuorumPeer self, QuorumCnxManager manager){\n        this.stop = false;\n        this.manager = manager;\n        starter(self, manager);\n    }\n\n    /**\n     * This method is invoked by the constructor. Because it is a\n     * part of the starting procedure of the object that must be on\n     * any constructor of this class, it is probably best to keep as\n     * a separate method. As we have a single constructor currently,\n     * it is not strictly necessary to have it separate.\n     *\n     * @param self      QuorumPeer that created this object\n     * @param manager   Connection manager\n     */\n    private void starter(QuorumPeer self, QuorumCnxManager manager) {\n        this.self = self;\n        proposedLeader = -1;\n        proposedZxid = -1;\n\n        sendqueue = new LinkedBlockingQueue<ToSend>();\n        recvqueue = new LinkedBlockingQueue<Notification>();\n        this.messenger = new Messenger(manager);\n    }\n\n    private void leaveInstance(Vote v) {\n        if(LOG.isDebugEnabled()){\n            LOG.debug(\"About to leave FLE instance: leader=\"\n                + v.getId() + \", zxid=0x\" +\n                Long.toHexString(v.getZxid()) + \", my id=\" + self.getId()\n                + \", my state=\" + self.getPeerState());\n        }\n        recvqueue.clear();\n    }\n\n    public QuorumCnxManager getCnxManager(){\n        return manager;\n    }\n\n    volatile boolean stop;\n    public void shutdown(){\n        stop = true;\n        LOG.debug(\"Shutting down connection manager\");\n        manager.halt();\n        LOG.debug(\"Shutting down messenger\");\n        messenger.halt();\n        LOG.debug(\"FLE is down\");\n    }\n\n\n    /**\n     * Send notifications to all peers upon a change in our vote\n     */\n    private void sendNotifications() {\n        for (QuorumServer server : self.getVotingView().values()) {\n            long sid = server.id;\n\n            ToSend notmsg = new ToSend(ToSend.mType.notification,\n                    proposedLeader,\n                    proposedZxid,\n                    logicalclock.get(),\n                    QuorumPeer.ServerState.LOOKING,\n                    sid,\n                    proposedEpoch);\n            if(LOG.isDebugEnabled()){\n                LOG.debug(\"Sending Notification: \" + proposedLeader + \" (n.leader), 0x\"  +\n                      Long.toHexString(proposedZxid) + \" (n.zxid), 0x\" + Long.toHexString(logicalclock.get())  +\n                      \" (n.round), \" + sid + \" (recipient), \" + self.getId() +\n                      \" (myid), 0x\" + Long.toHexString(proposedEpoch) + \" (n.peerEpoch)\");\n            }\n            sendqueue.offer(notmsg);\n        }\n    }\n\n\n    private void printNotification(Notification n){\n        LOG.info(\"Notification: \" + n.toString()\n                + self.getPeerState() + \" (my state)\");\n    }\n\n    /**\n     * Check if a pair (server id, zxid) succeeds our\n     * current vote.\n     *\n     * @param id    Server identifier\n     * @param zxid  Last zxid observed by the issuer of this vote\n     */\n    protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) {\n        LOG.debug(\"id: \" + newId + \", proposed id: \" + curId + \", zxid: 0x\" +\n                Long.toHexString(newZxid) + \", proposed zxid: 0x\" + Long.toHexString(curZxid));\n        if(self.getQuorumVerifier().getWeight(newId) == 0){\n            return false;\n        }\n        \n        /*\n         * We return true if one of the following three cases hold:\n         * 1- New epoch is higher\n         * 2- New epoch is the same as current epoch, but new zxid is higher\n         * 3- New epoch is the same as current epoch, new zxid is the same\n         *  as current zxid, but server id is higher.\n         */\n        \n        return ((newEpoch > curEpoch) || \n                ((newEpoch == curEpoch) &&\n                ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));\n    }\n\n    /**\n     * Termination predicate. Given a set of votes, determines if\n     * have sufficient to declare the end of the election round.\n     *\n     *  @param votes    Set of votes\n     *  @param l        Identifier of the vote received last\n     *  @param zxid     zxid of the the vote received last\n     */\n    protected boolean termPredicate(\n            HashMap<Long, Vote> votes,\n            Vote vote) {\n\n        HashSet<Long> set = new HashSet<Long>();\n\n        /*\n         * First make the views consistent. Sometimes peers will have\n         * different zxids for a server depending on timing.\n         */\n        for (Map.Entry<Long,Vote> entry : votes.entrySet()) {\n            if (vote.equals(entry.getValue())){\n                set.add(entry.getKey());\n            }\n        }\n\n        return self.getQuorumVerifier().containsQuorum(set);\n    }\n\n    /**\n     * In the case there is a leader elected, and a quorum supporting\n     * this leader, we have to check if the leader has voted and acked\n     * that it is leading. We need this check to avoid that peers keep\n     * electing over and over a peer that has crashed and it is no\n     * longer leading.\n     *\n     * @param votes set of votes\n     * @param   leader  leader id\n     * @param   electionEpoch   epoch id\n     */\n    protected boolean checkLeader(\n            HashMap<Long, Vote> votes,\n            long leader,\n            long electionEpoch){\n\n        boolean predicate = true;\n\n        /*\n         * If everyone else thinks I'm the leader, I must be the leader.\n         * The other two checks are just for the case in which I'm not the\n         * leader. If I'm not the leader and I haven't received a message\n         * from leader stating that it is leading, then predicate is false.\n         */\n\n        if(leader != self.getId()){\n            if(votes.get(leader) == null) predicate = false;\n            else if(votes.get(leader).getState() != ServerState.LEADING) predicate = false;\n        } else if(logicalclock.get() != electionEpoch) {\n            predicate = false;\n        } \n\n        return predicate;\n    }\n    \n    /**\n     * This predicate checks that a leader has been elected. It doesn't\n     * make a lot of sense without context (check lookForLeader) and it\n     * has been separated for testing purposes.\n     * \n     * @param recv  map of received votes \n     * @param ooe   map containing out of election votes (LEADING or FOLLOWING)\n     * @param n     Notification\n     * @return          \n     */\n    protected boolean ooePredicate(HashMap<Long,Vote> recv, \n                                    HashMap<Long,Vote> ooe, \n                                    Notification n) {\n        \n        return (termPredicate(recv, new Vote(n.version, \n                                             n.leader,\n                                             n.zxid, \n                                             n.electionEpoch, \n                                             n.peerEpoch, \n                                             n.state))\n                && checkLeader(ooe, n.leader, n.electionEpoch));\n        \n    }\n\n    synchronized void updateProposal(long leader, long zxid, long epoch){\n        if(LOG.isDebugEnabled()){\n            LOG.debug(\"Updating proposal: \" + leader + \" (newleader), 0x\"\n                    + Long.toHexString(zxid) + \" (newzxid), \" + proposedLeader\n                    + \" (oldleader), 0x\" + Long.toHexString(proposedZxid) + \" (oldzxid)\");\n        }\n        proposedLeader = leader;\n        proposedZxid = zxid;\n        proposedEpoch = epoch;\n    }\n\n    synchronized Vote getVote(){\n        return new Vote(proposedLeader, proposedZxid, proposedEpoch);\n    }\n\n    /**\n     * A learning state can be either FOLLOWING or OBSERVING.\n     * This method simply decides which one depending on the\n     * role of the server.\n     *\n     * @return ServerState\n     */\n    private ServerState learningState(){\n        if(self.getLearnerType() == LearnerType.PARTICIPANT){\n            LOG.debug(\"I'm a participant: \" + self.getId());\n            return ServerState.FOLLOWING;\n        }\n        else{\n            LOG.debug(\"I'm an observer: \" + self.getId());\n            return ServerState.OBSERVING;\n        }\n    }\n\n    /**\n     * Returns the initial vote value of server identifier.\n     *\n     * @return long\n     */\n    private long getInitId(){\n        if(self.getLearnerType() == LearnerType.PARTICIPANT)\n            return self.getId();\n        else return Long.MIN_VALUE;\n    }\n\n    /**\n     * Returns initial last logged zxid.\n     *\n     * @return long\n     */\n    private long getInitLastLoggedZxid(){\n        if(self.getLearnerType() == LearnerType.PARTICIPANT)\n            return self.getLastLoggedZxid();\n        else return Long.MIN_VALUE;\n    }\n\n    /**\n     * Returns the initial vote value of the peer epoch.\n     *\n     * @return long\n     */\n    private long getPeerEpoch(){\n        if(self.getLearnerType() == LearnerType.PARTICIPANT)\n        \ttry {\n        \t\treturn self.getCurrentEpoch();\n        \t} catch(IOException e) {\n        \t\tRuntimeException re = new RuntimeException(e.getMessage());\n        \t\tre.setStackTrace(e.getStackTrace());\n        \t\tthrow re;\n        \t}\n        else return Long.MIN_VALUE;\n    }\n    \n    /**\n     * Starts a new round of leader election. Whenever our QuorumPeer\n     * changes its state to LOOKING, this method is invoked, and it\n     * sends notifications to all other peers.\n     */\n    public Vote lookForLeader() throws InterruptedException {\n        try {\n            self.jmxLeaderElectionBean = new LeaderElectionBean();\n            MBeanRegistry.getInstance().register(\n                    self.jmxLeaderElectionBean, self.jmxLocalPeerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            self.jmxLeaderElectionBean = null;\n        }\n        if (self.start_fle == 0) {\n           self.start_fle = Time.currentElapsedTime();\n        }\n        try {\n            HashMap<Long, Vote> recvset = new HashMap<Long, Vote>();\n\n            HashMap<Long, Vote> outofelection = new HashMap<Long, Vote>();\n\n            int notTimeout = finalizeWait;\n\n            synchronized(this){\n                logicalclock.incrementAndGet();\n                updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());\n            }\n\n            LOG.info(\"New election. My id =  \" + self.getId() +\n                    \", proposed zxid=0x\" + Long.toHexString(proposedZxid));\n            sendNotifications();\n\n            /*\n             * Loop in which we exchange notifications until we find a leader\n             */\n\n            while ((self.getPeerState() == ServerState.LOOKING) &&\n                    (!stop)){\n                /*\n                 * Remove next notification from queue, times out after 2 times\n                 * the termination time\n                 */\n                Notification n = recvqueue.poll(notTimeout,\n                        TimeUnit.MILLISECONDS);\n\n                /*\n                 * Sends more notifications if haven't received enough.\n                 * Otherwise processes new notification.\n                 */\n                if(n == null){\n                    if(manager.haveDelivered()){\n                        sendNotifications();\n                    } else {\n                        manager.connectAll();\n                    }\n\n                    /*\n                     * Exponential backoff\n                     */\n                    int tmpTimeOut = notTimeout*2;\n                    notTimeout = (tmpTimeOut < maxNotificationInterval?\n                            tmpTimeOut : maxNotificationInterval);\n                    LOG.info(\"Notification time out: \" + notTimeout);\n                }\n                else if(self.getVotingView().containsKey(n.sid)) {\n                    /*\n                     * Only proceed if the vote comes from a replica in the\n                     * voting view.\n                     */\n                    switch (n.state) {\n                    case LOOKING:\n                        // If notification > current, replace and send messages out\n                        if (n.electionEpoch > logicalclock.get()) {\n                            logicalclock.set(n.electionEpoch);\n                            recvset.clear();\n                            if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,\n                                    getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {\n                                updateProposal(n.leader, n.zxid, n.peerEpoch);\n                            } else {\n                                updateProposal(getInitId(),\n                                        getInitLastLoggedZxid(),\n                                        getPeerEpoch());\n                            }\n                            sendNotifications();\n                        } else if (n.electionEpoch < logicalclock.get()) {\n                            if(LOG.isDebugEnabled()){\n                                LOG.debug(\"Notification election epoch is smaller than logicalclock. n.electionEpoch = 0x\"\n                                        + Long.toHexString(n.electionEpoch)\n                                        + \", logicalclock=0x\" + Long.toHexString(logicalclock.get()));\n                            }\n                            break;\n                        } else if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,\n                                proposedLeader, proposedZxid, proposedEpoch)) {\n                            updateProposal(n.leader, n.zxid, n.peerEpoch);\n                            sendNotifications();\n                        }\n\n                        if(LOG.isDebugEnabled()){\n                            LOG.debug(\"Adding vote: from=\" + n.sid +\n                                    \", proposed leader=\" + n.leader +\n                                    \", proposed zxid=0x\" + Long.toHexString(n.zxid) +\n                                    \", proposed election epoch=0x\" + Long.toHexString(n.electionEpoch));\n                        }\n\n                        recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));\n\n                        if (termPredicate(recvset,\n                                new Vote(proposedLeader, proposedZxid,\n                                        logicalclock.get(), proposedEpoch))) {\n\n                            // Verify if there is any change in the proposed leader\n                            while((n = recvqueue.poll(finalizeWait,\n                                    TimeUnit.MILLISECONDS)) != null){\n                                if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,\n                                        proposedLeader, proposedZxid, proposedEpoch)){\n                                    recvqueue.put(n);\n                                    break;\n                                }\n                            }\n\n                            /*\n                             * This predicate is true once we don't read any new\n                             * relevant message from the reception queue\n                             */\n                            if (n == null) {\n                                self.setPeerState((proposedLeader == self.getId()) ?\n                                        ServerState.LEADING: learningState());\n\n                                Vote endVote = new Vote(proposedLeader,\n                                                        proposedZxid,\n                                                        logicalclock.get(),\n                                                        proposedEpoch);\n                                leaveInstance(endVote);\n                                return endVote;\n                            }\n                        }\n                        break;\n                    case OBSERVING:\n                        LOG.debug(\"Notification from observer: \" + n.sid);\n                        break;\n                    case FOLLOWING:\n                    case LEADING:\n                        /*\n                         * Consider all notifications from the same epoch\n                         * together.\n                         */\n                        if(n.electionEpoch == logicalclock.get()){\n                            recvset.put(n.sid, new Vote(n.leader,\n                                                          n.zxid,\n                                                          n.electionEpoch,\n                                                          n.peerEpoch));\n                           \n                            if(ooePredicate(recvset, outofelection, n)) {\n                                self.setPeerState((n.leader == self.getId()) ?\n                                        ServerState.LEADING: learningState());\n\n                                Vote endVote = new Vote(n.leader, \n                                        n.zxid, \n                                        n.electionEpoch, \n                                        n.peerEpoch);\n                                leaveInstance(endVote);\n                                return endVote;\n                            }\n                        }\n\n                        /*\n                         * Before joining an established ensemble, verify\n                         * a majority is following the same leader.\n                         */\n                        outofelection.put(n.sid, new Vote(n.version,\n                                                            n.leader,\n                                                            n.zxid,\n                                                            n.electionEpoch,\n                                                            n.peerEpoch,\n                                                            n.state));\n           \n                        if(ooePredicate(outofelection, outofelection, n)) {\n                            synchronized(this){\n                                logicalclock.set(n.electionEpoch);\n                                self.setPeerState((n.leader == self.getId()) ?\n                                        ServerState.LEADING: learningState());\n                            }\n                            Vote endVote = new Vote(n.leader,\n                                                    n.zxid,\n                                                    n.electionEpoch,\n                                                    n.peerEpoch);\n                            leaveInstance(endVote);\n                            return endVote;\n                        }\n                        break;\n                    default:\n                        LOG.warn(\"Notification state unrecognized: {} (n.state), {} (n.sid)\",\n                                n.state, n.sid);\n                        break;\n                    }\n                } else {\n                    LOG.warn(\"Ignoring notification from non-cluster member \" + n.sid);\n                }\n            }\n            return null;\n        } finally {\n            try {\n                if(self.jmxLeaderElectionBean != null){\n                    MBeanRegistry.getInstance().unregister(\n                            self.jmxLeaderElectionBean);\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Failed to unregister with JMX\", e);\n            }\n            self.jmxLeaderElectionBean = null;\n            LOG.debug(\"Number of connection processing threads: {}\",\n                    manager.getConnectionThreadCount());\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Follower.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This class has the control logic for the Follower.\n */\npublic class Follower extends Learner{\n\n    private long lastQueued;\n    // This is the same object as this.zk, but we cache the downcast op\n    final FollowerZooKeeperServer fzk;\n    \n    Follower(QuorumPeer self,FollowerZooKeeperServer zk) {\n        this.self = self;\n        this.zk=zk;\n        this.fzk = zk;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Follower \").append(sock);\n        sb.append(\" lastQueuedZxid:\").append(lastQueued);\n        sb.append(\" pendingRevalidationCount:\")\n            .append(pendingRevalidations.size());\n        return sb.toString();\n    }\n\n    /**\n     * the main method called by the follower to follow the leader\n     *\n     * @throws InterruptedException\n     */\n    void followLeader() throws InterruptedException {\n        self.end_fle = Time.currentElapsedTime();\n        long electionTimeTaken = self.end_fle - self.start_fle;\n        self.setElectionTimeTaken(electionTimeTaken);\n        LOG.info(\"FOLLOWING - LEADER ELECTION TOOK - {}\", electionTimeTaken);\n        self.start_fle = 0;\n        self.end_fle = 0;\n        fzk.registerJMX(new FollowerBean(this, zk), self.jmxLocalPeerBean);\n        try {\n            QuorumServer leaderServer = findLeader();            \n            try {\n                connectToLeader(leaderServer.addr, leaderServer.hostname);\n                long newEpochZxid = registerWithLeader(Leader.FOLLOWERINFO);\n\n                //check to see if the leader zxid is lower than ours\n                //this should never happen but is just a safety check\n                long newEpoch = ZxidUtils.getEpochFromZxid(newEpochZxid);\n                if (newEpoch < self.getAcceptedEpoch()) {\n                    LOG.error(\"Proposed leader epoch \" + ZxidUtils.zxidToString(newEpochZxid)\n                            + \" is less than our accepted epoch \" + ZxidUtils.zxidToString(self.getAcceptedEpoch()));\n                    throw new IOException(\"Error: Epoch of leader is lower\");\n                }\n                syncWithLeader(newEpochZxid);                \n                QuorumPacket qp = new QuorumPacket();\n                while (this.isRunning()) {\n                    readPacket(qp);\n                    processPacket(qp);\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Exception when following the leader\", e);\n                try {\n                    sock.close();\n                } catch (IOException e1) {\n                    e1.printStackTrace();\n                }\n    \n                // clear pending revalidations\n                pendingRevalidations.clear();\n            }\n        } finally {\n            zk.unregisterJMX((Learner)this);\n        }\n    }\n\n    /**\n     * Examine the packet received in qp and dispatch based on its contents.\n     * @param qp\n     * @throws IOException\n     */\n    protected void processPacket(QuorumPacket qp) throws IOException{\n        switch (qp.getType()) {\n        case Leader.PING:            \n            ping(qp);            \n            break;\n        case Leader.PROPOSAL:            \n            TxnHeader hdr = new TxnHeader();\n            Record txn = SerializeUtils.deserializeTxn(qp.getData(), hdr);\n            if (hdr.getZxid() != lastQueued + 1) {\n                LOG.warn(\"Got zxid 0x\"\n                        + Long.toHexString(hdr.getZxid())\n                        + \" expected 0x\"\n                        + Long.toHexString(lastQueued + 1));\n            }\n            lastQueued = hdr.getZxid();\n            fzk.logRequest(hdr, txn);\n            break;\n        case Leader.COMMIT:\n            fzk.commit(qp.getZxid());\n            break;\n        case Leader.UPTODATE:\n            LOG.error(\"Received an UPTODATE message after Follower started\");\n            break;\n        case Leader.REVALIDATE:\n            revalidate(qp);\n            break;\n        case Leader.SYNC:\n            fzk.sync();\n            break;\n        default:\n            LOG.error(\"Invalid packet type: {} received by Observer\", qp.getType());\n        }\n    }\n\n    /**\n     * The zxid of the last operation seen\n     * @return zxid\n     */\n    public long getZxid() {\n        try {\n            synchronized (fzk) {\n                return fzk.getZxid();\n            }\n        } catch (NullPointerException e) {\n            LOG.warn(\"error getting zxid\", e);\n        }\n        return -1;\n    }\n    \n    /**\n     * The zxid of the last operation queued\n     * @return zxid\n     */\n    protected long getLastQueued() {\n        return lastQueued;\n    }\n\n    @Override\n    public void shutdown() {    \n        LOG.info(\"shutdown called\", new Exception(\"shutdown Follower\"));\n        super.shutdown();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/FollowerBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooKeeperServerBean;\n\n/**\n * Follower MBean interface implementation.\n */\npublic class FollowerBean extends ZooKeeperServerBean implements FollowerMXBean {\n    private final Follower follower;\n\n    public FollowerBean(Follower follower, ZooKeeperServer zks) {\n        super(zks);\n        this.follower = follower;\n    }\n    \n    public String getName() {\n        return \"Follower\";\n    }\n\n    public String getQuorumAddress() {\n        return follower.sock.toString();\n    }\n    \n    public String getLastQueuedZxid() {\n        return \"0x\" + Long.toHexString(follower.getLastQueued());\n    }\n    \n    public int getPendingRevalidationCount() {\n        return follower.getPendingRevalidationsCount();\n    }\n\n    @Override\n    public long getElectionTimeTaken() {\n        return follower.self.getElectionTimeTaken();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/FollowerMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServerMXBean;\n\n/**\n * Follower MBean\n */\npublic interface FollowerMXBean extends ZooKeeperServerMXBean {\n    /**\n     * @return socket address\n     */\n    public String getQuorumAddress();\n    \n    /**\n     * @return last queued zxid\n     */\n    public String getLastQueuedZxid();\n    \n    /**\n     * @return count of pending revalidations\n     */\n    public int getPendingRevalidationCount();\n\n    /**\n     * @return time taken for leader election in milliseconds.\n     */\n    public long getElectionTimeTaken();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/FollowerRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ZooKeeperCriticalThread;\nimport org.apache.zookeeper.server.ZooTrace;\n\n/**\n * This RequestProcessor forwards any requests that modify the state of the\n * system to the Leader.\n */\npublic class FollowerRequestProcessor extends ZooKeeperCriticalThread implements\n        RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(FollowerRequestProcessor.class);\n\n    FollowerZooKeeperServer zks;\n\n    RequestProcessor nextProcessor;\n\n    LinkedBlockingQueue<Request> queuedRequests = new LinkedBlockingQueue<Request>();\n\n    boolean finished = false;\n\n    public FollowerRequestProcessor(FollowerZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        super(\"FollowerRequestProcessor:\" + zks.getServerId(), zks\n                .getZooKeeperServerListener());\n        this.zks = zks;\n        this.nextProcessor = nextProcessor;\n    }\n\n    @Override\n    public void run() {\n        try {\n            while (!finished) {\n                Request request = queuedRequests.take();\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logRequest(LOG, ZooTrace.CLIENT_REQUEST_TRACE_MASK,\n                            'F', request, \"\");\n                }\n                if (request == Request.requestOfDeath) {\n                    break;\n                }\n                // We want to queue the request to be processed before we submit\n                // the request to the leader so that we are ready to receive\n                // the response\n                nextProcessor.processRequest(request);\n                \n                // We now ship the request to the leader. As with all\n                // other quorum operations, sync also follows this code\n                // path, but different from others, we need to keep track\n                // of the sync operations this follower has pending, so we\n                // add it to pendingSyncs.\n                switch (request.type) {\n                case OpCode.sync:\n                    zks.pendingSyncs.add(request);\n                    zks.getFollower().request(request);\n                    break;\n                case OpCode.create:\n                case OpCode.delete:\n                case OpCode.setData:\n                case OpCode.setACL:\n                case OpCode.createSession:\n                case OpCode.closeSession:\n                case OpCode.multi:\n                    zks.getFollower().request(request);\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            handleException(this.getName(), e);\n        }\n        LOG.info(\"FollowerRequestProcessor exited loop!\");\n    }\n\n    public void processRequest(Request request) {\n        if (!finished) {\n            queuedRequests.add(request);\n        }\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        finished = true;\n        queuedRequests.clear();\n        queuedRequests.add(Request.requestOfDeath);\n        nextProcessor.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/FollowerZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.FinalRequestProcessor;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * Just like the standard ZooKeeperServer. We just replace the request\n * processors: FollowerRequestProcessor -> CommitProcessor ->\n * FinalRequestProcessor\n * \n * A SyncRequestProcessor is also spawned off to log proposals from the leader.\n */\npublic class FollowerZooKeeperServer extends LearnerZooKeeperServer {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(FollowerZooKeeperServer.class);\n\n    CommitProcessor commitProcessor;\n\n    SyncRequestProcessor syncProcessor;\n\n    /*\n     * Pending sync requests\n     */\n    ConcurrentLinkedQueue<Request> pendingSyncs;\n    \n    /**\n     * @param port\n     * @param dataDir\n     * @throws IOException\n     */\n    FollowerZooKeeperServer(FileTxnSnapLog logFactory,QuorumPeer self,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb) throws IOException {\n        super(logFactory, self.tickTime, self.minSessionTimeout,\n                self.maxSessionTimeout, treeBuilder, zkDb, self);\n        this.pendingSyncs = new ConcurrentLinkedQueue<Request>();\n    }\n\n    public Follower getFollower(){\n        return self.follower;\n    }      \n\n    @Override\n    protected void setupRequestProcessors() {\n        RequestProcessor finalProcessor = new FinalRequestProcessor(this);\n        commitProcessor = new CommitProcessor(finalProcessor,\n                Long.toString(getServerId()), true,\n                getZooKeeperServerListener());\n        commitProcessor.start();\n        firstProcessor = new FollowerRequestProcessor(this, commitProcessor);\n        ((FollowerRequestProcessor) firstProcessor).start();\n        syncProcessor = new SyncRequestProcessor(this,\n                new SendAckRequestProcessor((Learner)getFollower()));\n        syncProcessor.start();\n    }\n\n    LinkedBlockingQueue<Request> pendingTxns = new LinkedBlockingQueue<Request>();\n\n    public void logRequest(TxnHeader hdr, Record txn) {\n        Request request = new Request(null, hdr.getClientId(), hdr.getCxid(),\n                hdr.getType(), null, null);\n        request.hdr = hdr;\n        request.txn = txn;\n        request.zxid = hdr.getZxid();\n        if ((request.zxid & 0xffffffffL) != 0) {\n            pendingTxns.add(request);\n        }\n        syncProcessor.processRequest(request);\n    }\n\n    /**\n     * When a COMMIT message is received, eventually this method is called, \n     * which matches up the zxid from the COMMIT with (hopefully) the head of\n     * the pendingTxns queue and hands it to the commitProcessor to commit.\n     * @param zxid - must correspond to the head of pendingTxns if it exists\n     */\n    public void commit(long zxid) {\n        if (pendingTxns.size() == 0) {\n            LOG.warn(\"Committing \" + Long.toHexString(zxid)\n                    + \" without seeing txn\");\n            return;\n        }\n        long firstElementZxid = pendingTxns.element().zxid;\n        if (firstElementZxid != zxid) {\n            LOG.error(\"Committing zxid 0x\" + Long.toHexString(zxid)\n                    + \" but next pending txn 0x\"\n                    + Long.toHexString(firstElementZxid));\n            System.exit(12);\n        }\n        Request request = pendingTxns.remove();\n        commitProcessor.commit(request);\n    }\n    \n    synchronized public void sync(){\n        if(pendingSyncs.size() ==0){\n            LOG.warn(\"Not expecting a sync.\");\n            return;\n        }\n                \n        Request r = pendingSyncs.remove();\n\t\tcommitProcessor.commit(r);\n    }\n             \n    @Override\n    public int getGlobalOutstandingLimit() {\n        return super.getGlobalOutstandingLimit() / (self.getQuorumSize() - 1);\n    }\n    \n    @Override\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        try {\n            super.shutdown();\n        } catch (Exception e) {\n            LOG.warn(\"Ignoring unexpected exception during shutdown\", e);\n        }\n        try {\n            if (syncProcessor != null) {\n                syncProcessor.shutdown();\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Ignoring unexpected exception in syncprocessor shutdown\",\n                    e);\n        }\n    }\n    \n    @Override\n    public String getState() {\n        return \"follower\";\n    }\n\n    @Override\n    public Learner getLearner() {\n        return getFollower();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Leader.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport java.net.BindException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.server.FinalRequestProcessor;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class has the control logic for the Leader.\n */\npublic class Leader {\n    private static final Logger LOG = LoggerFactory.getLogger(Leader.class);\n    \n    static final private boolean nodelay = System.getProperty(\"leader.nodelay\", \"true\").equals(\"true\");\n    static {\n        LOG.info(\"TCP NoDelay set to: \" + nodelay);\n    }\n\n    static public class Proposal {\n        public QuorumPacket packet;\n\n        public HashSet<Long> ackSet = new HashSet<Long>();\n\n        public Request request;\n\n        @Override\n        public String toString() {\n            return packet.getType() + \", \" + packet.getZxid() + \", \" + request;\n        }\n    }\n\n    final LeaderZooKeeperServer zk;\n\n    final QuorumPeer self;\n\n    private boolean quorumFormed = false;\n    \n    // the follower acceptor thread\n    LearnerCnxAcceptor cnxAcceptor;\n    \n    // list of all the followers\n    private final HashSet<LearnerHandler> learners =\n        new HashSet<LearnerHandler>();\n\n    /**\n     * Returns a copy of the current learner snapshot\n     */\n    public List<LearnerHandler> getLearners() {\n        synchronized (learners) {\n            return new ArrayList<LearnerHandler>(learners);\n        }\n    }\n\n    // list of followers that are ready to follow (i.e synced with the leader)\n    private final HashSet<LearnerHandler> forwardingFollowers =\n        new HashSet<LearnerHandler>();\n    \n    /**\n     * Returns a copy of the current forwarding follower snapshot\n     */\n    public List<LearnerHandler> getForwardingFollowers() {\n        synchronized (forwardingFollowers) {\n            return new ArrayList<LearnerHandler>(forwardingFollowers);\n        }\n    }\n\n    private void addForwardingFollower(LearnerHandler lh) {\n        synchronized (forwardingFollowers) {\n            forwardingFollowers.add(lh);\n        }\n    }\n\n    private final HashSet<LearnerHandler> observingLearners =\n        new HashSet<LearnerHandler>();\n        \n    /**\n     * Returns a copy of the current observer snapshot\n     */\n    public List<LearnerHandler> getObservingLearners() {\n        synchronized (observingLearners) {\n            return new ArrayList<LearnerHandler>(observingLearners);\n        }\n    }\n\n    private void addObserverLearnerHandler(LearnerHandler lh) {\n        synchronized (observingLearners) {\n            observingLearners.add(lh);\n        }\n    }\n\n    // Pending sync requests. Must access under 'this' lock.\n    private final HashMap<Long,List<LearnerSyncRequest>> pendingSyncs =\n        new HashMap<Long,List<LearnerSyncRequest>>();\n    \n    synchronized public int getNumPendingSyncs() {\n        return pendingSyncs.size();\n    }\n\n    //Follower counter\n    final AtomicLong followerCounter = new AtomicLong(-1);\n\n    /**\n     * Adds peer to the leader.\n     * \n     * @param learner\n     *                instance of learner handle\n     */\n    void addLearnerHandler(LearnerHandler learner) {\n        synchronized (learners) {\n            learners.add(learner);\n        }\n    }\n\n    /**\n     * Remove the learner from the learner list\n     * \n     * @param peer\n     */\n    void removeLearnerHandler(LearnerHandler peer) {\n        synchronized (forwardingFollowers) {\n            forwardingFollowers.remove(peer);            \n        }        \n        synchronized (learners) {\n            learners.remove(peer);\n        }\n        synchronized (observingLearners) {\n            observingLearners.remove(peer);\n        }\n    }\n\n    boolean isLearnerSynced(LearnerHandler peer){\n        synchronized (forwardingFollowers) {\n            return forwardingFollowers.contains(peer);\n        }        \n    }\n    \n    ServerSocket ss;\n\n    Leader(QuorumPeer self,LeaderZooKeeperServer zk) throws IOException {\n        this.self = self;\n        try {\n            if (self.getQuorumListenOnAllIPs()) {\n                ss = new ServerSocket(self.getQuorumAddress().getPort());\n            } else {\n                ss = new ServerSocket();\n            }\n            ss.setReuseAddress(true);\n            if (!self.getQuorumListenOnAllIPs()) {\n                ss.bind(self.getQuorumAddress());\n            }\n        } catch (BindException e) {\n            if (self.getQuorumListenOnAllIPs()) {\n                LOG.error(\"Couldn't bind to port \" + self.getQuorumAddress().getPort(), e);\n            } else {\n                LOG.error(\"Couldn't bind to \" + self.getQuorumAddress(), e);\n            }\n            throw e;\n        }\n        this.zk=zk;\n    }\n\n    /**\n     * This message is for follower to expect diff\n     */\n    final static int DIFF = 13;\n    \n    /**\n     * This is for follower to truncate its logs \n     */\n    final static int TRUNC = 14;\n    \n    /**\n     * This is for follower to download the snapshots\n     */\n    final static int SNAP = 15;\n    \n    /**\n     * This tells the leader that the connecting peer is actually an observer\n     */\n    final static int OBSERVERINFO = 16;\n    \n    /**\n     * This message type is sent by the leader to indicate it's zxid and if\n     * needed, its database.\n     */\n    final static int NEWLEADER = 10;\n\n    /**\n     * This message type is sent by a follower to pass the last zxid. This is here\n     * for backward compatibility purposes.\n     */\n    final static int FOLLOWERINFO = 11;\n\n    /**\n     * This message type is sent by the leader to indicate that the follower is\n     * now uptodate andt can start responding to clients.\n     */\n    final static int UPTODATE = 12;\n\n    /**\n     * This message is the first that a follower receives from the leader.\n     * It has the protocol version and the epoch of the leader.\n     */\n    public static final int LEADERINFO = 17;\n\n    /**\n     * This message is used by the follow to ack a proposed epoch.\n     */\n    public static final int ACKEPOCH = 18;\n    \n    /**\n     * This message type is sent to a leader to request and mutation operation.\n     * The payload will consist of a request header followed by a request.\n     */\n    final static int REQUEST = 1;\n\n    /**\n     * This message type is sent by a leader to propose a mutation.\n     */\n    public final static int PROPOSAL = 2;\n\n    /**\n     * This message type is sent by a follower after it has synced a proposal.\n     */\n    final static int ACK = 3;\n\n    /**\n     * This message type is sent by a leader to commit a proposal and cause\n     * followers to start serving the corresponding data.\n     */\n    final static int COMMIT = 4;\n\n    /**\n     * This message type is enchanged between follower and leader (initiated by\n     * follower) to determine liveliness.\n     */\n    final static int PING = 5;\n\n    /**\n     * This message type is to validate a session that should be active.\n     */\n    final static int REVALIDATE = 6;\n\n    /**\n     * This message is a reply to a synchronize command flushing the pipe\n     * between the leader and the follower.\n     */\n    final static int SYNC = 7;\n        \n    /**\n     * This message type informs observers of a committed proposal.\n     */\n    final static int INFORM = 8;\n\n    ConcurrentMap<Long, Proposal> outstandingProposals = new ConcurrentHashMap<Long, Proposal>();\n\n    ConcurrentLinkedQueue<Proposal> toBeApplied = new ConcurrentLinkedQueue<Proposal>();\n\n    Proposal newLeaderProposal = new Proposal();\n    \n    class LearnerCnxAcceptor extends ZooKeeperThread{\n        private volatile boolean stop = false;\n\n        public LearnerCnxAcceptor() {\n            super(\"LearnerCnxAcceptor-\" + ss.getLocalSocketAddress());\n        }\n\n        @Override\n        public void run() {\n            try {\n                while (!stop) {\n                    try{\n                        Socket s = ss.accept();\n                        // start with the initLimit, once the ack is processed\n                        // in LearnerHandler switch to the syncLimit\n                        s.setSoTimeout(self.tickTime * self.initLimit);\n                        s.setTcpNoDelay(nodelay);\n\n                        BufferedInputStream is = new BufferedInputStream(\n                                s.getInputStream());\n                        LearnerHandler fh = new LearnerHandler(s, is, Leader.this);\n                        fh.start();\n                    } catch (SocketException e) {\n                        if (stop) {\n                            LOG.info(\"exception while shutting down acceptor: \"\n                                    + e);\n\n                            // When Leader.shutdown() calls ss.close(),\n                            // the call to accept throws an exception.\n                            // We catch and set stop to true.\n                            stop = true;\n                        } else {\n                            throw e;\n                        }\n                    } catch (SaslException e){\n                        LOG.error(\"Exception while connecting to quorum learner\", e);\n                    }\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Exception while accepting follower\", e);\n            }\n        }\n        \n        public void halt() {\n            stop = true;\n        }\n    }\n\n    StateSummary leaderStateSummary;\n    \n    long epoch = -1;\n    boolean waitingForNewEpoch = true;\n    volatile boolean readyToStart = false;\n    \n    /**\n     * This method is main function that is called to lead\n     * \n     * @throws IOException\n     * @throws InterruptedException\n     */\n    void lead() throws IOException, InterruptedException {\n        self.end_fle = Time.currentElapsedTime();\n        long electionTimeTaken = self.end_fle - self.start_fle;\n        self.setElectionTimeTaken(electionTimeTaken);\n        LOG.info(\"LEADING - LEADER ELECTION TOOK - {}\", electionTimeTaken);\n        self.start_fle = 0;\n        self.end_fle = 0;\n\n        zk.registerJMX(new LeaderBean(this, zk), self.jmxLocalPeerBean);\n\n        try {\n            self.tick.set(0);\n            zk.loadData();\n            \n            leaderStateSummary = new StateSummary(self.getCurrentEpoch(), zk.getLastProcessedZxid());\n\n            // Start thread that waits for connection requests from \n            // new followers.\n            cnxAcceptor = new LearnerCnxAcceptor();\n            cnxAcceptor.start();\n            \n            readyToStart = true;\n            long epoch = getEpochToPropose(self.getId(), self.getAcceptedEpoch());\n            \n            zk.setZxid(ZxidUtils.makeZxid(epoch, 0));\n            \n            synchronized(this){\n                lastProposed = zk.getZxid();\n            }\n            \n            newLeaderProposal.packet = new QuorumPacket(NEWLEADER, zk.getZxid(),\n                    null, null);\n\n\n            if ((newLeaderProposal.packet.getZxid() & 0xffffffffL) != 0) {\n                LOG.info(\"NEWLEADER proposal has Zxid of \"\n                        + Long.toHexString(newLeaderProposal.packet.getZxid()));\n            }\n            \n            waitForEpochAck(self.getId(), leaderStateSummary);\n            self.setCurrentEpoch(epoch);\n\n            // We have to get at least a majority of servers in sync with\n            // us. We do this by waiting for the NEWLEADER packet to get\n            // acknowledged\n            try {\n                waitForNewLeaderAck(self.getId(), zk.getZxid(), LearnerType.PARTICIPANT);\n            } catch (InterruptedException e) {\n                shutdown(\"Waiting for a quorum of followers, only synced with sids: [ \"\n                        + getSidSetString(newLeaderProposal.ackSet) + \" ]\");\n                HashSet<Long> followerSet = new HashSet<Long>();\n                for (LearnerHandler f : learners)\n                    followerSet.add(f.getSid());\n                    \n                if (self.getQuorumVerifier().containsQuorum(followerSet)) {\n                    LOG.warn(\"Enough followers present. \"\n                            + \"Perhaps the initTicks need to be increased.\");\n                }\n                Thread.sleep(self.tickTime);\n                self.tick.incrementAndGet();\n                return;\n            }\n            \n            startZkServer();\n            \n            /**\n             * WARNING: do not use this for anything other than QA testing\n             * on a real cluster. Specifically to enable verification that quorum\n             * can handle the lower 32bit roll-over issue identified in\n             * ZOOKEEPER-1277. Without this option it would take a very long\n             * time (on order of a month say) to see the 4 billion writes\n             * necessary to cause the roll-over to occur.\n             * \n             * This field allows you to override the zxid of the server. Typically\n             * you'll want to set it to something like 0xfffffff0 and then\n             * start the quorum, run some operations and see the re-election.\n             */\n            String initialZxid = System.getProperty(\"zookeeper.testingonly.initialZxid\");\n            if (initialZxid != null) {\n                long zxid = Long.parseLong(initialZxid);\n                zk.setZxid((zk.getZxid() & 0xffffffff00000000L) | zxid);\n            }\n            \n            if (!System.getProperty(\"zookeeper.leaderServes\", \"yes\").equals(\"no\")) {\n                self.cnxnFactory.setZooKeeperServer(zk);\n            }\n            // Everything is a go, simply start counting the ticks\n            // WARNING: I couldn't find any wait statement on a synchronized\n            // block that would be notified by this notifyAll() call, so\n            // I commented it out\n            //synchronized (this) {\n            //    notifyAll();\n            //}\n            // We ping twice a tick, so we only update the tick every other\n            // iteration\n            boolean tickSkip = true;\n    \n            while (true) {\n                Thread.sleep(self.tickTime / 2);\n                if (!tickSkip) {\n                    self.tick.incrementAndGet();\n                }\n                HashSet<Long> syncedSet = new HashSet<Long>();\n\n                // lock on the followers when we use it.\n                syncedSet.add(self.getId());\n\n                for (LearnerHandler f : getLearners()) {\n                    // Synced set is used to check we have a supporting quorum, so only\n                    // PARTICIPANT, not OBSERVER, learners should be used\n                    if (f.synced() && f.getLearnerType() == LearnerType.PARTICIPANT) {\n                        syncedSet.add(f.getSid());\n                    }\n                    f.ping();\n                }\n\n                // check leader running status\n                if (!this.isRunning()) {\n                    shutdown(\"Unexpected internal error\");\n                    return;\n                }\n\n              if (!tickSkip && !self.getQuorumVerifier().containsQuorum(syncedSet)) {\n                //if (!tickSkip && syncedCount < self.quorumPeers.size() / 2) {\n                    // Lost quorum, shutdown\n                    shutdown(\"Not sufficient followers synced, only synced with sids: [ \"\n                            + getSidSetString(syncedSet) + \" ]\");\n                    // make sure the order is the same!\n                    // the leader goes to looking\n                    return;\n              } \n              tickSkip = !tickSkip;\n            }\n        } finally {\n            zk.unregisterJMX(this);\n        }\n    }\n\n    boolean isShutdown;\n\n    /**\n     * Close down all the LearnerHandlers\n     */\n    void shutdown(String reason) {\n        LOG.info(\"Shutting down\");\n\n        if (isShutdown) {\n            return;\n        }\n        \n        LOG.info(\"Shutdown called\",\n                new Exception(\"shutdown Leader! reason: \" + reason));\n\n        if (cnxAcceptor != null) {\n            cnxAcceptor.halt();\n        }\n        \n        // NIO should not accept conenctions\n        self.cnxnFactory.setZooKeeperServer(null);\n        try {\n            ss.close();\n        } catch (IOException e) {\n            LOG.warn(\"Ignoring unexpected exception during close\",e);\n        }\n        // clear all the connections\n        self.cnxnFactory.closeAll();\n        // shutdown the previous zk\n        if (zk != null) {\n            zk.shutdown();\n        }\n        synchronized (learners) {\n            for (Iterator<LearnerHandler> it = learners.iterator(); it\n                    .hasNext();) {\n                LearnerHandler f = it.next();\n                it.remove();\n                f.shutdown();\n            }\n        }\n        isShutdown = true;\n    }\n\n    /**\n     * Keep a count of acks that are received by the leader for a particular\n     * proposal\n     * \n     * @param zxid\n     *                the zxid of the proposal sent out\n     * @param followerAddr\n     */\n    synchronized public void processAck(long sid, long zxid, SocketAddress followerAddr) {\n        if (LOG.isTraceEnabled()) {\n            LOG.trace(\"Ack zxid: 0x{}\", Long.toHexString(zxid));\n            for (Proposal p : outstandingProposals.values()) {\n                long packetZxid = p.packet.getZxid();\n                LOG.trace(\"outstanding proposal: 0x{}\",\n                        Long.toHexString(packetZxid));\n            }\n            LOG.trace(\"outstanding proposals all\");\n        }\n\n        if ((zxid & 0xffffffffL) == 0) {\n            /*\n             * We no longer process NEWLEADER ack by this method. However,\n             * the learner sends ack back to the leader after it gets UPTODATE\n             * so we just ignore the message.\n             */\n            return;\n        }\n    \n        if (outstandingProposals.size() == 0) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"outstanding is 0\");\n            }\n            return;\n        }\n        if (lastCommitted >= zxid) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"proposal has already been committed, pzxid: 0x{} zxid: 0x{}\",\n                        Long.toHexString(lastCommitted), Long.toHexString(zxid));\n            }\n            // The proposal has already been committed\n            return;\n        }\n        Proposal p = outstandingProposals.get(zxid);\n        if (p == null) {\n            LOG.warn(\"Trying to commit future proposal: zxid 0x{} from {}\",\n                    Long.toHexString(zxid), followerAddr);\n            return;\n        }\n        \n        p.ackSet.add(sid);\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Count for zxid: 0x{} is {}\",\n                    Long.toHexString(zxid), p.ackSet.size());\n        }\n        if (self.getQuorumVerifier().containsQuorum(p.ackSet)){             \n            if (zxid != lastCommitted+1) {\n                LOG.warn(\"Commiting zxid 0x{} from {} not first!\",\n                        Long.toHexString(zxid), followerAddr);\n                LOG.warn(\"First is 0x{}\", Long.toHexString(lastCommitted + 1));\n            }\n            outstandingProposals.remove(zxid);\n            if (p.request != null) {\n                toBeApplied.add(p);\n            }\n\n            if (p.request == null) {\n                LOG.warn(\"Going to commmit null request for proposal: {}\", p);\n            }\n            commit(zxid);\n            inform(p);\n            zk.commitProcessor.commit(p.request);\n            if(pendingSyncs.containsKey(zxid)){\n                for(LearnerSyncRequest r: pendingSyncs.remove(zxid)) {\n                    sendSync(r);\n                }\n            }\n        }\n    }\n\n    static class ToBeAppliedRequestProcessor implements RequestProcessor {\n        private RequestProcessor next;\n\n        private ConcurrentLinkedQueue<Proposal> toBeApplied;\n\n        /**\n         * This request processor simply maintains the toBeApplied list. For\n         * this to work next must be a FinalRequestProcessor and\n         * FinalRequestProcessor.processRequest MUST process the request\n         * synchronously!\n         * \n         * @param next\n         *                a reference to the FinalRequestProcessor\n         */\n        ToBeAppliedRequestProcessor(RequestProcessor next,\n                ConcurrentLinkedQueue<Proposal> toBeApplied) {\n            if (!(next instanceof FinalRequestProcessor)) {\n                throw new RuntimeException(ToBeAppliedRequestProcessor.class\n                        .getName()\n                        + \" must be connected to \"\n                        + FinalRequestProcessor.class.getName()\n                        + \" not \"\n                        + next.getClass().getName());\n            }\n            this.toBeApplied = toBeApplied;\n            this.next = next;\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see org.apache.zookeeper.server.RequestProcessor#processRequest(org.apache.zookeeper.server.Request)\n         */\n        public void processRequest(Request request) throws RequestProcessorException {\n            // request.addRQRec(\">tobe\");\n            next.processRequest(request);\n            Proposal p = toBeApplied.peek();\n            if (p != null && p.request != null\n                    && p.request.zxid == request.zxid) {\n                toBeApplied.remove();\n            }\n        }\n\n        /*\n         * (non-Javadoc)\n         * \n         * @see org.apache.zookeeper.server.RequestProcessor#shutdown()\n         */\n        public void shutdown() {\n            LOG.info(\"Shutting down\");\n            next.shutdown();\n        }\n    }\n\n    /**\n     * send a packet to all the followers ready to follow\n     * \n     * @param qp\n     *                the packet to be sent\n     */\n    void sendPacket(QuorumPacket qp) {\n        synchronized (forwardingFollowers) {\n            for (LearnerHandler f : forwardingFollowers) {                \n                f.queuePacket(qp);\n            }\n        }\n    }\n    \n    /**\n     * send a packet to all observers     \n     */\n    void sendObserverPacket(QuorumPacket qp) {        \n        for (LearnerHandler f : getObservingLearners()) {\n            f.queuePacket(qp);\n        }\n    }\n\n    long lastCommitted = -1;\n\n    /**\n     * Create a commit packet and send it to all the members of the quorum\n     * \n     * @param zxid\n     */\n    public void commit(long zxid) {\n        synchronized(this){\n            lastCommitted = zxid;\n        }\n        QuorumPacket qp = new QuorumPacket(Leader.COMMIT, zxid, null, null);\n        sendPacket(qp);\n    }\n    \n    /**\n     * Create an inform packet and send it to all observers.\n     * @param zxid\n     * @param proposal\n     */\n    public void inform(Proposal proposal) {   \n        QuorumPacket qp = new QuorumPacket(Leader.INFORM, proposal.request.zxid, \n                                            proposal.packet.getData(), null);\n        sendObserverPacket(qp);\n    }\n\n    long lastProposed;\n\n    \n    /**\n     * Returns the current epoch of the leader.\n     * \n     * @return\n     */\n    public long getEpoch(){\n        return ZxidUtils.getEpochFromZxid(lastProposed);\n    }\n    \n    @SuppressWarnings(\"serial\")\n    public static class XidRolloverException extends Exception {\n        public XidRolloverException(String message) {\n            super(message);\n        }\n    }\n\n    /**\n     * create a proposal and send it out to all the members\n     * \n     * @param request\n     * @return the proposal that is queued to send to all the members\n     */\n    public Proposal propose(Request request) throws XidRolloverException {\n        /**\n         * Address the rollover issue. All lower 32bits set indicate a new leader\n         * election. Force a re-election instead. See ZOOKEEPER-1277\n         */\n        if ((request.zxid & 0xffffffffL) == 0xffffffffL) {\n            String msg =\n                    \"zxid lower 32 bits have rolled over, forcing re-election, and therefore new epoch start\";\n            shutdown(msg);\n            throw new XidRolloverException(msg);\n        }\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n        try {\n            request.hdr.serialize(boa, \"hdr\");\n            if (request.txn != null) {\n                request.txn.serialize(boa, \"txn\");\n            }\n            baos.close();\n        } catch (IOException e) {\n            LOG.warn(\"This really should be impossible\", e);\n        }\n        QuorumPacket pp = new QuorumPacket(Leader.PROPOSAL, request.zxid, \n                baos.toByteArray(), null);\n        \n        Proposal p = new Proposal();\n        p.packet = pp;\n        p.request = request;\n        synchronized (this) {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Proposing:: \" + request);\n            }\n\n            lastProposed = p.packet.getZxid();\n            outstandingProposals.put(lastProposed, p);\n            sendPacket(pp);\n        }\n        return p;\n    }\n            \n    /**\n     * Process sync requests\n     * \n     * @param r the request\n     */\n    \n    synchronized public void processSync(LearnerSyncRequest r){\n        if(outstandingProposals.isEmpty()){\n            sendSync(r);\n        } else {\n            List<LearnerSyncRequest> l = pendingSyncs.get(lastProposed);\n            if (l == null) {\n                l = new ArrayList<LearnerSyncRequest>();\n            }\n            l.add(r);\n            pendingSyncs.put(lastProposed, l);\n        }\n    }\n        \n    /**\n     * Sends a sync message to the appropriate server\n     * \n     * @param f\n     * @param r\n     */\n            \n    public void sendSync(LearnerSyncRequest r){\n        QuorumPacket qp = new QuorumPacket(Leader.SYNC, 0, null, null);\n        r.fh.queuePacket(qp);\n    }\n                \n    /**\n     * lets the leader know that a follower is capable of following and is done\n     * syncing\n     * \n     * @param handler handler of the follower\n     * @return last proposed zxid\n     */\n    synchronized public long startForwarding(LearnerHandler handler,\n            long lastSeenZxid) {\n        // Queue up any outstanding requests enabling the receipt of\n        // new requests\n        if (lastProposed > lastSeenZxid) {\n            for (Proposal p : toBeApplied) {\n                if (p.packet.getZxid() <= lastSeenZxid) {\n                    continue;\n                }\n                handler.queuePacket(p.packet);\n                // Since the proposal has been committed we need to send the\n                // commit message also\n                QuorumPacket qp = new QuorumPacket(Leader.COMMIT, p.packet\n                        .getZxid(), null, null);\n                handler.queuePacket(qp);\n            }\n            // Only participant need to get outstanding proposals\n            if (handler.getLearnerType() == LearnerType.PARTICIPANT) {\n                List<Long>zxids = new ArrayList<Long>(outstandingProposals.keySet());\n                Collections.sort(zxids);\n                for (Long zxid: zxids) {\n                    if (zxid <= lastSeenZxid) {\n                        continue;\n                    }\n                    handler.queuePacket(outstandingProposals.get(zxid).packet);\n                }\n            }\n        }\n        if (handler.getLearnerType() == LearnerType.PARTICIPANT) {\n            addForwardingFollower(handler);\n        } else {\n            addObserverLearnerHandler(handler);\n        }\n                \n        return lastProposed;\n    }\n\n    private HashSet<Long> connectingFollowers = new HashSet<Long>();\n    public long getEpochToPropose(long sid, long lastAcceptedEpoch) throws InterruptedException, IOException {\n        synchronized(connectingFollowers) {\n            if (!waitingForNewEpoch) {\n                return epoch;\n            }\n            if (lastAcceptedEpoch >= epoch) {\n                epoch = lastAcceptedEpoch+1;\n            }\n            connectingFollowers.add(sid);\n            QuorumVerifier verifier = self.getQuorumVerifier();\n            if (connectingFollowers.contains(self.getId()) && \n                                            verifier.containsQuorum(connectingFollowers)) {\n                waitingForNewEpoch = false;\n                self.setAcceptedEpoch(epoch);\n                connectingFollowers.notifyAll();\n            } else {\n                long start = Time.currentElapsedTime();\n                long cur = start;\n                long end = start + self.getInitLimit()*self.getTickTime();\n                while(waitingForNewEpoch && cur < end) {\n                    connectingFollowers.wait(end - cur);\n                    cur = Time.currentElapsedTime();\n                }\n                if (waitingForNewEpoch) {\n                    throw new InterruptedException(\"Timeout while waiting for epoch from quorum\");        \n                }\n            }\n            return epoch;\n        }\n    }\n\n    private HashSet<Long> electingFollowers = new HashSet<Long>();\n    private boolean electionFinished = false;\n    public void waitForEpochAck(long id, StateSummary ss) throws IOException, InterruptedException {\n        synchronized(electingFollowers) {\n            if (electionFinished) {\n                return;\n            }\n            if (ss.getCurrentEpoch() != -1) {\n                if (ss.isMoreRecentThan(leaderStateSummary)) {\n                    throw new IOException(\"Follower is ahead of the leader, leader summary: \" \n                                                    + leaderStateSummary.getCurrentEpoch()\n                                                    + \" (current epoch), \"\n                                                    + leaderStateSummary.getLastZxid()\n                                                    + \" (last zxid)\");\n                }\n                electingFollowers.add(id);\n            }\n            QuorumVerifier verifier = self.getQuorumVerifier();\n            if (electingFollowers.contains(self.getId()) && verifier.containsQuorum(electingFollowers)) {\n                electionFinished = true;\n                electingFollowers.notifyAll();\n            } else {                \n                long start = Time.currentElapsedTime();\n                long cur = start;\n                long end = start + self.getInitLimit()*self.getTickTime();\n                while(!electionFinished && cur < end) {\n                    electingFollowers.wait(end - cur);\n                    cur = Time.currentElapsedTime();\n                }\n                if (!electionFinished) {\n                    throw new InterruptedException(\"Timeout while waiting for epoch to be acked by quorum\");\n                }\n            }\n        }\n    }\n\n    /**\n     * Return a list of sid in set as string  \n     */\n    private String getSidSetString(Set<Long> sidSet) {\n        StringBuilder sids = new StringBuilder();\n        Iterator<Long> iter = sidSet.iterator();\n        while (iter.hasNext()) {\n            sids.append(iter.next());\n            if (!iter.hasNext()) {\n              break;\n            }\n            sids.append(\",\");\n        }\n        return sids.toString();\n    }\n\n    /**\n     * Start up Leader ZooKeeper server and initialize zxid to the new epoch\n     */\n    private synchronized void startZkServer() {\n        // Update lastCommitted and Db's zxid to a value representing the new epoch\n        lastCommitted = zk.getZxid();\n        LOG.info(\"Have quorum of supporters, sids: [ \"\n                + getSidSetString(newLeaderProposal.ackSet)\n                + \" ]; starting up and setting last processed zxid: 0x{}\",\n                Long.toHexString(zk.getZxid()));\n        zk.startup();\n        /*\n         * Update the election vote here to ensure that all members of the\n         * ensemble report the same vote to new servers that start up and\n         * send leader election notifications to the ensemble.\n         * \n         * @see https://issues.apache.org/jira/browse/ZOOKEEPER-1732\n         */\n        self.updateElectionVote(getEpoch());\n\n        zk.getZKDatabase().setlastProcessedZxid(zk.getZxid());\n    }\n\n    /**\n     * Process NEWLEADER ack of a given sid and wait until the leader receives\n     * sufficient acks.\n     *\n     * @param sid\n     * @param learnerType\n     * @throws InterruptedException\n     */\n    public void waitForNewLeaderAck(long sid, long zxid, LearnerType learnerType)\n            throws InterruptedException {\n\n        synchronized (newLeaderProposal.ackSet) {\n\n            if (quorumFormed) {\n                return;\n            }\n\n            long currentZxid = newLeaderProposal.packet.getZxid();\n            if (zxid != currentZxid) {\n                LOG.error(\"NEWLEADER ACK from sid: \" + sid\n                        + \" is from a different epoch - current 0x\"\n                        + Long.toHexString(currentZxid) + \" receieved 0x\"\n                        + Long.toHexString(zxid));\n                return;\n            }\n\n            if (learnerType == LearnerType.PARTICIPANT) {\n                newLeaderProposal.ackSet.add(sid);\n            }\n\n            if (self.getQuorumVerifier().containsQuorum(\n                    newLeaderProposal.ackSet)) {\n                quorumFormed = true;\n                newLeaderProposal.ackSet.notifyAll();\n            } else {\n                long start = Time.currentElapsedTime();\n                long cur = start;\n                long end = start + self.getInitLimit() * self.getTickTime();\n                while (!quorumFormed && cur < end) {\n                    newLeaderProposal.ackSet.wait(end - cur);\n                    cur = Time.currentElapsedTime();\n                }\n                if (!quorumFormed) {\n                    throw new InterruptedException(\n                            \"Timeout while waiting for NEWLEADER to be acked by quorum\");\n                }\n            }\n        }\n    }\n\n    /**\n     * Get string representation of a given packet type\n     * @param packetType\n     * @return string representing the packet type\n     */\n    public static String getPacketType(int packetType) {\n        switch (packetType) {\n        case DIFF:\n            return \"DIFF\";\n        case TRUNC:\n            return \"TRUNC\";\n        case SNAP:\n            return \"SNAP\";\n        case OBSERVERINFO:\n            return \"OBSERVERINFO\";\n        case NEWLEADER:\n            return \"NEWLEADER\";\n        case FOLLOWERINFO:\n            return \"FOLLOWERINFO\";\n        case UPTODATE:\n            return \"UPTODATE\";\n        case LEADERINFO:\n            return \"LEADERINFO\";\n        case ACKEPOCH:\n            return \"ACKEPOCH\";\n        case REQUEST:\n            return \"REQUEST\";\n        case PROPOSAL:\n            return \"PROPOSAL\";\n        case ACK:\n            return \"ACK\";\n        case COMMIT:\n            return \"COMMIT\";\n        case PING:\n            return \"PING\";\n        case REVALIDATE:\n            return \"REVALIDATE\";\n        case SYNC:\n            return \"SYNC\";\n        case INFORM:\n            return \"INFORM\";\n        default:\n            return \"UNKNOWN\";\n        }\n    }\n\n    private boolean isRunning() {\n        return self.isRunning() && zk.isRunning();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServerBean;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.quorum.LearnerHandler;\nimport org.apache.zookeeper.server.quorum.Leader;\n\n/**\n * Leader MBean interface implementation.\n */\npublic class LeaderBean extends ZooKeeperServerBean implements LeaderMXBean {\n    private final Leader leader;\n    \n    public LeaderBean(Leader leader, ZooKeeperServer zks) {\n        super(zks);\n        this.leader = leader;\n    }\n    \n    public String getName() {\n        return \"Leader\";\n    }\n\n    public String getCurrentZxid() {\n        return \"0x\" + Long.toHexString(zks.getZxid());\n    }\n    \n    public String followerInfo() {\n        StringBuilder sb = new StringBuilder();\n        for (LearnerHandler handler : leader.getLearners()) {\n            sb.append(handler.toString()).append(\"\\n\");\n        }\n        return sb.toString();\n    }\n\n    @Override\n    public long getElectionTimeTaken() {\n        return leader.self.getElectionTimeTaken();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderElection.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetSocketAddress;\nimport java.net.SocketException;\nimport java.nio.ByteBuffer;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Map.Entry;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\n\n/**\n * @deprecated This class has been deprecated as of release 3.4.0. \n */\n@Deprecated\npublic class LeaderElection implements Election  {\n    private static final Logger LOG = LoggerFactory.getLogger(LeaderElection.class);\n    protected static final Random epochGen = new Random();\n\n    protected QuorumPeer self;\n\n    public LeaderElection(QuorumPeer self) {\n        this.self = self;\n    }\n\n    protected static class ElectionResult {\n        public Vote vote;\n\n        public int count;\n\n        public Vote winner;\n\n        public int winningCount;\n\n        public int numValidVotes;\n    }\n\n    protected ElectionResult countVotes(HashMap<InetSocketAddress, Vote> votes, HashSet<Long> heardFrom) {\n        final ElectionResult result = new ElectionResult();\n        // Initialize with null vote\n        result.vote = new Vote(Long.MIN_VALUE, Long.MIN_VALUE);\n        result.winner = new Vote(Long.MIN_VALUE, Long.MIN_VALUE);\n\n        // First, filter out votes from unheard-from machines. Then\n        // make the views consistent. Sometimes peers will have\n        // different zxids for a server depending on timing.\n        final HashMap<InetSocketAddress, Vote> validVotes = new HashMap<InetSocketAddress, Vote>();\n        final Map<Long, Long> maxZxids = new HashMap<Long,Long>();\n        for (Map.Entry<InetSocketAddress, Vote> e : votes.entrySet()) {\n            // Only include votes from machines that we heard from\n            final Vote v = e.getValue();\n            if (heardFrom.contains(v.getId())) {\n                validVotes.put(e.getKey(), v);\n                Long val = maxZxids.get(v.getId());\n                if (val == null || val < v.getZxid()) {\n                    maxZxids.put(v.getId(), v.getZxid());\n            }\n                    }\n                }\n\n        // Make all zxids for a given vote id equal to the largest zxid seen for\n        // that id\n        for (Map.Entry<InetSocketAddress, Vote> e : validVotes.entrySet()) {\n            final Vote v = e.getValue();\n            Long zxid = maxZxids.get(v.getId());\n            if (v.getZxid() < zxid) {\n                // This is safe inside an iterator as per\n                // http://download.oracle.com/javase/1.5.0/docs/api/java/util/Map.Entry.html\n                e.setValue(new Vote(v.getId(), zxid, v.getElectionEpoch(), v.getPeerEpoch(), v.getState()));\n            }\n        }\n\n        result.numValidVotes = validVotes.size();\n\n        final HashMap<Vote, Integer> countTable = new HashMap<Vote, Integer>();\n        // Now do the tally\n        for (Vote v : validVotes.values()) {\n            Integer count = countTable.get(v);\n            if (count == null) {\n                count = 0;\n            }\n            countTable.put(v, count + 1);\n            if (v.getId() == result.vote.getId()) {\n                result.count++;\n            } else if (v.getZxid() > result.vote.getZxid()\n                    || (v.getZxid() == result.vote.getZxid() && v.getId() > result.vote.getId())) {\n                result.vote = v;\n                result.count = 1;\n            }\n        }\n        result.winningCount = 0;\n        LOG.info(\"Election tally: \");\n        for (Entry<Vote, Integer> entry : countTable.entrySet()) {\n            if (entry.getValue() > result.winningCount) {\n                result.winningCount = entry.getValue();\n                result.winner = entry.getKey();\n            }\n            LOG.info(entry.getKey().getId() + \"\\t-> \" + entry.getValue());\n        }\n        return result;\n    }\n\n    /**\n     * There is nothing to shutdown in this implementation of\n     * leader election, so we simply have an empty method.\n     */\n    public void shutdown(){}\n    \n    /**\n     * Invoked in QuorumPeer to find or elect a new leader.\n     * \n     * @throws InterruptedException\n     */\n    public Vote lookForLeader() throws InterruptedException {\n        try {\n            self.jmxLeaderElectionBean = new LeaderElectionBean();\n            MBeanRegistry.getInstance().register(\n                    self.jmxLeaderElectionBean, self.jmxLocalPeerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            self.jmxLeaderElectionBean = null;\n        }\n\n        try {\n            self.setCurrentVote(new Vote(self.getId(),\n                    self.getLastLoggedZxid()));\n            // We are going to look for a leader by casting a vote for ourself\n            byte requestBytes[] = new byte[4];\n            ByteBuffer requestBuffer = ByteBuffer.wrap(requestBytes);\n            byte responseBytes[] = new byte[28];\n            ByteBuffer responseBuffer = ByteBuffer.wrap(responseBytes);\n            /* The current vote for the leader. Initially me! */\n            DatagramSocket s = null;\n            try {\n                s = new DatagramSocket();\n                s.setSoTimeout(200);\n            } catch (SocketException e1) {\n                LOG.error(\"Socket exception when creating socket for leader election\", e1);\n                System.exit(4);\n            }\n            DatagramPacket requestPacket = new DatagramPacket(requestBytes,\n                    requestBytes.length);\n            DatagramPacket responsePacket = new DatagramPacket(responseBytes,\n                    responseBytes.length);\n            int xid = epochGen.nextInt();\n            while (self.isRunning()) {\n                HashMap<InetSocketAddress, Vote> votes =\n                    new HashMap<InetSocketAddress, Vote>(self.getVotingView().size());\n\n                requestBuffer.clear();\n                requestBuffer.putInt(xid);\n                requestPacket.setLength(4);\n                HashSet<Long> heardFrom = new HashSet<Long>();\n                for (QuorumServer server : self.getVotingView().values()) {\n                    LOG.info(\"Server address: \" + server.addr);\n                    try {\n                        requestPacket.setSocketAddress(server.addr);\n                    } catch (IllegalArgumentException e) {\n                        // Sun doesn't include the address that causes this\n                        // exception to be thrown, so we wrap the exception\n                        // in order to capture this critical detail.\n                        throw new IllegalArgumentException(\n                                \"Unable to set socket address on packet, msg:\"\n                                + e.getMessage() + \" with addr:\" + server.addr,\n                                e);\n                    }\n\n                    try {\n                        s.send(requestPacket);\n                        responsePacket.setLength(responseBytes.length);\n                        s.receive(responsePacket);\n                        if (responsePacket.getLength() != responseBytes.length) {\n                            LOG.error(\"Got a short response: \"\n                                    + responsePacket.getLength());\n                            continue;\n                        }\n                        responseBuffer.clear();\n                        int recvedXid = responseBuffer.getInt();\n                        if (recvedXid != xid) {\n                            LOG.error(\"Got bad xid: expected \" + xid\n                                    + \" got \" + recvedXid);\n                            continue;\n                        }\n                        long peerId = responseBuffer.getLong();\n                        heardFrom.add(peerId);\n                        //if(server.id != peerId){\n                            Vote vote = new Vote(responseBuffer.getLong(),\n                                responseBuffer.getLong());\n                            InetSocketAddress addr =\n                                (InetSocketAddress) responsePacket\n                                .getSocketAddress();\n                            votes.put(addr, vote);\n                        //}\n                    } catch (IOException e) {\n                        LOG.warn(\"Ignoring exception while looking for leader\",\n                                e);\n                        // Errors are okay, since hosts may be\n                        // down\n                    }\n                }\n\n                ElectionResult result = countVotes(votes, heardFrom);\n                // ZOOKEEPER-569:\n                // If no votes are received for live peers, reset to voting \n                // for ourselves as otherwise we may hang on to a vote \n                // for a dead peer                 \n                if (result.numValidVotes == 0) {\n                    self.setCurrentVote(new Vote(self.getId(),\n                            self.getLastLoggedZxid()));\n                } else {\n                    if (result.winner.getId() >= 0) {\n                        self.setCurrentVote(result.vote);\n                        // To do: this doesn't use a quorum verifier\n                        if (result.winningCount > (self.getVotingView().size() / 2)) {\n                            self.setCurrentVote(result.winner);\n                            s.close();\n                            Vote current = self.getCurrentVote();\n                            LOG.info(\"Found leader: my type is: \" + self.getLearnerType());\n                            /*\n                             * We want to make sure we implement the state machine\n                             * correctly. If we are a PARTICIPANT, once a leader\n                             * is elected we can move either to LEADING or \n                             * FOLLOWING. However if we are an OBSERVER, it is an\n                             * error to be elected as a Leader.\n                             */\n                            if (self.getLearnerType() == LearnerType.OBSERVER) {\n                                if (current.getId() == self.getId()) {\n                                    // This should never happen!\n                                    LOG.error(\"OBSERVER elected as leader!\");\n                                    Thread.sleep(100);\n                                }\n                                else {\n                                    self.setPeerState(ServerState.OBSERVING);\n                                    Thread.sleep(100);\n                                    return current;\n                                }\n                            } else {\n                                self.setPeerState((current.getId() == self.getId())\n                                        ? ServerState.LEADING: ServerState.FOLLOWING);\n                                if (self.getPeerState() == ServerState.FOLLOWING) {\n                                    Thread.sleep(100);\n                                }                            \n                                return current;\n                            }\n                        }\n                    }\n                }\n                Thread.sleep(1000);\n            }\n            return null;\n        } finally {\n            try {\n                if(self.jmxLeaderElectionBean != null){\n                    MBeanRegistry.getInstance().unregister(\n                            self.jmxLeaderElectionBean);\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Failed to unregister with JMX\", e);\n            }\n            self.jmxLeaderElectionBean = null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderElectionBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.util.Date;\n\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\n\n/**\n * Leader election MBean interface implementation\n */\npublic class LeaderElectionBean implements LeaderElectionMXBean, ZKMBeanInfo {\n    private final Date startTime = new Date();\n\n    public String getName() {\n        return \"LeaderElection\";\n    }\n\n    public boolean isHidden() {\n        return false;\n    }\n\n    public String getStartTime() {\n        return startTime.toString();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderElectionMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n\n/**\n * Leader election protocol MBean. \n */\npublic interface LeaderElectionMXBean {\n    /**\n     * \n     * @return the time when the leader election started\n     */\n    public String getStartTime();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServerMXBean;\n\n/**\n * Leader MBean.\n */\npublic interface LeaderMXBean extends ZooKeeperServerMXBean {\n    /**\n     * Current zxid of cluster.\n     */\n    public String getCurrentZxid();\n\n    /**\n     * @return information on current followers\n     */\n    public String followerInfo();\n\n    /**\n     * @return time taken for leader election in milliseconds.\n     */\n    public long getElectionTimeTaken();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LeaderZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.DataTreeBean;\nimport org.apache.zookeeper.server.FinalRequestProcessor;\nimport org.apache.zookeeper.server.PrepRequestProcessor;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport org.apache.zookeeper.server.SessionTrackerImpl;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * \n * Just like the standard ZooKeeperServer. We just replace the request\n * processors: PrepRequestProcessor -> ProposalRequestProcessor ->\n * CommitProcessor -> Leader.ToBeAppliedRequestProcessor ->\n * FinalRequestProcessor\n */\npublic class LeaderZooKeeperServer extends QuorumZooKeeperServer {\n    CommitProcessor commitProcessor;\n\n    /**\n     * @param port\n     * @param dataDir\n     * @throws IOException\n     */\n    LeaderZooKeeperServer(FileTxnSnapLog logFactory, QuorumPeer self,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb) throws IOException {\n        super(logFactory, self.tickTime, self.minSessionTimeout,\n                self.maxSessionTimeout, treeBuilder, zkDb, self);\n    }\n\n    public Leader getLeader(){\n        return self.leader;\n    }\n    \n    @Override\n    protected void setupRequestProcessors() {\n        RequestProcessor finalProcessor = new FinalRequestProcessor(this);\n        RequestProcessor toBeAppliedProcessor = new Leader.ToBeAppliedRequestProcessor(\n                finalProcessor, getLeader().toBeApplied);\n        commitProcessor = new CommitProcessor(toBeAppliedProcessor,\n                Long.toString(getServerId()), false,\n                getZooKeeperServerListener());\n        commitProcessor.start();\n        ProposalRequestProcessor proposalProcessor = new ProposalRequestProcessor(this,\n                commitProcessor);\n        proposalProcessor.initialize();\n        firstProcessor = new PrepRequestProcessor(this, proposalProcessor);\n        ((PrepRequestProcessor)firstProcessor).start();\n    }\n\n    @Override\n    public int getGlobalOutstandingLimit() {\n        return super.getGlobalOutstandingLimit() / (self.getQuorumSize() - 1);\n    }\n    \n    @Override\n    public void createSessionTracker() {\n        sessionTracker = new SessionTrackerImpl(this, getZKDatabase()\n                .getSessionWithTimeOuts(), tickTime, self.getId(),\n                getZooKeeperServerListener());\n    }\n    \n    @Override\n    protected void startSessionTracker() {\n        ((SessionTrackerImpl)sessionTracker).start();\n    }\n\n\n    public boolean touch(long sess, int to) {\n        return sessionTracker.touchSession(sess, to);\n    }\n\n    @Override\n    protected void registerJMX() {\n        // register with JMX\n        try {\n            jmxDataTreeBean = new DataTreeBean(getZKDatabase().getDataTree());\n            MBeanRegistry.getInstance().register(jmxDataTreeBean, jmxServerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxDataTreeBean = null;\n        }\n    }\n\n    public void registerJMX(LeaderBean leaderBean,\n            LocalPeerBean localPeerBean)\n    {\n        // register with JMX\n        if (self.jmxLeaderElectionBean != null) {\n            try {\n                MBeanRegistry.getInstance().unregister(self.jmxLeaderElectionBean);\n            } catch (Exception e) {\n                LOG.warn(\"Failed to register with JMX\", e);\n            }\n            self.jmxLeaderElectionBean = null;\n        }\n\n        try {\n            jmxServerBean = leaderBean;\n            MBeanRegistry.getInstance().register(leaderBean, localPeerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxServerBean = null;\n        }\n    }\n\n    @Override\n    protected void unregisterJMX() {\n        // unregister from JMX\n        try {\n            if (jmxDataTreeBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxDataTreeBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxDataTreeBean = null;\n    }\n\n    protected void unregisterJMX(Leader leader) {\n        // unregister from JMX\n        try {\n            if (jmxServerBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxServerBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxServerBean = null;\n    }\n    \n    @Override\n    public String getState() {\n        return \"leader\";\n    }\n\n    /**\n     * Returns the id of the associated QuorumPeer, which will do for a unique\n     * id of this server. \n     */\n    @Override\n    public long getServerId() {\n        return self.getId();\n    }    \n    \n    @Override\n    protected void revalidateSession(ServerCnxn cnxn, long sessionId,\n        int sessionTimeout) throws IOException {\n        super.revalidateSession(cnxn, sessionId, sessionTimeout);\n        try {\n            // setowner as the leader itself, unless updated\n            // via the follower handlers\n            setOwner(sessionId, ServerCnxn.me);\n        } catch (SessionExpiredException e) {\n            // this is ok, it just means that the session revalidation failed.\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Learner.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.ConnectException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.Map.Entry;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class is the superclass of two of the three main actors in a ZK\n * ensemble: Followers and Observers. Both Followers and Observers share \n * a good deal of code which is moved into Peer to avoid duplication. \n */\npublic class Learner {       \n    static class PacketInFlight {\n        TxnHeader hdr;\n        Record rec;\n    }\n    QuorumPeer self;\n    LearnerZooKeeperServer zk;\n    \n    protected BufferedOutputStream bufferedOutput;\n    \n    protected Socket sock;\n    \n    /**\n     * Socket getter\n     * @return \n     */\n    public Socket getSocket() {\n        return sock;\n    }\n    \n    protected InputArchive leaderIs;\n    protected OutputArchive leaderOs;  \n    /** the protocol version of the leader */\n    protected int leaderProtocolVersion = 0x01;\n    \n    protected static final Logger LOG = LoggerFactory.getLogger(Learner.class);\n\n    static final private boolean nodelay = System.getProperty(\"follower.nodelay\", \"true\").equals(\"true\");\n    static {\n        LOG.info(\"TCP NoDelay set to: \" + nodelay);\n    }   \n    \n    final ConcurrentHashMap<Long, ServerCnxn> pendingRevalidations =\n        new ConcurrentHashMap<Long, ServerCnxn>();\n    \n    public int getPendingRevalidationsCount() {\n        return pendingRevalidations.size();\n    }\n    \n    /**\n     * validate a session for a client\n     *\n     * @param clientId\n     *                the client to be revalidated\n     * @param timeout\n     *                the timeout for which the session is valid\n     * @return\n     * @throws IOException\n     */\n    void validateSession(ServerCnxn cnxn, long clientId, int timeout)\n            throws IOException {\n        LOG.info(\"Revalidating client: 0x\" + Long.toHexString(clientId));\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        DataOutputStream dos = new DataOutputStream(baos);\n        dos.writeLong(clientId);\n        dos.writeInt(timeout);\n        dos.close();\n        QuorumPacket qp = new QuorumPacket(Leader.REVALIDATE, -1, baos\n                .toByteArray(), null);\n        pendingRevalidations.put(clientId, cnxn);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG,\n                                     ZooTrace.SESSION_TRACE_MASK,\n                                     \"To validate session 0x\"\n                                     + Long.toHexString(clientId));\n        }\n        writePacket(qp, true);\n    }     \n    \n    /**\n     * write a packet to the leader\n     *\n     * @param pp\n     *                the proposal packet to be sent to the leader\n     * @throws IOException\n     */\n    void writePacket(QuorumPacket pp, boolean flush) throws IOException {\n        synchronized (leaderOs) {\n            if (pp != null) {\n                leaderOs.writeRecord(pp, \"packet\");\n            }\n            if (flush) {\n                bufferedOutput.flush();\n            }\n        }\n    }\n\n    /**\n     * read a packet from the leader\n     *\n     * @param pp\n     *                the packet to be instantiated\n     * @throws IOException\n     */\n    void readPacket(QuorumPacket pp) throws IOException {\n        synchronized (leaderIs) {\n            leaderIs.readRecord(pp, \"packet\");\n        }\n        long traceMask = ZooTrace.SERVER_PACKET_TRACE_MASK;\n        if (pp.getType() == Leader.PING) {\n            traceMask = ZooTrace.SERVER_PING_TRACE_MASK;\n        }\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logQuorumPacket(LOG, traceMask, 'i', pp);\n        }\n    }\n    \n    /**\n     * send a request packet to the leader\n     *\n     * @param request\n     *                the request from the client\n     * @throws IOException\n     */\n    void request(Request request) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        DataOutputStream oa = new DataOutputStream(baos);\n        oa.writeLong(request.sessionId);\n        oa.writeInt(request.cxid);\n        oa.writeInt(request.type);\n        if (request.request != null) {\n            request.request.rewind();\n            int len = request.request.remaining();\n            byte b[] = new byte[len];\n            request.request.get(b);\n            request.request.rewind();\n            oa.write(b);\n        }\n        oa.close();\n        QuorumPacket qp = new QuorumPacket(Leader.REQUEST, -1, baos\n                .toByteArray(), request.authInfo);\n        writePacket(qp, true);\n    }\n    \n    /**\n     * Returns the address of the node we think is the leader.\n     */\n    protected QuorumServer findLeader() {\n        QuorumServer leaderServer = null;\n        // Find the leader by id\n        Vote current = self.getCurrentVote();\n        for (QuorumServer s : self.getView().values()) {\n            if (s.id == current.getId()) {\n                // Ensure we have the leader's correct IP address before\n                // attempting to connect.\n                s.recreateSocketAddresses();\n                leaderServer = s;\n                break;\n            }\n        }\n        if (leaderServer == null) {\n            LOG.warn(\"Couldn't find the leader with id = \"\n                    + current.getId());\n        }\n        return leaderServer;\n    }\n    \n    /**\n     * Establish a connection with the Leader found by findLeader. Retries\n     * 5 times before giving up. \n     * @param addr - the address of the Leader to connect to.\n     * @throws IOException <li>if the socket connection fails on the 5th attempt</li>\n     * <li>if there is an authentication failure while connecting to leader</li>\n     * @throws ConnectException\n     * @throws InterruptedException\n     */\n    protected void connectToLeader(InetSocketAddress addr, String hostname)\n            throws IOException, ConnectException, InterruptedException {\n        sock = new Socket();        \n        sock.setSoTimeout(self.tickTime * self.initLimit);\n        for (int tries = 0; tries < 5; tries++) {\n            try {\n                sock.connect(addr, self.tickTime * self.syncLimit);\n                sock.setTcpNoDelay(nodelay);\n                break;\n            } catch (IOException e) {\n                if (tries == 4) {\n                    LOG.error(\"Unexpected exception\",e);\n                    throw e;\n                } else {\n                    LOG.warn(\"Unexpected exception, tries=\"+tries+\n                            \", connecting to \" + addr,e);\n                    sock = new Socket();\n                    sock.setSoTimeout(self.tickTime * self.initLimit);\n                }\n            }\n            Thread.sleep(1000);\n        }\n\n        self.authLearner.authenticate(sock, hostname);\n\n        leaderIs = BinaryInputArchive.getArchive(new BufferedInputStream(\n                sock.getInputStream()));\n        bufferedOutput = new BufferedOutputStream(sock.getOutputStream());\n        leaderOs = BinaryOutputArchive.getArchive(bufferedOutput);\n    }   \n    \n    /**\n     * Once connected to the leader, perform the handshake protocol to\n     * establish a following / observing connection. \n     * @param pktType\n     * @return the zxid the Leader sends for synchronization purposes.\n     * @throws IOException\n     */\n    protected long registerWithLeader(int pktType) throws IOException{\n        /*\n         * Send follower info, including last zxid and sid\n         */\n    \tlong lastLoggedZxid = self.getLastLoggedZxid();\n        QuorumPacket qp = new QuorumPacket();                \n        qp.setType(pktType);\n        qp.setZxid(ZxidUtils.makeZxid(self.getAcceptedEpoch(), 0));\n        \n        /*\n         * Add sid to payload\n         */\n        LearnerInfo li = new LearnerInfo(self.getId(), 0x10000);\n        ByteArrayOutputStream bsid = new ByteArrayOutputStream();\n        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(bsid);\n        boa.writeRecord(li, \"LearnerInfo\");\n        qp.setData(bsid.toByteArray());\n        \n        writePacket(qp, true);\n        readPacket(qp);        \n        final long newEpoch = ZxidUtils.getEpochFromZxid(qp.getZxid());\n\t\tif (qp.getType() == Leader.LEADERINFO) {\n        \t// we are connected to a 1.0 server so accept the new epoch and read the next packet\n        \tleaderProtocolVersion = ByteBuffer.wrap(qp.getData()).getInt();\n        \tbyte epochBytes[] = new byte[4];\n        \tfinal ByteBuffer wrappedEpochBytes = ByteBuffer.wrap(epochBytes);\n        \tif (newEpoch > self.getAcceptedEpoch()) {\n        \t\twrappedEpochBytes.putInt((int)self.getCurrentEpoch());\n        \t\tself.setAcceptedEpoch(newEpoch);\n        \t} else if (newEpoch == self.getAcceptedEpoch()) {\n        \t\t// since we have already acked an epoch equal to the leaders, we cannot ack\n        \t\t// again, but we still need to send our lastZxid to the leader so that we can\n        \t\t// sync with it if it does assume leadership of the epoch.\n        \t\t// the -1 indicates that this reply should not count as an ack for the new epoch\n                wrappedEpochBytes.putInt(-1);\n        \t} else {\n        \t\tthrow new IOException(\"Leaders epoch, \" + newEpoch + \" is less than accepted epoch, \" + self.getAcceptedEpoch());\n        \t}\n        \tQuorumPacket ackNewEpoch = new QuorumPacket(Leader.ACKEPOCH, lastLoggedZxid, epochBytes, null);\n        \twritePacket(ackNewEpoch, true);\n            return ZxidUtils.makeZxid(newEpoch, 0);\n        } else {\n        \tif (newEpoch > self.getAcceptedEpoch()) {\n        \t\tself.setAcceptedEpoch(newEpoch);\n        \t}\n            if (qp.getType() != Leader.NEWLEADER) {\n                LOG.error(\"First packet should have been NEWLEADER\");\n                throw new IOException(\"First packet should have been NEWLEADER\");\n            }\n            return qp.getZxid();\n        }\n    } \n    \n    /**\n     * Finally, synchronize our history with the Leader. \n     * @param newLeaderZxid\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    protected void syncWithLeader(long newLeaderZxid) throws IOException, InterruptedException{\n        QuorumPacket ack = new QuorumPacket(Leader.ACK, 0, null, null);\n        QuorumPacket qp = new QuorumPacket();\n        long newEpoch = ZxidUtils.getEpochFromZxid(newLeaderZxid);\n        // In the DIFF case we don't need to do a snapshot because the transactions will sync on top of any existing snapshot\n        // For SNAP and TRUNC the snapshot is needed to save that history\n        boolean snapshotNeeded = true;\n        readPacket(qp);\n        LinkedList<Long> packetsCommitted = new LinkedList<Long>();\n        LinkedList<PacketInFlight> packetsNotCommitted = new LinkedList<PacketInFlight>();\n        synchronized (zk) {\n            if (qp.getType() == Leader.DIFF) {\n                LOG.info(\"Getting a diff from the leader 0x{}\", Long.toHexString(qp.getZxid()));\n                snapshotNeeded = false;\n            }\n            else if (qp.getType() == Leader.SNAP) {\n                LOG.info(\"Getting a snapshot from leader 0x\" + Long.toHexString(qp.getZxid()));\n                // The leader is going to dump the database\n                // clear our own database and read\n                zk.getZKDatabase().clear();\n                zk.getZKDatabase().deserializeSnapshot(leaderIs);\n                String signature = leaderIs.readString(\"signature\");\n                if (!signature.equals(\"BenWasHere\")) {\n                    LOG.error(\"Missing signature. Got \" + signature);\n                    throw new IOException(\"Missing signature\");                   \n                }\n                zk.getZKDatabase().setlastProcessedZxid(qp.getZxid());\n            } else if (qp.getType() == Leader.TRUNC) {\n                //we need to truncate the log to the lastzxid of the leader\n                LOG.warn(\"Truncating log to get in sync with the leader 0x\"\n                        + Long.toHexString(qp.getZxid()));\n                boolean truncated=zk.getZKDatabase().truncateLog(qp.getZxid());\n                if (!truncated) {\n                    // not able to truncate the log\n                    LOG.error(\"Not able to truncate the log \"\n                            + Long.toHexString(qp.getZxid()));\n                    System.exit(13);\n                }\n                zk.getZKDatabase().setlastProcessedZxid(qp.getZxid());\n            }\n            else {\n                LOG.error(\"Got unexpected packet from leader \"\n                        + qp.getType() + \" exiting ... \" );\n                System.exit(13);\n\n            }\n            zk.createSessionTracker();\n            \n            long lastQueued = 0;\n\n            // in Zab V1.0 (ZK 3.4+) we might take a snapshot when we get the NEWLEADER message, but in pre V1.0\n            // we take the snapshot on the UPDATE message, since Zab V1.0 also gets the UPDATE (after the NEWLEADER)\n            // we need to make sure that we don't take the snapshot twice.\n            boolean isPreZAB1_0 = true;\n            //If we are not going to take the snapshot be sure the transactions are not applied in memory\n            // but written out to the transaction log\n            boolean writeToTxnLog = !snapshotNeeded;\n            // we are now going to start getting transactions to apply followed by an UPTODATE\n            outerLoop:\n            while (self.isRunning()) {\n                readPacket(qp);\n                switch(qp.getType()) {\n                case Leader.PROPOSAL:\n                    PacketInFlight pif = new PacketInFlight();\n                    pif.hdr = new TxnHeader();\n                    pif.rec = SerializeUtils.deserializeTxn(qp.getData(), pif.hdr);\n                    if (pif.hdr.getZxid() != lastQueued + 1) {\n                    LOG.warn(\"Got zxid 0x\"\n                            + Long.toHexString(pif.hdr.getZxid())\n                            + \" expected 0x\"\n                            + Long.toHexString(lastQueued + 1));\n                    }\n                    lastQueued = pif.hdr.getZxid();\n                    packetsNotCommitted.add(pif);\n                    break;\n                case Leader.COMMIT:\n                    if (!writeToTxnLog) {\n                        pif = packetsNotCommitted.peekFirst();\n                        if (pif.hdr.getZxid() != qp.getZxid()) {\n                            LOG.warn(\"Committing \" + qp.getZxid() + \", but next proposal is \" + pif.hdr.getZxid());\n                        } else {\n                            zk.processTxn(pif.hdr, pif.rec);\n                            packetsNotCommitted.remove();\n                        }\n                    } else {\n                        packetsCommitted.add(qp.getZxid());\n                    }\n                    break;\n                case Leader.INFORM:\n                    /*\n                     * Only observer get this type of packet. We treat this\n                     * as receiving PROPOSAL and COMMMIT.\n                     */\n                    PacketInFlight packet = new PacketInFlight();\n                    packet.hdr = new TxnHeader();\n                    packet.rec = SerializeUtils.deserializeTxn(qp.getData(), packet.hdr);\n                    // Log warning message if txn comes out-of-order\n                    if (packet.hdr.getZxid() != lastQueued + 1) {\n                        LOG.warn(\"Got zxid 0x\"\n                                + Long.toHexString(packet.hdr.getZxid())\n                                + \" expected 0x\"\n                                + Long.toHexString(lastQueued + 1));\n                    }\n                    lastQueued = packet.hdr.getZxid();\n                    if (!writeToTxnLog) {\n                        // Apply to db directly if we haven't taken the snapshot\n                        zk.processTxn(packet.hdr, packet.rec);\n                    } else {\n                        packetsNotCommitted.add(packet);\n                        packetsCommitted.add(qp.getZxid());\n                    }\n                    break;\n                case Leader.UPTODATE:\n                    if (isPreZAB1_0) {\n                        zk.takeSnapshot();\n                        self.setCurrentEpoch(newEpoch);\n                    }\n                    self.cnxnFactory.setZooKeeperServer(zk);                \n                    break outerLoop;\n                case Leader.NEWLEADER: // Getting NEWLEADER here instead of in discovery \n                    // means this is Zab 1.0\n                    // Create updatingEpoch file and remove it after current\n                    // epoch is set. QuorumPeer.loadDataBase() uses this file to\n                    // detect the case where the server was terminated after\n                    // taking a snapshot but before setting the current epoch.\n                    File updating = new File(self.getTxnFactory().getSnapDir(),\n                                        QuorumPeer.UPDATING_EPOCH_FILENAME);\n                    if (!updating.exists() && !updating.createNewFile()) {\n                        throw new IOException(\"Failed to create \" +\n                                              updating.toString());\n                    }\n                    if (snapshotNeeded) {\n                        zk.takeSnapshot();\n                    }\n                    self.setCurrentEpoch(newEpoch);\n                    if (!updating.delete()) {\n                        throw new IOException(\"Failed to delete \" +\n                                              updating.toString());\n                    }\n                    writeToTxnLog = true; //Anything after this needs to go to the transaction log, not applied directly in memory\n                    isPreZAB1_0 = false;\n                    writePacket(new QuorumPacket(Leader.ACK, newLeaderZxid, null, null), true);\n                    break;\n                }\n            }\n        }\n        ack.setZxid(ZxidUtils.makeZxid(newEpoch, 0));\n        writePacket(ack, true);\n        sock.setSoTimeout(self.tickTime * self.syncLimit);\n        zk.startup();\n        /*\n         * Update the election vote here to ensure that all members of the\n         * ensemble report the same vote to new servers that start up and\n         * send leader election notifications to the ensemble.\n         * \n         * @see https://issues.apache.org/jira/browse/ZOOKEEPER-1732\n         */\n        self.updateElectionVote(newEpoch);\n\n        // We need to log the stuff that came in between the snapshot and the uptodate\n        if (zk instanceof FollowerZooKeeperServer) {\n            FollowerZooKeeperServer fzk = (FollowerZooKeeperServer)zk;\n            for(PacketInFlight p: packetsNotCommitted) {\n                fzk.logRequest(p.hdr, p.rec);\n            }\n            for(Long zxid: packetsCommitted) {\n                fzk.commit(zxid);\n            }\n        } else if (zk instanceof ObserverZooKeeperServer) {\n            // Similar to follower, we need to log requests between the snapshot\n            // and UPTODATE\n            ObserverZooKeeperServer ozk = (ObserverZooKeeperServer) zk;\n            for (PacketInFlight p : packetsNotCommitted) {\n                Long zxid = packetsCommitted.peekFirst();\n                if (p.hdr.getZxid() != zxid) {\n                    // log warning message if there is no matching commit\n                    // old leader send outstanding proposal to observer\n                    LOG.warn(\"Committing \" + Long.toHexString(zxid)\n                            + \", but next proposal is \"\n                            + Long.toHexString(p.hdr.getZxid()));\n                    continue;\n                }\n                packetsCommitted.remove();\n                Request request = new Request(null, p.hdr.getClientId(),\n                        p.hdr.getCxid(), p.hdr.getType(), null, null);\n                request.txn = p.rec;\n                request.hdr = p.hdr;\n                ozk.commitRequest(request);\n            }\n        } else {\n            // New server type need to handle in-flight packets\n            throw new UnsupportedOperationException(\"Unknown server type\");\n        }\n    }\n    \n    protected void revalidate(QuorumPacket qp) throws IOException {\n        ByteArrayInputStream bis = new ByteArrayInputStream(qp\n                .getData());\n        DataInputStream dis = new DataInputStream(bis);\n        long sessionId = dis.readLong();\n        boolean valid = dis.readBoolean();\n        ServerCnxn cnxn = pendingRevalidations\n        .remove(sessionId);\n        if (cnxn == null) {\n            LOG.warn(\"Missing session 0x\"\n                    + Long.toHexString(sessionId)\n                    + \" for validation\");\n        } else {\n            zk.finishSessionInit(cnxn, valid);\n        }\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG,\n                    ZooTrace.SESSION_TRACE_MASK,\n                    \"Session 0x\" + Long.toHexString(sessionId)\n                    + \" is valid: \" + valid);\n        }\n    }\n        \n    protected void ping(QuorumPacket qp) throws IOException {\n        // Send back the ping with our session data\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        DataOutputStream dos = new DataOutputStream(bos);\n        HashMap<Long, Integer> touchTable = zk\n                .getTouchSnapshot();\n        for (Entry<Long, Integer> entry : touchTable.entrySet()) {\n            dos.writeLong(entry.getKey());\n            dos.writeInt(entry.getValue());\n        }\n        qp.setData(bos.toByteArray());\n        writePacket(qp, true);\n    }\n    \n    \n    /**\n     * Shutdown the Peer\n     */\n    public void shutdown() {\n        // set the zookeeper server to null\n        self.cnxnFactory.setZooKeeperServer(null);\n        // clear all the connections\n        self.cnxnFactory.closeAll();\n        // shutdown previous zookeeper\n        if (zk != null) {\n            zk.shutdown();\n        }\n    }\n\n    boolean isRunning() {\n        return self.isRunning() && zk.isRunning();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LearnerHandler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.util.LinkedList;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;\n\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.quorum.Leader.Proposal;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * There will be an instance of this class created by the Leader for each\n * learner. All communication with a learner is handled by this\n * class.\n */\npublic class LearnerHandler extends ZooKeeperThread {\n    private static final Logger LOG = LoggerFactory.getLogger(LearnerHandler.class);\n\n    protected final Socket sock;    \n\n    public Socket getSocket() {\n        return sock;\n    }\n\n    final Leader leader;\n\n    /** Deadline for receiving the next ack. If we are bootstrapping then\n     * it's based on the initLimit, if we are done bootstrapping it's based\n     * on the syncLimit. Once the deadline is past this learner should\n     * be considered no longer \"sync'd\" with the leader. */\n    volatile long tickOfNextAckDeadline;\n    \n    /**\n     * ZooKeeper server identifier of this learner\n     */\n    protected long sid = 0;\n    \n    long getSid(){\n        return sid;\n    }                    \n\n    protected int version = 0x1;\n    \n    int getVersion() {\n    \treturn version;\n    }\n    \n    /**\n     * The packets to be sent to the learner\n     */\n    final LinkedBlockingQueue<QuorumPacket> queuedPackets =\n        new LinkedBlockingQueue<QuorumPacket>();\n\n    /**\n     * This class controls the time that the Leader has been\n     * waiting for acknowledgement of a proposal from this Learner.\n     * If the time is above syncLimit, the connection will be closed.\n     * It keeps track of only one proposal at a time, when the ACK for\n     * that proposal arrives, it switches to the last proposal received\n     * or clears the value if there is no pending proposal.\n     */\n    private class SyncLimitCheck {\n        private boolean started = false;\n        private long currentZxid = 0;\n        private long currentTime = 0;\n        private long nextZxid = 0;\n        private long nextTime = 0;\n\n        public synchronized void start() {\n            started = true;\n        }\n\n        public synchronized void updateProposal(long zxid, long time) {\n            if (!started) {\n                return;\n            }\n            if (currentTime == 0) {\n                currentTime = time;\n                currentZxid = zxid;\n            } else {\n                nextTime = time;\n                nextZxid = zxid;\n            }\n        }\n\n        public synchronized void updateAck(long zxid) {\n             if (currentZxid == zxid) {\n                 currentTime = nextTime;\n                 currentZxid = nextZxid;\n                 nextTime = 0;\n                 nextZxid = 0;\n             } else if (nextZxid == zxid) {\n                 LOG.warn(\"ACK for \" + zxid + \" received before ACK for \" + currentZxid + \"!!!!\");\n                 nextTime = 0;\n                 nextZxid = 0;\n             }\n        }\n\n        public synchronized boolean check(long time) {\n            if (currentTime == 0) {\n                return true;\n            } else {\n                long msDelay = (time - currentTime) / 1000000;\n                return (msDelay < (leader.self.tickTime * leader.self.syncLimit));\n            }\n        }\n    };\n\n    private SyncLimitCheck syncLimitCheck = new SyncLimitCheck();\n\n    private BinaryInputArchive ia;\n\n    private BinaryOutputArchive oa;\n\n    private final BufferedInputStream bufferedInput;\n    private BufferedOutputStream bufferedOutput;\n\n    LearnerHandler(Socket sock, BufferedInputStream bufferedInput,\n                   Leader leader) throws IOException {\n        super(\"LearnerHandler-\" + sock.getRemoteSocketAddress());\n        this.sock = sock;\n        this.leader = leader;\n        this.bufferedInput = bufferedInput;\n        try {\n            leader.self.authServer.authenticate(sock,\n                    new DataInputStream(bufferedInput));\n        } catch (IOException e) {\n            LOG.error(\"Server failed to authenticate quorum learner, addr: {}, closing connection\",\n                    sock.getRemoteSocketAddress(), e);\n            try {\n                sock.close();\n            } catch (IOException ie) {\n                LOG.error(\"Exception while closing socket\", ie);\n            }\n            throw new SaslException(\"Authentication failure: \" + e.getMessage());\n        }\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"LearnerHandler \").append(sock);\n        sb.append(\" tickOfNextAckDeadline:\").append(tickOfNextAckDeadline());\n        sb.append(\" synced?:\").append(synced());\n        sb.append(\" queuedPacketLength:\").append(queuedPackets.size());\n        return sb.toString();\n    }\n\n    /**\n     * If this packet is queued, the sender thread will exit\n     */\n    final QuorumPacket proposalOfDeath = new QuorumPacket();\n\n    private LearnerType  learnerType = LearnerType.PARTICIPANT;\n    public LearnerType getLearnerType() {\n        return learnerType;\n    }\n\n    /**\n     * This method will use the thread to send packets added to the\n     * queuedPackets list\n     *\n     * @throws InterruptedException\n     */\n    private void sendPackets() throws InterruptedException {\n        long traceMask = ZooTrace.SERVER_PACKET_TRACE_MASK;\n        while (true) {\n            try {\n                QuorumPacket p;\n                p = queuedPackets.poll();\n                if (p == null) {\n                    bufferedOutput.flush();\n                    p = queuedPackets.take();\n                }\n\n                if (p == proposalOfDeath) {\n                    // Packet of death!\n                    break;\n                }\n                if (p.getType() == Leader.PING) {\n                    traceMask = ZooTrace.SERVER_PING_TRACE_MASK;\n                }\n                if (p.getType() == Leader.PROPOSAL) {\n                    syncLimitCheck.updateProposal(p.getZxid(), System.nanoTime());\n                }\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logQuorumPacket(LOG, traceMask, 'o', p);\n                }\n                oa.writeRecord(p, \"packet\");\n            } catch (IOException e) {\n                if (!sock.isClosed()) {\n                    LOG.warn(\"Unexpected exception at \" + this, e);\n                    try {\n                        // this will cause everything to shutdown on\n                        // this learner handler and will help notify\n                        // the learner/observer instantaneously\n                        sock.close();\n                    } catch(IOException ie) {\n                        LOG.warn(\"Error closing socket for handler \" + this, ie);\n                    }\n                }\n                break;\n            }\n        }\n    }\n\n    static public String packetToString(QuorumPacket p) {\n        String type = null;\n        String mess = null;\n        Record txn = null;\n        \n        switch (p.getType()) {\n        case Leader.ACK:\n            type = \"ACK\";\n            break;\n        case Leader.COMMIT:\n            type = \"COMMIT\";\n            break;\n        case Leader.FOLLOWERINFO:\n            type = \"FOLLOWERINFO\";\n            break;    \n        case Leader.NEWLEADER:\n            type = \"NEWLEADER\";\n            break;\n        case Leader.PING:\n            type = \"PING\";\n            break;\n        case Leader.PROPOSAL:\n            type = \"PROPOSAL\";\n            TxnHeader hdr = new TxnHeader();\n            try {\n                SerializeUtils.deserializeTxn(p.getData(), hdr);\n                // mess = \"transaction: \" + txn.toString();\n            } catch (IOException e) {\n                LOG.warn(\"Unexpected exception\",e);\n            }\n            break;\n        case Leader.REQUEST:\n            type = \"REQUEST\";\n            break;\n        case Leader.REVALIDATE:\n            type = \"REVALIDATE\";\n            ByteArrayInputStream bis = new ByteArrayInputStream(p.getData());\n            DataInputStream dis = new DataInputStream(bis);\n            try {\n                long id = dis.readLong();\n                mess = \" sessionid = \" + id;\n            } catch (IOException e) {\n                LOG.warn(\"Unexpected exception\", e);\n            }\n\n            break;\n        case Leader.UPTODATE:\n            type = \"UPTODATE\";\n            break;\n        default:\n            type = \"UNKNOWN\" + p.getType();\n        }\n        String entry = null;\n        if (type != null) {\n            entry = type + \" \" + Long.toHexString(p.getZxid()) + \" \" + mess;\n        }\n        return entry;\n    }\n\n    /**\n     * This thread will receive packets from the peer and process them and\n     * also listen to new connections from new peers.\n     */\n    @Override\n    public void run() {\n        try {\n            leader.addLearnerHandler(this);\n            tickOfNextAckDeadline = leader.self.tick.get()\n                    + leader.self.initLimit + leader.self.syncLimit;\n\n            ia = BinaryInputArchive.getArchive(bufferedInput);\n            bufferedOutput = new BufferedOutputStream(sock.getOutputStream());\n            oa = BinaryOutputArchive.getArchive(bufferedOutput);\n\n            QuorumPacket qp = new QuorumPacket();\n            ia.readRecord(qp, \"packet\");\n            if(qp.getType() != Leader.FOLLOWERINFO && qp.getType() != Leader.OBSERVERINFO){\n            \tLOG.error(\"First packet \" + qp.toString()\n                        + \" is not FOLLOWERINFO or OBSERVERINFO!\");\n                return;\n            }\n            byte learnerInfoData[] = qp.getData();\n            if (learnerInfoData != null) {\n            \tif (learnerInfoData.length == 8) {\n            \t\tByteBuffer bbsid = ByteBuffer.wrap(learnerInfoData);\n            \t\tthis.sid = bbsid.getLong();\n            \t} else {\n            \t\tLearnerInfo li = new LearnerInfo();\n            \t\tByteBufferInputStream.byteBuffer2Record(ByteBuffer.wrap(learnerInfoData), li);\n            \t\tthis.sid = li.getServerid();\n            \t\tthis.version = li.getProtocolVersion();\n            \t}\n            } else {\n            \tthis.sid = leader.followerCounter.getAndDecrement();\n            }\n\n            LOG.info(\"Follower sid: \" + sid + \" : info : \"\n                    + leader.self.quorumPeers.get(sid));\n                        \n            if (qp.getType() == Leader.OBSERVERINFO) {\n                  learnerType = LearnerType.OBSERVER;\n            }            \n            \n            long lastAcceptedEpoch = ZxidUtils.getEpochFromZxid(qp.getZxid());\n            \n            long peerLastZxid;\n            StateSummary ss = null;\n            long zxid = qp.getZxid();\n            long newEpoch = leader.getEpochToPropose(this.getSid(), lastAcceptedEpoch);\n            \n            if (this.getVersion() < 0x10000) {\n                // we are going to have to extrapolate the epoch information\n                long epoch = ZxidUtils.getEpochFromZxid(zxid);\n                ss = new StateSummary(epoch, zxid);\n                // fake the message\n                leader.waitForEpochAck(this.getSid(), ss);\n            } else {\n                byte ver[] = new byte[4];\n                ByteBuffer.wrap(ver).putInt(0x10000);\n                QuorumPacket newEpochPacket = new QuorumPacket(Leader.LEADERINFO, ZxidUtils.makeZxid(newEpoch, 0), ver, null);\n                oa.writeRecord(newEpochPacket, \"packet\");\n                bufferedOutput.flush();\n                QuorumPacket ackEpochPacket = new QuorumPacket();\n                ia.readRecord(ackEpochPacket, \"packet\");\n                if (ackEpochPacket.getType() != Leader.ACKEPOCH) {\n                    LOG.error(ackEpochPacket.toString()\n                            + \" is not ACKEPOCH\");\n                    return;\n\t\t\t\t}\n                ByteBuffer bbepoch = ByteBuffer.wrap(ackEpochPacket.getData());\n                ss = new StateSummary(bbepoch.getInt(), ackEpochPacket.getZxid());\n                leader.waitForEpochAck(this.getSid(), ss);\n            }\n            peerLastZxid = ss.getLastZxid();\n            \n            /* the default to send to the follower */\n            int packetToSend = Leader.SNAP;\n            long zxidToSend = 0;\n            long leaderLastZxid = 0;\n            /** the packets that the follower needs to get updates from **/\n            long updates = peerLastZxid;\n            \n            /* we are sending the diff check if we have proposals in memory to be able to \n             * send a diff to the \n             */ \n            ReentrantReadWriteLock lock = leader.zk.getZKDatabase().getLogLock();\n            ReadLock rl = lock.readLock();\n            try {\n                rl.lock();        \n                final long maxCommittedLog = leader.zk.getZKDatabase().getmaxCommittedLog();\n                final long minCommittedLog = leader.zk.getZKDatabase().getminCommittedLog();\n                LOG.info(\"Synchronizing with Follower sid: \" + sid\n                        +\" maxCommittedLog=0x\"+Long.toHexString(maxCommittedLog)\n                        +\" minCommittedLog=0x\"+Long.toHexString(minCommittedLog)\n                        +\" peerLastZxid=0x\"+Long.toHexString(peerLastZxid));\n\n                LinkedList<Proposal> proposals = leader.zk.getZKDatabase().getCommittedLog();\n\n                if (peerLastZxid == leader.zk.getZKDatabase().getDataTreeLastProcessedZxid()) {\n                    // Follower is already sync with us, send empty diff\n                    LOG.info(\"leader and follower are in sync, zxid=0x{}\",\n                            Long.toHexString(peerLastZxid));\n                    packetToSend = Leader.DIFF;\n                    zxidToSend = peerLastZxid;\n                } else if (proposals.size() != 0) {\n                    LOG.debug(\"proposal size is {}\", proposals.size());\n                    if ((maxCommittedLog >= peerLastZxid)\n                            && (minCommittedLog <= peerLastZxid)) {\n                        LOG.debug(\"Sending proposals to follower\");\n\n                        // as we look through proposals, this variable keeps track of previous\n                        // proposal Id.\n                        long prevProposalZxid = minCommittedLog;\n\n                        // Keep track of whether we are about to send the first packet.\n                        // Before sending the first packet, we have to tell the learner\n                        // whether to expect a trunc or a diff\n                        boolean firstPacket=true;\n\n                        // If we are here, we can use committedLog to sync with\n                        // follower. Then we only need to decide whether to\n                        // send trunc or not\n                        packetToSend = Leader.DIFF;\n                        zxidToSend = maxCommittedLog;\n\n                        for (Proposal propose: proposals) {\n                            // skip the proposals the peer already has\n                            if (propose.packet.getZxid() <= peerLastZxid) {\n                                prevProposalZxid = propose.packet.getZxid();\n                                continue;\n                            } else {\n                                // If we are sending the first packet, figure out whether to trunc\n                                // in case the follower has some proposals that the leader doesn't\n                                if (firstPacket) {\n                                    firstPacket = false;\n                                    // Does the peer have some proposals that the leader hasn't seen yet\n                                    if (prevProposalZxid < peerLastZxid) {\n                                        // send a trunc message before sending the diff\n                                        packetToSend = Leader.TRUNC;                                        \n                                        zxidToSend = prevProposalZxid;\n                                        updates = zxidToSend;\n                                    }\n                                }\n                                queuePacket(propose.packet);\n                                QuorumPacket qcommit = new QuorumPacket(Leader.COMMIT, propose.packet.getZxid(),\n                                        null, null);\n                                queuePacket(qcommit);\n                            }\n                        }\n                    } else if (peerLastZxid > maxCommittedLog) {\n                        LOG.debug(\"Sending TRUNC to follower zxidToSend=0x{} updates=0x{}\",\n                                Long.toHexString(maxCommittedLog),\n                                Long.toHexString(updates));\n\n                        packetToSend = Leader.TRUNC;\n                        zxidToSend = maxCommittedLog;\n                        updates = zxidToSend;\n                    } else {\n                        LOG.warn(\"Unhandled proposal scenario\");\n                    }\n                } else {\n                    // just let the state transfer happen\n                    LOG.debug(\"proposals is empty\");\n                }               \n\n                LOG.info(\"Sending \" + Leader.getPacketType(packetToSend));\n                leaderLastZxid = leader.startForwarding(this, updates);\n\n            } finally {\n                rl.unlock();\n            }\n\n             QuorumPacket newLeaderQP = new QuorumPacket(Leader.NEWLEADER,\n                    ZxidUtils.makeZxid(newEpoch, 0), null, null);\n             if (getVersion() < 0x10000) {\n                oa.writeRecord(newLeaderQP, \"packet\");\n            } else {\n                queuedPackets.add(newLeaderQP);\n            }\n            bufferedOutput.flush();\n            //Need to set the zxidToSend to the latest zxid\n            if (packetToSend == Leader.SNAP) {\n                zxidToSend = leader.zk.getZKDatabase().getDataTreeLastProcessedZxid();\n            }\n            oa.writeRecord(new QuorumPacket(packetToSend, zxidToSend, null, null), \"packet\");\n            bufferedOutput.flush();\n            \n            /* if we are not truncating or sending a diff just send a snapshot */\n            if (packetToSend == Leader.SNAP) {\n                LOG.info(\"Sending snapshot last zxid of peer is 0x\"\n                        + Long.toHexString(peerLastZxid) + \" \" \n                        + \" zxid of leader is 0x\"\n                        + Long.toHexString(leaderLastZxid)\n                        + \"sent zxid of db as 0x\" \n                        + Long.toHexString(zxidToSend));\n                // Dump data to peer\n                leader.zk.getZKDatabase().serializeSnapshot(oa);\n                oa.writeString(\"BenWasHere\", \"signature\");\n            }\n            bufferedOutput.flush();\n            \n            // Start sending packets\n            new Thread() {\n                public void run() {\n                    Thread.currentThread().setName(\n                            \"Sender-\" + sock.getRemoteSocketAddress());\n                    try {\n                        sendPackets();\n                    } catch (InterruptedException e) {\n                        LOG.warn(\"Unexpected interruption\",e);\n                    }\n                }\n            }.start();\n            \n            /*\n             * Have to wait for the first ACK, wait until \n             * the leader is ready, and only then we can\n             * start processing messages.\n             */\n            qp = new QuorumPacket();\n            ia.readRecord(qp, \"packet\");\n            if(qp.getType() != Leader.ACK){\n                LOG.error(\"Next packet was supposed to be an ACK\");\n                return;\n            }\n            LOG.info(\"Received NEWLEADER-ACK message from \" + getSid());\n            leader.waitForNewLeaderAck(getSid(), qp.getZxid(), getLearnerType());\n\n            syncLimitCheck.start();\n            \n            // now that the ack has been processed expect the syncLimit\n            sock.setSoTimeout(leader.self.tickTime * leader.self.syncLimit);\n\n            /*\n             * Wait until leader starts up\n             */\n            synchronized(leader.zk){\n                while(!leader.zk.isRunning() && !this.isInterrupted()){\n                    leader.zk.wait(20);\n                }\n            }\n            // Mutation packets will be queued during the serialize,\n            // so we need to mark when the peer can actually start\n            // using the data\n            //\n            queuedPackets.add(new QuorumPacket(Leader.UPTODATE, -1, null, null));\n\n            while (true) {\n                qp = new QuorumPacket();\n                ia.readRecord(qp, \"packet\");\n\n                long traceMask = ZooTrace.SERVER_PACKET_TRACE_MASK;\n                if (qp.getType() == Leader.PING) {\n                    traceMask = ZooTrace.SERVER_PING_TRACE_MASK;\n                }\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logQuorumPacket(LOG, traceMask, 'i', qp);\n                }\n                tickOfNextAckDeadline = leader.self.tick.get() + leader.self.syncLimit;\n\n\n                ByteBuffer bb;\n                long sessionId;\n                int cxid;\n                int type;\n\n                switch (qp.getType()) {\n                case Leader.ACK:\n                    if (this.learnerType == LearnerType.OBSERVER) {\n                        if (LOG.isDebugEnabled()) {\n                            LOG.debug(\"Received ACK from Observer  \" + this.sid);\n                        }\n                    }\n                    syncLimitCheck.updateAck(qp.getZxid());\n                    leader.processAck(this.sid, qp.getZxid(), sock.getLocalSocketAddress());\n                    break;\n                case Leader.PING:\n                    // Process the touches\n                    ByteArrayInputStream bis = new ByteArrayInputStream(qp\n                            .getData());\n                    DataInputStream dis = new DataInputStream(bis);\n                    while (dis.available() > 0) {\n                        long sess = dis.readLong();\n                        int to = dis.readInt();\n                        leader.zk.touch(sess, to);\n                    }\n                    break;\n                case Leader.REVALIDATE:\n                    bis = new ByteArrayInputStream(qp.getData());\n                    dis = new DataInputStream(bis);\n                    long id = dis.readLong();\n                    int to = dis.readInt();\n                    ByteArrayOutputStream bos = new ByteArrayOutputStream();\n                    DataOutputStream dos = new DataOutputStream(bos);\n                    dos.writeLong(id);\n                    boolean valid = leader.zk.touch(id, to);\n                    if (valid) {\n                        try {\n                            //set the session owner\n                            // as the follower that\n                            // owns the session\n                            leader.zk.setOwner(id, this);\n                        } catch (SessionExpiredException e) {\n                            LOG.error(\"Somehow session \" + Long.toHexString(id) + \" expired right after being renewed! (impossible)\", e);\n                        }\n                    }\n                    if (LOG.isTraceEnabled()) {\n                        ZooTrace.logTraceMessage(LOG,\n                                                 ZooTrace.SESSION_TRACE_MASK,\n                                                 \"Session 0x\" + Long.toHexString(id)\n                                                 + \" is valid: \"+ valid);\n                    }\n                    dos.writeBoolean(valid);\n                    qp.setData(bos.toByteArray());\n                    queuedPackets.add(qp);\n                    break;\n                case Leader.REQUEST:                    \n                    bb = ByteBuffer.wrap(qp.getData());\n                    sessionId = bb.getLong();\n                    cxid = bb.getInt();\n                    type = bb.getInt();\n                    bb = bb.slice();\n                    Request si;\n                    if(type == OpCode.sync){\n                        si = new LearnerSyncRequest(this, sessionId, cxid, type, bb, qp.getAuthinfo());\n                    } else {\n                        si = new Request(null, sessionId, cxid, type, bb, qp.getAuthinfo());\n                    }\n                    si.setOwner(this);\n                    leader.zk.submitRequest(si);\n                    break;\n                default:\n                    LOG.warn(\"unexpected quorum packet, type: {}\", packetToString(qp));\n                    break;\n                }\n            }\n        } catch (IOException e) {\n            if (sock != null && !sock.isClosed()) {\n                LOG.error(\"Unexpected exception causing shutdown while sock \"\n                        + \"still open\", e);\n            \t//close the socket to make sure the \n            \t//other side can see it being close\n            \ttry {\n            \t\tsock.close();\n            \t} catch(IOException ie) {\n            \t\t// do nothing\n            \t}\n            }\n        } catch (InterruptedException e) {\n            LOG.error(\"Unexpected exception causing shutdown\", e);\n        } finally {\n            LOG.warn(\"******* GOODBYE \" \n                    + (sock != null ? sock.getRemoteSocketAddress() : \"<null>\")\n                    + \" ********\");\n            shutdown();\n        }\n    }\n\n    public void shutdown() {\n        // Send the packet of death\n        try {\n            queuedPackets.put(proposalOfDeath);\n        } catch (InterruptedException e) {\n            LOG.warn(\"Ignoring unexpected exception\", e);\n        }\n        try {\n            if (sock != null && !sock.isClosed()) {\n                sock.close();\n            }\n        } catch (IOException e) {\n            LOG.warn(\"Ignoring unexpected exception during socket close\", e);\n        }\n        this.interrupt();\n        leader.removeLearnerHandler(this);\n    }\n\n    public long tickOfNextAckDeadline() {\n        return tickOfNextAckDeadline;\n    }\n\n    /**\n     * ping calls from the leader to the peers\n     */\n    public void ping() {\n        long id;\n        if (syncLimitCheck.check(System.nanoTime())) {\n            synchronized(leader) {\n                id = leader.lastProposed;\n            }\n            QuorumPacket ping = new QuorumPacket(Leader.PING, id, null, null);\n            queuePacket(ping);\n        } else {\n            LOG.warn(\"Closing connection to peer due to transaction timeout.\");\n            shutdown();\n        }\n    }\n\n    void queuePacket(QuorumPacket p) {\n        queuedPackets.add(p);\n    }\n\n    public boolean synced() {\n        return isAlive()\n        && leader.self.tick.get() <= tickOfNextAckDeadline;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LearnerSessionTracker.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.zookeeper.server.SessionTracker;\nimport org.apache.zookeeper.server.SessionTrackerImpl;\nimport org.apache.zookeeper.server.ZooKeeperServerListener;\n\n/**\n * This is really just a shell of a SessionTracker that tracks session activity\n * to be forwarded to the Leader using a PING.\n */\npublic class LearnerSessionTracker implements SessionTracker {\n    SessionExpirer expirer;\n\n    HashMap<Long, Integer> touchTable = new HashMap<Long, Integer>();\n    long serverId = 1;\n    long nextSessionId=0;\n    \n    private ConcurrentHashMap<Long, Integer> sessionsWithTimeouts;\n\n    public LearnerSessionTracker(SessionExpirer expirer,\n            ConcurrentHashMap<Long, Integer> sessionsWithTimeouts, long id,\n            ZooKeeperServerListener listener) {\n        this.expirer = expirer;\n        this.sessionsWithTimeouts = sessionsWithTimeouts;\n        this.serverId = id;\n        nextSessionId = SessionTrackerImpl.initializeNextSession(this.serverId);\n        \n    }\n\n    synchronized public void removeSession(long sessionId) {\n        sessionsWithTimeouts.remove(sessionId);\n        touchTable.remove(sessionId);\n    }\n\n    public void shutdown() {\n    }\n\n    synchronized public void addSession(long sessionId, int sessionTimeout) {\n        sessionsWithTimeouts.put(sessionId, sessionTimeout);\n        touchTable.put(sessionId, sessionTimeout);\n    }\n\n    synchronized public boolean touchSession(long sessionId, int sessionTimeout) {\n        touchTable.put(sessionId, sessionTimeout);\n        return true;\n    }\n\n    synchronized HashMap<Long, Integer> snapshot() {\n        HashMap<Long, Integer> oldTouchTable = touchTable;\n        touchTable = new HashMap<Long, Integer>();\n        return oldTouchTable;\n    }\n\n\n    synchronized public long createSession(int sessionTimeout) {\n        return (nextSessionId++);\n    }\n\n    public void checkSession(long sessionId, Object owner)  {\n        // Nothing to do here. Sessions are checked at the Leader\n    }\n    \n    public void setOwner(long sessionId, Object owner) {\n        // Nothing to do here. Sessions are checked at the Leader\n    }\n\n    public void dumpSessions(PrintWriter pwriter) {\n    \t// the original class didn't have tostring impl, so just\n    \t// dup what we had before\n    \tpwriter.println(toString());\n    }\n\n    public void setSessionClosing(long sessionId) {\n        // Nothing to do here.\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LearnerSyncRequest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.nio.ByteBuffer;\nimport java.util.List;\n\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.server.Request;\n\npublic class LearnerSyncRequest extends Request {\n\tLearnerHandler fh;\n\tpublic LearnerSyncRequest(LearnerHandler fh, long sessionId, int xid, int type,\n\t\t\tByteBuffer bb, List<Id> authInfo) {\n\t\tsuper(null, sessionId, xid, type, bb, authInfo);\n\t\tthis.fh = fh;\n\t}\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LearnerZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.util.HashMap;\n\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.DataTreeBean;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServerBean;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * Parent class for all ZooKeeperServers for Learners \n */\npublic abstract class LearnerZooKeeperServer extends QuorumZooKeeperServer {    \n    public LearnerZooKeeperServer(FileTxnSnapLog logFactory, int tickTime,\n            int minSessionTimeout, int maxSessionTimeout,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb, QuorumPeer self)\n        throws IOException\n    {\n        super(logFactory, tickTime, minSessionTimeout, maxSessionTimeout,\n                treeBuilder, zkDb, self);\n    }\n\n    /**\n     * Abstract method to return the learner associated with this server.\n     * Since the Learner may change under our feet (when QuorumPeer reassigns\n     * it) we can't simply take a reference here. Instead, we need the \n     * subclasses to implement this.     \n     */\n    abstract public Learner getLearner();        \n    \n    /**\n     * Returns the current state of the session tracker. This is only currently\n     * used by a Learner to build a ping response packet.\n     * \n     */\n    protected HashMap<Long, Integer> getTouchSnapshot() {\n        if (sessionTracker != null) {\n            return ((LearnerSessionTracker) sessionTracker).snapshot();\n        }\n        return new HashMap<Long, Integer>();\n    }\n    \n    /**\n     * Returns the id of the associated QuorumPeer, which will do for a unique\n     * id of this server. \n     */\n    @Override\n    public long getServerId() {\n        return self.getId();\n    }    \n    \n    @Override\n    public void createSessionTracker() {\n        sessionTracker = new LearnerSessionTracker(this, getZKDatabase()\n                .getSessionWithTimeOuts(), self.getId(),\n                getZooKeeperServerListener());\n    }\n    \n    @Override\n    protected void startSessionTracker() {}\n    \n    @Override\n    protected void revalidateSession(ServerCnxn cnxn, long sessionId,\n            int sessionTimeout) throws IOException {\n        getLearner().validateSession(cnxn, sessionId, sessionTimeout);\n    }\n    \n    @Override\n    protected void registerJMX() {\n        // register with JMX\n        try {\n            jmxDataTreeBean = new DataTreeBean(getZKDatabase().getDataTree());\n            MBeanRegistry.getInstance().register(jmxDataTreeBean, jmxServerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxDataTreeBean = null;\n        }\n    }\n\n    public void registerJMX(ZooKeeperServerBean serverBean,\n            LocalPeerBean localPeerBean)\n    {\n        // register with JMX\n        if (self.jmxLeaderElectionBean != null) {\n            try {\n                MBeanRegistry.getInstance().unregister(self.jmxLeaderElectionBean);\n            } catch (Exception e) {\n                LOG.warn(\"Failed to register with JMX\", e);\n            }\n            self.jmxLeaderElectionBean = null;\n        }\n\n        try {\n            jmxServerBean = serverBean;\n            MBeanRegistry.getInstance().register(serverBean, localPeerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxServerBean = null;\n        }\n    }\n\n    @Override\n    protected void unregisterJMX() {\n        // unregister from JMX\n        try {\n            if (jmxDataTreeBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxDataTreeBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxDataTreeBean = null;\n    }\n\n    protected void unregisterJMX(Learner peer) {\n        // unregister from JMX\n        try {\n            if (jmxServerBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxServerBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxServerBean = null;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LocalPeerBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n\n/**\n * Implementation of the local peer MBean interface.\n */\npublic class LocalPeerBean extends ServerBean implements LocalPeerMXBean {\n    private final QuorumPeer peer;\n    \n    public LocalPeerBean(QuorumPeer peer) {\n        this.peer = peer;\n    }\n\n    public String getName() {\n        return \"replica.\" + peer.getId();\n    }\n\n    public boolean isHidden() {\n        return false;\n    }\n\n    public int getTickTime() {\n        return peer.getTickTime();\n    }\n    \n    public int getMaxClientCnxnsPerHost() {\n        return peer.getMaxClientCnxnsPerHost();\n    }\n\n    public int getMinSessionTimeout() {\n        return peer.getMinSessionTimeout();\n    }\n    \n    public int getMaxSessionTimeout() {\n        return peer.getMaxSessionTimeout();\n    }\n    \n    public int getInitLimit() {\n        return peer.getInitLimit();\n    }\n    \n    public int getSyncLimit() {\n        return peer.getSyncLimit();\n    }\n    \n    public int getTick() {\n        return peer.getTick();\n    }\n    \n    public String getState() {\n        return peer.getServerState();\n    }\n    \n    public String getQuorumAddress() {\n        return peer.getQuorumAddress().toString();\n    }\n    \n    public int getElectionType() {\n        return peer.getElectionType();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n\n/**\n * A local zookeeper server MBean interface. Unlike the remote peer, the local\n * peer provides complete state/statistics at runtime and can be managed (just \n * like a standalone zookeeper server).\n */\npublic interface LocalPeerMXBean extends ServerMXBean {\n    \n    /**\n     * @return the number of milliseconds of each tick\n     */\n    public int getTickTime();\n    \n    /** Current maxClientCnxns allowed from a particular host */\n    public int getMaxClientCnxnsPerHost();\n\n    /**\n     * @return the minimum number of milliseconds allowed for a session timeout\n     */\n    public int getMinSessionTimeout();\n    \n    /**\n     * @return the maximum number of milliseconds allowed for a session timeout\n     */\n    public int getMaxSessionTimeout();\n    \n    /**\n     * @return the number of ticks that the initial sync phase can take\n     */\n    public int getInitLimit();\n    \n    /**\n     * @return the number of ticks that can pass between sending a request\n     * and getting a acknowledgment\n     */\n    public int getSyncLimit();\n    \n    /**\n     * @return the current tick\n     */\n    public int getTick();\n    \n    /**\n     * @return the current server state\n     */\n    public String getState();\n    \n    /**\n     * @return the quorum address\n     */\n    public String getQuorumAddress();\n    \n    /**\n     * @return the election type\n     */\n    public int getElectionType();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Observer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.server.ObserverBean;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * Observers are peers that do not take part in the atomic broadcast protocol.\n * Instead, they are informed of successful proposals by the Leader. Observers\n * therefore naturally act as a relay point for publishing the proposal stream\n * and can relieve Followers of some of the connection load. Observers may\n * submit proposals, but do not vote in their acceptance. \n *\n * See ZOOKEEPER-368 for a discussion of this feature. \n */\npublic class Observer extends Learner{      \n\n    Observer(QuorumPeer self,ObserverZooKeeperServer observerZooKeeperServer) {\n        this.self = self;\n        this.zk=observerZooKeeperServer;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Observer \").append(sock);        \n        sb.append(\" pendingRevalidationCount:\")\n            .append(pendingRevalidations.size());\n        return sb.toString();\n    }\n    \n    /**\n     * the main method called by the observer to observe the leader\n     *\n     * @throws InterruptedException\n     */\n    void observeLeader() throws InterruptedException {\n        zk.registerJMX(new ObserverBean(this, zk), self.jmxLocalPeerBean);\n\n        try {\n            QuorumServer leaderServer = findLeader();\n            LOG.info(\"Observing \" + leaderServer.addr);\n            try {\n                connectToLeader(leaderServer.addr, leaderServer.hostname);\n                long newLeaderZxid = registerWithLeader(Leader.OBSERVERINFO);\n\n                syncWithLeader(newLeaderZxid);\n                QuorumPacket qp = new QuorumPacket();\n                while (this.isRunning()) {\n                    readPacket(qp);\n                    processPacket(qp);                   \n                }\n            } catch (Exception e) {\n                LOG.warn(\"Exception when observing the leader\", e);\n                try {\n                    sock.close();\n                } catch (IOException e1) {\n                    e1.printStackTrace();\n                }\n    \n                // clear pending revalidations\n                pendingRevalidations.clear();\n            }\n        } finally {\n            zk.unregisterJMX(this);\n        }\n    }\n    \n    /**\n     * Controls the response of an observer to the receipt of a quorumpacket\n     * @param qp\n     * @throws IOException\n     */\n    protected void processPacket(QuorumPacket qp) throws IOException{\n        switch (qp.getType()) {\n        case Leader.PING:\n            ping(qp);\n            break;\n        case Leader.PROPOSAL:\n            LOG.warn(\"Ignoring proposal\");\n            break;\n        case Leader.COMMIT:\n            LOG.warn(\"Ignoring commit\");            \n            break;            \n        case Leader.UPTODATE:\n            LOG.error(\"Received an UPTODATE message after Observer started\");\n            break;\n        case Leader.REVALIDATE:\n            revalidate(qp);\n            break;\n        case Leader.SYNC:\n            ((ObserverZooKeeperServer)zk).sync();\n            break;\n        case Leader.INFORM:            \n            TxnHeader hdr = new TxnHeader();\n            Record txn = SerializeUtils.deserializeTxn(qp.getData(), hdr);\n            Request request = new Request (null, hdr.getClientId(), \n                                           hdr.getCxid(),\n                                           hdr.getType(), null, null);\n            request.txn = txn;\n            request.hdr = hdr;\n            ObserverZooKeeperServer obs = (ObserverZooKeeperServer)zk;\n            obs.commitRequest(request);            \n            break;\n        default:\n            LOG.error(\"Invalid packet type: {} received by Observer\", qp.getType());\n        }\n    }\n\n    /**\n     * Shutdown the Observer.\n     */\n    public void shutdown() {       \n        LOG.info(\"shutdown called\", new Exception(\"shutdown Observer\"));\n        super.shutdown();\n    }\n}\n\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ObserverMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServerMXBean;\n\n/**\n * Observer MX Bean interface, implemented by ObserverBean\n *\n */\npublic interface ObserverMXBean extends ZooKeeperServerMXBean {\n    /**\n     * @return count of pending revalidations\n     */\n    public int getPendingRevalidationCount();\n    \n    /**\n     * @return socket address\n     */\n    public String getQuorumAddress();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ObserverRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ZooKeeperCriticalThread;\nimport org.apache.zookeeper.server.ZooTrace;\n\n/**\n * This RequestProcessor forwards any requests that modify the state of the\n * system to the Leader.\n */\npublic class ObserverRequestProcessor extends ZooKeeperCriticalThread implements\n        RequestProcessor {\n    private static final Logger LOG = LoggerFactory.getLogger(ObserverRequestProcessor.class);\n\n    ObserverZooKeeperServer zks;\n\n    RequestProcessor nextProcessor;\n\n    // We keep a queue of requests. As requests get submitted they are \n    // stored here. The queue is drained in the run() method. \n    LinkedBlockingQueue<Request> queuedRequests = new LinkedBlockingQueue<Request>();\n\n    boolean finished = false;\n\n    /**\n     * Constructor - takes an ObserverZooKeeperServer to associate with\n     * and the next processor to pass requests to after we're finished. \n     * @param zks\n     * @param nextProcessor\n     */\n    public ObserverRequestProcessor(ObserverZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        super(\"ObserverRequestProcessor:\" + zks.getServerId(), zks\n                .getZooKeeperServerListener());\n        this.zks = zks;\n        this.nextProcessor = nextProcessor;\n    }\n\n    @Override\n    public void run() {\n        try {\n            while (!finished) {\n                Request request = queuedRequests.take();\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logRequest(LOG, ZooTrace.CLIENT_REQUEST_TRACE_MASK,\n                            'F', request, \"\");\n                }\n                if (request == Request.requestOfDeath) {\n                    break;\n                }\n                // We want to queue the request to be processed before we submit\n                // the request to the leader so that we are ready to receive\n                // the response\n                nextProcessor.processRequest(request);\n                \n                // We now ship the request to the leader. As with all\n                // other quorum operations, sync also follows this code\n                // path, but different from others, we need to keep track\n                // of the sync operations this Observer has pending, so we\n                // add it to pendingSyncs.\n                switch (request.type) {\n                case OpCode.sync:\n                    zks.pendingSyncs.add(request);\n                    zks.getObserver().request(request);\n                    break;\n                case OpCode.create:\n                case OpCode.delete:\n                case OpCode.setData:\n                case OpCode.setACL:\n                case OpCode.createSession:\n                case OpCode.closeSession:\n                case OpCode.multi:\n                    zks.getObserver().request(request);\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            handleException(this.getName(), e);\n        }\n        LOG.info(\"ObserverRequestProcessor exited loop!\");\n    }\n\n    /**\n     * Simply queue the request, which will be processed in FIFO order. \n     */\n    public void processRequest(Request request) {\n        if (!finished) {\n            queuedRequests.add(request);\n        }\n    }\n\n    /**\n     * Shutdown the processor.\n     */\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        finished = true;\n        queuedRequests.clear();\n        queuedRequests.add(Request.requestOfDeath);\n        nextProcessor.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ObserverZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.FinalRequestProcessor;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * A ZooKeeperServer for the Observer node type. Not much is different, but\n * we anticipate specializing the request processors in the future. \n *\n */\npublic class ObserverZooKeeperServer extends LearnerZooKeeperServer {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(ObserverZooKeeperServer.class);        \n    \n    /**\n     * Enable since request processor for writing txnlog to disk and\n     * take periodic snapshot. Default is ON.\n     */\n    \n    private boolean syncRequestProcessorEnabled = this.self.getSyncEnabled();\n    \n    /*\n     * Request processors\n     */\n    private CommitProcessor commitProcessor;\n    private SyncRequestProcessor syncProcessor;\n    \n    /*\n     * Pending sync requests\n     */\n    ConcurrentLinkedQueue<Request> pendingSyncs = \n        new ConcurrentLinkedQueue<Request>();\n        \n    ObserverZooKeeperServer(FileTxnSnapLog logFactory, QuorumPeer self,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb) throws IOException {\n        super(logFactory, self.tickTime, self.minSessionTimeout,\n                self.maxSessionTimeout, treeBuilder, zkDb, self);\n        LOG.info(\"syncEnabled =\" + syncRequestProcessorEnabled);\n    }\n    \n    public Observer getObserver() {\n        return self.observer;\n    }\n    \n    @Override\n    public Learner getLearner() {\n        return self.observer;\n    }       \n    \n    /**\n     * Unlike a Follower, which sees a full request only during the PROPOSAL\n     * phase, Observers get all the data required with the INFORM packet. \n     * This method commits a request that has been unpacked by from an INFORM\n     * received from the Leader. \n     *      \n     * @param request\n     */\n    public void commitRequest(Request request) {     \n        if (syncRequestProcessorEnabled) {\n            // Write to txnlog and take periodic snapshot\n            syncProcessor.processRequest(request);\n        }\n        commitProcessor.commit(request);        \n    }\n    \n    /**\n     * Set up the request processors for an Observer:\n     * firstProcesor->commitProcessor->finalProcessor\n     */\n    @Override\n    protected void setupRequestProcessors() {      \n        // We might consider changing the processor behaviour of \n        // Observers to, for example, remove the disk sync requirements.\n        // Currently, they behave almost exactly the same as followers.\n        RequestProcessor finalProcessor = new FinalRequestProcessor(this);\n        commitProcessor = new CommitProcessor(finalProcessor,\n                Long.toString(getServerId()), true,\n                getZooKeeperServerListener());\n        commitProcessor.start();\n        firstProcessor = new ObserverRequestProcessor(this, commitProcessor);\n        ((ObserverRequestProcessor) firstProcessor).start();\n\n        /*\n         * Observer should write to disk, so that the it won't request\n         * too old txn from the leader which may lead to getting an entire\n         * snapshot.\n         *\n         * However, this may degrade performance as it has to write to disk\n         * and do periodic snapshot which may double the memory requirements\n         */\n        if (syncRequestProcessorEnabled) {\n            syncProcessor = new SyncRequestProcessor(this, null);\n            syncProcessor.start();\n        }\n    }\n\n    /*\n     * Process a sync request\n     */\n    synchronized public void sync(){\n        if(pendingSyncs.size() ==0){\n            LOG.warn(\"Not expecting a sync.\");\n            return;\n        }\n                \n        Request r = pendingSyncs.remove();\n        commitProcessor.commit(r);\n    }\n    \n    @Override\n    public String getState() {\n        return \"observer\";\n    };    \n\n    @Override\n    public synchronized void shutdown() {\n        if (!canShutdown()) {\n            LOG.debug(\"ZooKeeper server is not running, so not proceeding to shutdown!\");\n            return;\n        }\n        super.shutdown();\n        if (syncRequestProcessorEnabled && syncProcessor != null) {\n            syncProcessor.shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ProposalRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.quorum.Leader.XidRolloverException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This RequestProcessor simply forwards requests to an AckRequestProcessor and\n * SyncRequestProcessor.\n */\npublic class ProposalRequestProcessor implements RequestProcessor {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(ProposalRequestProcessor.class);\n\n    LeaderZooKeeperServer zks;\n    \n    RequestProcessor nextProcessor;\n\n    SyncRequestProcessor syncProcessor;\n\n    public ProposalRequestProcessor(LeaderZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        this.zks = zks;\n        this.nextProcessor = nextProcessor;\n        AckRequestProcessor ackProcessor = new AckRequestProcessor(zks.getLeader());\n        syncProcessor = new SyncRequestProcessor(zks, ackProcessor);\n    }\n    \n    /**\n     * initialize this processor\n     */\n    public void initialize() {\n        syncProcessor.start();\n    }\n    \n    public void processRequest(Request request) throws RequestProcessorException {\n        // LOG.warn(\"Ack>>> cxid = \" + request.cxid + \" type = \" +\n        // request.type + \" id = \" + request.sessionId);\n        // request.addRQRec(\">prop\");\n                \n        \n        /* In the following IF-THEN-ELSE block, we process syncs on the leader. \n         * If the sync is coming from a follower, then the follower\n         * handler adds it to syncHandler. Otherwise, if it is a client of\n         * the leader that issued the sync command, then syncHandler won't \n         * contain the handler. In this case, we add it to syncHandler, and \n         * call processRequest on the next processor.\n         */\n        \n        if(request instanceof LearnerSyncRequest){\n            zks.getLeader().processSync((LearnerSyncRequest)request);\n        } else {\n                nextProcessor.processRequest(request);\n            if (request.hdr != null) {\n                // We need to sync and get consensus on any transactions\n                try {\n                    zks.getLeader().propose(request);\n                } catch (XidRolloverException e) {\n                    throw new RequestProcessorException(e.getMessage(), e);\n                }\n                syncProcessor.processRequest(request);\n            }\n        }\n    }\n\n    public void shutdown() {\n        LOG.info(\"Shutting down\");\n        nextProcessor.shutdown();\n        syncProcessor.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\n\npublic class QuorumBean implements QuorumMXBean, ZKMBeanInfo {\n    private final QuorumPeer peer;\n    private final String name;\n    \n    public QuorumBean(QuorumPeer peer){\n        this.peer = peer;\n        name = \"ReplicatedServer_id\" + peer.getMyid();\n    }\n    \n    public String getName() {\n        return name;\n    }\n    \n    public boolean isHidden() {\n        return false;\n    }\n    \n    public int getQuorumSize() {\n        return peer.getQuorumSize();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedInputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.nio.BufferUnderflowException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.UnresolvedAddressException;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Set;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthServer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class implements a connection manager for leader election using TCP. It\n * maintains one connection for every pair of servers. The tricky part is to\n * guarantee that there is exactly one connection for every pair of servers that\n * are operating correctly and that can communicate over the network.\n * \n * If two servers try to start a connection concurrently, then the connection\n * manager uses a very simple tie-breaking mechanism to decide which connection\n * to drop based on the IP addressed of the two parties. \n * \n * For every peer, the manager maintains a queue of messages to send. If the\n * connection to any particular peer drops, then the sender thread puts the\n * message back on the list. As this implementation currently uses a queue\n * implementation to maintain messages to send to another peer, we add the\n * message to the tail of the queue, thus changing the order of messages.\n * Although this is not a problem for the leader election, it could be a problem\n * when consolidating peer communication. This is to be verified, though.\n * \n */\n\npublic class QuorumCnxManager {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumCnxManager.class);\n\n    /*\n     * Maximum capacity of thread queues\n     */\n    static final int RECV_CAPACITY = 100;\n    // Initialized to 1 to prevent sending\n    // stale notifications to peers\n    static final int SEND_CAPACITY = 1;\n\n    static final int PACKETMAXSIZE = 1024 * 512;\n\n    /*\n     * Max buffer size to be read from the network.\n     */\n    static public final int maxBuffer = 2048;\n    \n    /*\n     * Negative counter for observer server ids.\n     */\n    \n    private AtomicLong observerCounter = new AtomicLong(-1);\n    \n    /*\n     * Connection time out value in milliseconds \n     */\n    \n    private int cnxTO = 5000;\n    \n    /*\n     * Local IP address\n     */\n    final long mySid;\n    final int socketTimeout;\n    final Map<Long, QuorumPeer.QuorumServer> view;\n    final boolean tcpKeepAlive = Boolean.getBoolean(\"zookeeper.tcpKeepAlive\");\n    final boolean listenOnAllIPs;\n    private ThreadPoolExecutor connectionExecutor;\n    private final Set<Long> inprogressConnections = Collections\n            .synchronizedSet(new HashSet<Long>());\n    private QuorumAuthServer authServer;\n    private QuorumAuthLearner authLearner;\n    private boolean quorumSaslAuthEnabled;\n    /*\n     * Counter to count connection processing threads.\n     */\n    private AtomicInteger connectionThreadCnt = new AtomicInteger(0);\n\n    /*\n     * Mapping from Peer to Thread number\n     */\n    final ConcurrentHashMap<Long, SendWorker> senderWorkerMap;\n    final ConcurrentHashMap<Long, ArrayBlockingQueue<ByteBuffer>> queueSendMap;\n    final ConcurrentHashMap<Long, ByteBuffer> lastMessageSent;\n\n    /*\n     * Reception queue\n     */\n    public final ArrayBlockingQueue<Message> recvQueue;\n    /*\n     * Object to synchronize access to recvQueue\n     */\n    private final Object recvQLock = new Object();\n\n    /*\n     * Shutdown flag\n     */\n\n    volatile boolean shutdown = false;\n\n    /*\n     * Listener thread\n     */\n    public final Listener listener;\n\n    /*\n     * Counter to count worker threads\n     */\n    private AtomicInteger threadCnt = new AtomicInteger(0);\n\n    static public class Message {\n        \n        Message(ByteBuffer buffer, long sid) {\n            this.buffer = buffer;\n            this.sid = sid;\n        }\n\n        ByteBuffer buffer;\n        long sid;\n    }\n\n    public QuorumCnxManager(final long mySid,\n                            Map<Long,QuorumPeer.QuorumServer> view,\n                            QuorumAuthServer authServer,\n                            QuorumAuthLearner authLearner,\n                            int socketTimeout,\n                            boolean listenOnAllIPs,\n                            int quorumCnxnThreadsSize,\n                            boolean quorumSaslAuthEnabled) {\n        this(mySid, view, authServer, authLearner, socketTimeout, listenOnAllIPs,\n                quorumCnxnThreadsSize, quorumSaslAuthEnabled, new ConcurrentHashMap<Long, SendWorker>());\n    }\n\n    // visible for testing\n    public QuorumCnxManager(final long mySid,\n                            Map<Long,QuorumPeer.QuorumServer> view,\n                            QuorumAuthServer authServer,\n                            QuorumAuthLearner authLearner,\n                            int socketTimeout,\n                            boolean listenOnAllIPs,\n                            int quorumCnxnThreadsSize,\n                            boolean quorumSaslAuthEnabled,\n                            ConcurrentHashMap<Long, SendWorker> senderWorkerMap) {\n        this.senderWorkerMap = senderWorkerMap;\n\n        this.recvQueue = new ArrayBlockingQueue<Message>(RECV_CAPACITY);\n        this.queueSendMap = new ConcurrentHashMap<Long, ArrayBlockingQueue<ByteBuffer>>();\n        this.lastMessageSent = new ConcurrentHashMap<Long, ByteBuffer>();\n        String cnxToValue = System.getProperty(\"zookeeper.cnxTimeout\");\n        if(cnxToValue != null){\n            this.cnxTO = Integer.parseInt(cnxToValue);\n        }\n\n        this.mySid = mySid;\n        this.socketTimeout = socketTimeout;\n        this.view = view;\n        this.listenOnAllIPs = listenOnAllIPs;\n\n        initializeAuth(mySid, authServer, authLearner, quorumCnxnThreadsSize,\n                quorumSaslAuthEnabled);\n\n        // Starts listener thread that waits for connection requests \n        listener = new Listener();\n    }\n\n    private void initializeAuth(final long mySid,\n            final QuorumAuthServer authServer,\n            final QuorumAuthLearner authLearner,\n            final int quorumCnxnThreadsSize,\n            final boolean quorumSaslAuthEnabled) {\n        this.authServer = authServer;\n        this.authLearner = authLearner;\n        this.quorumSaslAuthEnabled = quorumSaslAuthEnabled;\n        if (!this.quorumSaslAuthEnabled) {\n            LOG.debug(\"Not initializing connection executor as quorum sasl auth is disabled\");\n            return;\n        }\n\n        // init connection executors\n        final AtomicInteger threadIndex = new AtomicInteger(1);\n        SecurityManager s = System.getSecurityManager();\n        final ThreadGroup group = (s != null) ? s.getThreadGroup()\n                : Thread.currentThread().getThreadGroup();\n        ThreadFactory daemonThFactory = new ThreadFactory() {\n\n            @Override\n            public Thread newThread(Runnable r) {\n                Thread t = new Thread(group, r, \"QuorumConnectionThread-\"\n                        + \"[myid=\" + mySid + \"]-\"\n                        + threadIndex.getAndIncrement());\n                return t;\n            }\n        };\n        this.connectionExecutor = new ThreadPoolExecutor(3,\n                quorumCnxnThreadsSize, 60, TimeUnit.SECONDS,\n                new SynchronousQueue<Runnable>(), daemonThFactory);\n        this.connectionExecutor.allowCoreThreadTimeOut(true);\n    }\n\n    /**\n     * Invokes initiateConnection for testing purposes\n     * \n     * @param sid\n     */\n    public void testInitiateConnection(long sid) throws Exception {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Opening channel to server \" + sid);\n        }\n        Socket sock = new Socket();\n        setSockOpts(sock);\n        sock.connect(QuorumPeer.viewToVotingView(view).get(sid).electionAddr,\n                     cnxTO);\n        initiateConnection(sock, sid);\n    }\n    \n    /**\n     * If this server has initiated the connection, then it gives up on the\n     * connection if it loses challenge. Otherwise, it keeps the connection.\n     */\n    public void initiateConnection(final Socket sock, final Long sid) {\n        try {\n            startConnection(sock, sid);\n        } catch (IOException e) {\n            LOG.error(\"Exception while connecting, id: {}, addr: {}, closing learner connection\",\n                     new Object[] { sid, sock.getRemoteSocketAddress() }, e);\n            closeSocket(sock);\n            return;\n        }\n    }\n\n    /**\n     * Server will initiate the connection request to its peer server\n     * asynchronously via separate connection thread.\n     */\n    public void initiateConnectionAsync(final Socket sock, final Long sid) {\n        if(!inprogressConnections.add(sid)){\n            // simply return as there is a connection request to\n            // server 'sid' already in progress.\n            LOG.debug(\"Connection request to server id: {} is already in progress, so skipping this request\",\n                    sid);\n            closeSocket(sock);\n            return;\n        }\n        try {\n            connectionExecutor.execute(\n                    new QuorumConnectionReqThread(sock, sid));\n            connectionThreadCnt.incrementAndGet();\n        } catch (Throwable e) {\n            // Imp: Safer side catching all type of exceptions and remove 'sid'\n            // from inprogress connections. This is to avoid blocking further\n            // connection requests from this 'sid' in case of errors.\n            inprogressConnections.remove(sid);\n            LOG.error(\"Exception while submitting quorum connection request\", e);\n            closeSocket(sock);\n        }\n    }\n\n    /**\n     * Thread to send connection request to peer server.\n     */\n    private class QuorumConnectionReqThread extends ZooKeeperThread {\n        final Socket sock;\n        final Long sid;\n        QuorumConnectionReqThread(final Socket sock, final Long sid) {\n            super(\"QuorumConnectionReqThread-\" + sid);\n            this.sock = sock;\n            this.sid = sid;\n        }\n\n        @Override\n        public void run() {\n            try{\n                initiateConnection(sock, sid);\n            } finally {\n                inprogressConnections.remove(sid);\n            }\n        }\n    }\n\n    private boolean startConnection(Socket sock, Long sid)\n            throws IOException {\n        DataOutputStream dout = null;\n        DataInputStream din = null;\n        try {\n            // Sending id and challenge\n            dout = new DataOutputStream(sock.getOutputStream());\n            dout.writeLong(this.mySid);\n            dout.flush();\n\n            din = new DataInputStream(\n                    new BufferedInputStream(sock.getInputStream()));\n        } catch (IOException e) {\n            LOG.warn(\"Ignoring exception reading or writing challenge: \", e);\n            closeSocket(sock);\n            return false;\n        }\n\n        // authenticate learner\n        authLearner.authenticate(sock, view.get(sid).hostname);\n\n        // If lost the challenge, then drop the new connection\n        if (sid > this.mySid) {\n            LOG.info(\"Have smaller server identifier, so dropping the \" +\n                     \"connection: (\" + sid + \", \" + this.mySid + \")\");\n            closeSocket(sock);\n            // Otherwise proceed with the connection\n        } else {\n            SendWorker sw = new SendWorker(sock, sid);\n            RecvWorker rw = new RecvWorker(sock, din, sid, sw);\n            sw.setRecv(rw);\n\n            SendWorker vsw = senderWorkerMap.get(sid);\n            \n            if(vsw != null)\n                vsw.finish();\n            \n            senderWorkerMap.put(sid, sw);\n            queueSendMap.putIfAbsent(sid, new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY));\n            \n            sw.start();\n            rw.start();\n            \n            return true;    \n            \n        }\n        return false;\n    }\n\n    /**\n     * If this server receives a connection request, then it gives up on the new\n     * connection if it wins. Notice that it checks whether it has a connection\n     * to this server already or not. If it does, then it sends the smallest\n     * possible long value to lose the challenge.\n     * \n     */\n    public void receiveConnection(final Socket sock) {\n        DataInputStream din = null;\n        try {\n            din = new DataInputStream(\n                    new BufferedInputStream(sock.getInputStream()));\n\n            handleConnection(sock, din);\n        } catch (IOException e) {\n            LOG.error(\"Exception handling connection, addr: {}, closing server connection\",\n                     sock.getRemoteSocketAddress());\n            closeSocket(sock);\n        }\n    }\n\n    /**\n     * Server receives a connection request and handles it asynchronously via\n     * separate thread.\n     */\n    public void receiveConnectionAsync(final Socket sock) {\n        try {\n            connectionExecutor.execute(\n                    new QuorumConnectionReceiverThread(sock));\n            connectionThreadCnt.incrementAndGet();\n        } catch (Throwable e) {\n            LOG.error(\"Exception handling connection, addr: {}, closing server connection\",\n                     sock.getRemoteSocketAddress());\n            closeSocket(sock);\n        }\n    }\n\n    /**\n     * Thread to receive connection request from peer server.\n     */\n    private class QuorumConnectionReceiverThread extends ZooKeeperThread {\n        private final Socket sock;\n        QuorumConnectionReceiverThread(final Socket sock) {\n            super(\"QuorumConnectionReceiverThread-\" + sock.getRemoteSocketAddress());\n            this.sock = sock;\n        }\n\n        @Override\n        public void run() {\n            receiveConnection(sock);\n        }\n    }\n\n    private void handleConnection(Socket sock, DataInputStream din)\n            throws IOException {\n        Long sid = null;\n        try {\n            // Read server id\n            sid = din.readLong();\n            if (sid < 0) { // this is not a server id but a protocol version (see ZOOKEEPER-1633)\n                sid = din.readLong();\n\n                // next comes the #bytes in the remainder of the message\n                // note that 0 bytes is fine (old servers)\n                int num_remaining_bytes = din.readInt();\n                if (num_remaining_bytes < 0 || num_remaining_bytes > maxBuffer) {\n                    LOG.error(\"Unreasonable buffer length: {}\", num_remaining_bytes);\n                    closeSocket(sock);\n                    return;\n                }\n                byte[] b = new byte[num_remaining_bytes];\n\n                // remove the remainder of the message from din\n                int num_read = din.read(b);\n                if (num_read != num_remaining_bytes) {\n                    LOG.error(\"Read only \" + num_read + \" bytes out of \" + num_remaining_bytes + \" sent by server \" + sid);\n                }\n            }\n            if (sid == QuorumPeer.OBSERVER_ID) {\n                /*\n                 * Choose identifier at random. We need a value to identify\n                 * the connection.\n                 */\n                sid = observerCounter.getAndDecrement();\n                LOG.info(\"Setting arbitrary identifier to observer: \" + sid);\n            }\n        } catch (IOException e) {\n            closeSocket(sock);\n            LOG.warn(\"Exception reading or writing challenge: \" + e.toString());\n            return;\n        }\n\n        // do authenticating learner\n        LOG.debug(\"Authenticating learner server.id: {}\", sid);\n        authServer.authenticate(sock, din);\n\n        //If wins the challenge, then close the new connection.\n        if (sid < this.mySid) {\n            /*\n             * This replica might still believe that the connection to sid is\n             * up, so we have to shut down the workers before trying to open a\n             * new connection.\n             */\n            SendWorker sw = senderWorkerMap.get(sid);\n            if (sw != null) {\n                sw.finish();\n            }\n\n            /*\n             * Now we start a new connection\n             */\n            LOG.debug(\"Create new connection to server: \" + sid);\n            closeSocket(sock);\n            connectOne(sid);\n\n            // Otherwise start worker threads to receive data.\n        } else {\n            SendWorker sw = new SendWorker(sock, sid);\n            RecvWorker rw = new RecvWorker(sock, din, sid, sw);\n            sw.setRecv(rw);\n\n            SendWorker vsw = senderWorkerMap.get(sid);\n            \n            if(vsw != null)\n                vsw.finish();\n            \n            senderWorkerMap.put(sid, sw);\n            queueSendMap.putIfAbsent(sid, new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY));\n            \n            sw.start();\n            rw.start();\n            \n            return;\n        }\n    }\n\n    /**\n     * Processes invoke this message to queue a message to send. Currently, \n     * only leader election uses it.\n     */\n    public void toSend(Long sid, ByteBuffer b) {\n        /*\n         * If sending message to myself, then simply enqueue it (loopback).\n         */\n        if (this.mySid == sid) {\n             b.position(0);\n             addToRecvQueue(new Message(b.duplicate(), sid));\n            /*\n             * Otherwise send to the corresponding thread to send.\n             */\n        } else {\n             /*\n              * Start a new connection if doesn't have one already.\n              */\n             ArrayBlockingQueue<ByteBuffer> bq = new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY);\n             ArrayBlockingQueue<ByteBuffer> bqExisting = queueSendMap.putIfAbsent(sid, bq);\n             if (bqExisting != null) {\n                 addToSendQueue(bqExisting, b);\n             } else {\n                 addToSendQueue(bq, b);\n             }\n             connectOne(sid);\n                \n        }\n    }\n    \n    /**\n     * Try to establish a connection to server with id sid.\n     * \n     *  @param sid  server id\n     */\n    synchronized public void connectOne(long sid){\n        if (!connectedToPeer(sid)){\n            InetSocketAddress electionAddr;\n            if (view.containsKey(sid)) {\n                electionAddr = view.get(sid).electionAddr;\n            } else {\n                LOG.warn(\"Invalid server id: \" + sid);\n                return;\n            }\n            try {\n\n                LOG.debug(\"Opening channel to server \" + sid);\n                Socket sock = new Socket();\n                setSockOpts(sock);\n                sock.connect(view.get(sid).electionAddr, cnxTO);\n                LOG.debug(\"Connected to server \" + sid);\n\n                // Sends connection request asynchronously if the quorum\n                // sasl authentication is enabled. This is required because\n                // sasl server authentication process may take few seconds to\n                // finish, this may delay next peer connection requests.\n                if (quorumSaslAuthEnabled) {\n                    initiateConnectionAsync(sock, sid);\n                } else {\n                    initiateConnection(sock, sid);\n                }\n            } catch (UnresolvedAddressException e) {\n                // Sun doesn't include the address that causes this\n                // exception to be thrown, also UAE cannot be wrapped cleanly\n                // so we log the exception in order to capture this critical\n                // detail.\n                LOG.warn(\"Cannot open channel to \" + sid\n                        + \" at election address \" + electionAddr, e);\n                // Resolve hostname for this server in case the\n                // underlying ip address has changed.\n                if (view.containsKey(sid)) {\n                    view.get(sid).recreateSocketAddresses();\n                }\n                throw e;\n            } catch (IOException e) {\n                LOG.warn(\"Cannot open channel to \" + sid\n                        + \" at election address \" + electionAddr,\n                        e);\n                // We can't really tell if the server is actually down or it failed\n                // to connect to the server because the underlying IP address\n                // changed. Resolve the hostname again just in case.\n                if (view.containsKey(sid)) {\n                    view.get(sid).recreateSocketAddresses();\n                }\n            }\n        } else {\n            LOG.debug(\"There is a connection already for server \" + sid);\n        }\n    }\n    \n    \n    /**\n     * Try to establish a connection with each server if one\n     * doesn't exist.\n     */\n    \n    public void connectAll(){\n        long sid;\n        for(Enumeration<Long> en = queueSendMap.keys();\n            en.hasMoreElements();){\n            sid = en.nextElement();\n            connectOne(sid);\n        }      \n    }\n    \n\n    /**\n     * Check if all queues are empty, indicating that all messages have been delivered.\n     */\n    boolean haveDelivered() {\n        for (ArrayBlockingQueue<ByteBuffer> queue : queueSendMap.values()) {\n            LOG.debug(\"Queue size: \" + queue.size());\n            if (queue.size() == 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Flag that it is time to wrap up all activities and interrupt the listener.\n     */\n    public void halt() {\n        shutdown = true;\n        LOG.debug(\"Halting listener\");\n        listener.halt();\n        \n        softHalt();\n\n        // clear data structures used for auth\n        if (connectionExecutor != null) {\n            connectionExecutor.shutdown();\n        }\n        inprogressConnections.clear();\n        resetConnectionThreadCount();\n    }\n   \n    /**\n     * A soft halt simply finishes workers.\n     */\n    public void softHalt() {\n        for (SendWorker sw : senderWorkerMap.values()) {\n            LOG.debug(\"Halting sender: \" + sw);\n            sw.finish();\n        }\n    }\n\n    /**\n     * Helper method to set socket options.\n     * \n     * @param sock\n     *            Reference to socket\n     */\n    private void setSockOpts(Socket sock) throws SocketException {\n        sock.setTcpNoDelay(true);\n        sock.setKeepAlive(tcpKeepAlive);\n        sock.setSoTimeout(socketTimeout);\n    }\n\n    /**\n     * Helper method to close a socket.\n     * \n     * @param sock\n     *            Reference to socket\n     */\n    private void closeSocket(Socket sock) {\n        try {\n            sock.close();\n        } catch (IOException ie) {\n            LOG.error(\"Exception while closing\", ie);\n        }\n    }\n\n    /**\n     * Return number of worker threads\n     */\n    public long getThreadCount() {\n        return threadCnt.get();\n    }\n\n    /**\n     * Return number of connection processing threads.\n     */\n    public long getConnectionThreadCount() {\n        return connectionThreadCnt.get();\n    }\n\n    /**\n     * Reset the value of connection processing threads count to zero.\n     */\n    private void resetConnectionThreadCount() {\n        connectionThreadCnt.set(0);\n    }\n\n    /**\n     * Thread to listen on some port\n     */\n    public class Listener extends ZooKeeperThread {\n\n        volatile ServerSocket ss = null;\n\n        public Listener() {\n            // During startup of thread, thread name will be overridden to\n            // specific election address\n            super(\"ListenerThread\");\n        }\n\n        /**\n         * Sleeps on accept().\n         */\n        @Override\n        public void run() {\n            int numRetries = 0;\n            InetSocketAddress addr;\n            while((!shutdown) && (numRetries < 3)){\n                try {\n                    ss = new ServerSocket();\n                    ss.setReuseAddress(true);\n                    if (listenOnAllIPs) {\n                        int port = view.get(QuorumCnxManager.this.mySid)\n                            .electionAddr.getPort();\n                        addr = new InetSocketAddress(port);\n                    } else {\n                        addr = view.get(QuorumCnxManager.this.mySid)\n                            .electionAddr;\n                    }\n                    LOG.info(\"My election bind port: \" + addr.toString());\n                    setName(view.get(QuorumCnxManager.this.mySid)\n                            .electionAddr.toString());\n                    ss.bind(addr);\n                    while (!shutdown) {\n                        Socket client = ss.accept();\n                        setSockOpts(client);\n                        LOG.info(\"Received connection request \"\n                                + client.getRemoteSocketAddress());\n\n                        // Receive and handle the connection request\n                        // asynchronously if the quorum sasl authentication is\n                        // enabled. This is required because sasl server\n                        // authentication process may take few seconds to finish,\n                        // this may delay next peer connection requests.\n                        if (quorumSaslAuthEnabled) {\n                            receiveConnectionAsync(client);\n                        } else {\n                            receiveConnection(client);\n                        }\n\n                        numRetries = 0;\n                    }\n                } catch (IOException e) {\n                    LOG.error(\"Exception while listening\", e);\n                    numRetries++;\n                    try {\n                        ss.close();\n                        Thread.sleep(1000);\n                    } catch (IOException ie) {\n                        LOG.error(\"Error closing server socket\", ie);\n                    } catch (InterruptedException ie) {\n                        LOG.error(\"Interrupted while sleeping. \" +\n                                  \"Ignoring exception\", ie);\n                    }\n                }\n            }\n            LOG.info(\"Leaving listener\");\n            if (!shutdown) {\n                LOG.error(\"As I'm leaving the listener thread, \"\n                        + \"I won't be able to participate in leader \"\n                        + \"election any longer: \"\n                        + view.get(QuorumCnxManager.this.mySid).electionAddr);\n            }\n        }\n        \n        /**\n         * Halts this listener thread.\n         */\n        void halt(){\n            try{\n                LOG.debug(\"Trying to close listener: \" + ss);\n                if(ss != null) {\n                    LOG.debug(\"Closing listener: \"\n                              + QuorumCnxManager.this.mySid);\n                    ss.close();\n                }\n            } catch (IOException e){\n                LOG.warn(\"Exception when shutting down listener: \" + e);\n            }\n        }\n    }\n\n    /**\n     * Thread to send messages. Instance waits on a queue, and send a message as\n     * soon as there is one available. If connection breaks, then opens a new\n     * one.\n     */\n    class SendWorker extends ZooKeeperThread {\n        Long sid;\n        Socket sock;\n        RecvWorker recvWorker;\n        volatile boolean running = true;\n        DataOutputStream dout;\n\n        /**\n         * An instance of this thread receives messages to send\n         * through a queue and sends them to the server sid.\n         * \n         * @param sock\n         *            Socket to remote peer\n         * @param sid\n         *            Server identifier of remote peer\n         */\n        SendWorker(Socket sock, Long sid) {\n            super(\"SendWorker:\" + sid);\n            this.sid = sid;\n            this.sock = sock;\n            recvWorker = null;\n            try {\n                dout = new DataOutputStream(sock.getOutputStream());\n            } catch (IOException e) {\n                LOG.error(\"Unable to access socket output stream\", e);\n                closeSocket(sock);\n                running = false;\n            }\n            LOG.debug(\"Address of remote peer: \" + this.sid);\n        }\n\n        synchronized void setRecv(RecvWorker recvWorker) {\n            this.recvWorker = recvWorker;\n        }\n\n        /**\n         * Returns RecvWorker that pairs up with this SendWorker.\n         * \n         * @return RecvWorker \n         */\n        synchronized RecvWorker getRecvWorker(){\n            return recvWorker;\n        }\n                \n        synchronized boolean finish() {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Calling finish for \" + sid);\n            }\n            \n            if(!running){\n                /*\n                 * Avoids running finish() twice. \n                 */\n                return running;\n            }\n            \n            running = false;\n            closeSocket(sock);\n            // channel = null;\n\n            this.interrupt();\n            if (recvWorker != null) {\n                recvWorker.finish();\n            }\n\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Removing entry from senderWorkerMap sid=\" + sid);\n            }\n            senderWorkerMap.remove(sid, this);\n            threadCnt.decrementAndGet();\n            return running;\n        }\n        \n        synchronized void send(ByteBuffer b) throws IOException {\n            byte[] msgBytes = new byte[b.capacity()];\n            try {\n                b.position(0);\n                b.get(msgBytes);\n            } catch (BufferUnderflowException be) {\n                LOG.error(\"BufferUnderflowException \", be);\n                return;\n            }\n            dout.writeInt(b.capacity());\n            dout.write(b.array());\n            dout.flush();\n        }\n\n        @Override\n        public void run() {\n            threadCnt.incrementAndGet();\n            try {\n                /**\n                 * If there is nothing in the queue to send, then we\n                 * send the lastMessage to ensure that the last message\n                 * was received by the peer. The message could be dropped\n                 * in case self or the peer shutdown their connection\n                 * (and exit the thread) prior to reading/processing\n                 * the last message. Duplicate messages are handled correctly\n                 * by the peer.\n                 *\n                 * If the send queue is non-empty, then we have a recent\n                 * message than that stored in lastMessage. To avoid sending\n                 * stale message, we should send the message in the send queue.\n                 */\n                ArrayBlockingQueue<ByteBuffer> bq = queueSendMap.get(sid);\n                if (bq == null || isSendQueueEmpty(bq)) {\n                   ByteBuffer b = lastMessageSent.get(sid);\n                   if (b != null) {\n                       LOG.debug(\"Attempting to send lastMessage to sid=\" + sid);\n                       send(b);\n                   }\n                }\n            } catch (IOException e) {\n                LOG.error(\"Failed to send last message. Shutting down thread.\", e);\n                this.finish();\n            }\n            \n            try {\n                while (running && !shutdown && sock != null) {\n\n                    ByteBuffer b = null;\n                    try {\n                        ArrayBlockingQueue<ByteBuffer> bq = queueSendMap\n                                .get(sid);\n                        if (bq != null) {\n                            b = pollSendQueue(bq, 1000, TimeUnit.MILLISECONDS);\n                        } else {\n                            LOG.error(\"No queue of incoming messages for \" +\n                                      \"server \" + sid);\n                            break;\n                        }\n\n                        if(b != null){\n                            lastMessageSent.put(sid, b);\n                            send(b);\n                        }\n                    } catch (InterruptedException e) {\n                        LOG.warn(\"Interrupted while waiting for message on queue\",\n                                e);\n                    }\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Exception when using channel: for id \" + sid\n                         + \" my id = \" + QuorumCnxManager.this.mySid\n                         + \" error = \" + e);\n            }\n            this.finish();\n            LOG.warn(\"Send worker leaving thread\");\n        }\n    }\n\n    /**\n     * Thread to receive messages. Instance waits on a socket read. If the\n     * channel breaks, then removes itself from the pool of receivers.\n     */\n    class RecvWorker extends ZooKeeperThread {\n        Long sid;\n        Socket sock;\n        volatile boolean running = true;\n        final DataInputStream din;\n        final SendWorker sw;\n\n        RecvWorker(Socket sock, DataInputStream din, Long sid, SendWorker sw) {\n            super(\"RecvWorker:\" + sid);\n            this.sid = sid;\n            this.sock = sock;\n            this.sw = sw;\n            this.din = din;\n            try {\n                // OK to wait until socket disconnects while reading.\n                sock.setSoTimeout(0);\n            } catch (IOException e) {\n                LOG.error(\"Error while accessing socket for \" + sid, e);\n                closeSocket(sock);\n                running = false;\n            }\n        }\n        \n        /**\n         * Shuts down this worker\n         * \n         * @return boolean  Value of variable running\n         */\n        synchronized boolean finish() {\n            if(!running){\n                /*\n                 * Avoids running finish() twice. \n                 */\n                return running;\n            }\n            running = false;            \n\n            this.interrupt();\n            threadCnt.decrementAndGet();\n            return running;\n        }\n\n        @Override\n        public void run() {\n            threadCnt.incrementAndGet();\n            try {\n                while (running && !shutdown && sock != null) {\n                    /**\n                     * Reads the first int to determine the length of the\n                     * message\n                     */\n                    int length = din.readInt();\n                    if (length <= 0 || length > PACKETMAXSIZE) {\n                        throw new IOException(\n                                \"Received packet with invalid packet: \"\n                                        + length);\n                    }\n                    /**\n                     * Allocates a new ByteBuffer to receive the message\n                     */\n                    byte[] msgArray = new byte[length];\n                    din.readFully(msgArray, 0, length);\n                    ByteBuffer message = ByteBuffer.wrap(msgArray);\n                    addToRecvQueue(new Message(message.duplicate(), sid));\n                }\n            } catch (Exception e) {\n                LOG.warn(\"Connection broken for id \" + sid + \", my id = \"\n                         + QuorumCnxManager.this.mySid + \", error = \" , e);\n            } finally {\n                LOG.warn(\"Interrupting SendWorker\");\n                sw.finish();\n                if (sock != null) {\n                    closeSocket(sock);\n                }\n            }\n        }\n    }\n\n    /**\n     * Inserts an element in the specified queue. If the Queue is full, this\n     * method removes an element from the head of the Queue and then inserts\n     * the element at the tail. It can happen that the an element is removed\n     * by another thread in {@link SendWorker#processMessage() processMessage}\n     * method before this method attempts to remove an element from the queue.\n     * This will cause {@link ArrayBlockingQueue#remove() remove} to throw an\n     * exception, which is safe to ignore.\n     *\n     * Unlike {@link #addToRecvQueue(Message) addToRecvQueue} this method does\n     * not need to be synchronized since there is only one thread that inserts\n     * an element in the queue and another thread that reads from the queue.\n     *\n     * @param queue\n     *          Reference to the Queue\n     * @param buffer\n     *          Reference to the buffer to be inserted in the queue\n     */\n    private void addToSendQueue(ArrayBlockingQueue<ByteBuffer> queue,\n          ByteBuffer buffer) {\n        if (queue.remainingCapacity() == 0) {\n            try {\n                queue.remove();\n            } catch (NoSuchElementException ne) {\n                // element could be removed by poll()\n                LOG.debug(\"Trying to remove from an empty \" +\n                        \"Queue. Ignoring exception \" + ne);\n            }\n        }\n        try {\n            queue.add(buffer);\n        } catch (IllegalStateException ie) {\n            // This should never happen\n            LOG.error(\"Unable to insert an element in the queue \" + ie);\n        }\n    }\n\n    /**\n     * Returns true if queue is empty.\n     * @param queue\n     *          Reference to the queue\n     * @return\n     *      true if the specified queue is empty\n     */\n    private boolean isSendQueueEmpty(ArrayBlockingQueue<ByteBuffer> queue) {\n        return queue.isEmpty();\n    }\n\n    /**\n     * Retrieves and removes buffer at the head of this queue,\n     * waiting up to the specified wait time if necessary for an element to\n     * become available.\n     *\n     * {@link ArrayBlockingQueue#poll(long, java.util.concurrent.TimeUnit)}\n     */\n    private ByteBuffer pollSendQueue(ArrayBlockingQueue<ByteBuffer> queue,\n          long timeout, TimeUnit unit) throws InterruptedException {\n       return queue.poll(timeout, unit);\n    }\n\n    /**\n     * Inserts an element in the {@link #recvQueue}. If the Queue is full, this\n     * methods removes an element from the head of the Queue and then inserts\n     * the element at the tail of the queue.\n     *\n     * This method is synchronized to achieve fairness between two threads that\n     * are trying to insert an element in the queue. Each thread checks if the\n     * queue is full, then removes the element at the head of the queue, and\n     * then inserts an element at the tail. This three-step process is done to\n     * prevent a thread from blocking while inserting an element in the queue.\n     * If we do not synchronize the call to this method, then a thread can grab\n     * a slot in the queue created by the second thread. This can cause the call\n     * to insert by the second thread to fail.\n     * Note that synchronizing this method does not block another thread\n     * from polling the queue since that synchronization is provided by the\n     * queue itself.\n     *\n     * @param msg\n     *          Reference to the message to be inserted in the queue\n     */\n    public void addToRecvQueue(Message msg) {\n        synchronized(recvQLock) {\n            if (recvQueue.remainingCapacity() == 0) {\n                try {\n                    recvQueue.remove();\n                } catch (NoSuchElementException ne) {\n                    // element could be removed by poll()\n                     LOG.debug(\"Trying to remove from an empty \" +\n                         \"recvQueue. Ignoring exception \" + ne);\n                }\n            }\n            try {\n                recvQueue.add(msg);\n            } catch (IllegalStateException ie) {\n                // This should never happen\n                LOG.error(\"Unable to insert element in the recvQueue \" + ie);\n            }\n        }\n    }\n\n    /**\n     * Retrieves and removes a message at the head of this queue,\n     * waiting up to the specified wait time if necessary for an element to\n     * become available.\n     *\n     * {@link ArrayBlockingQueue#poll(long, java.util.concurrent.TimeUnit)}\n     */\n    public Message pollRecvQueue(long timeout, TimeUnit unit)\n       throws InterruptedException {\n       return recvQueue.poll(timeout, unit);\n    }\n\n    public boolean connectedToPeer(long peerSid) {\n        return senderWorkerMap.get(peerSid) != null;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n/**\n * An MBean representing a zookeeper cluster nodes (aka quorum peers)\n */\npublic interface QuorumMXBean {\n    /**\n     * @return the name of the quorum\n     */\n    public String getName();\n    \n    /**\n     * @return configured number of peers in the quorum\n     */\n    public int getQuorumSize();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumPeer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.SocketException;\nimport java.net.UnknownHostException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.security.sasl.SaslException;\n\nimport org.apache.zookeeper.common.AtomicFileOutputStream;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooKeeperThread;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuth;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.auth.SaslQuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.SaslQuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.auth.NullQuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.NullQuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumMaj;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class manages the quorum protocol. There are three states this server\n * can be in:\n * <ol>\n * <li>Leader election - each server will elect a leader (proposing itself as a\n * leader initially).</li>\n * <li>Follower - the server will synchronize with the leader and replicate any\n * transactions.</li>\n * <li>Leader - the server will process requests and forward them to followers.\n * A majority of followers must log the request before it can be accepted.\n * </ol>\n *\n * This class will setup a datagram socket that will always respond with its\n * view of the current leader. The response will take the form of:\n *\n * <pre>\n * int xid;\n *\n * long myid;\n *\n * long leader_id;\n *\n * long leader_zxid;\n * </pre>\n *\n * The request for the current leader will consist solely of an xid: int xid;\n */\npublic class QuorumPeer extends ZooKeeperThread implements QuorumStats.Provider {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumPeer.class);\n\n    QuorumBean jmxQuorumBean;\n    LocalPeerBean jmxLocalPeerBean;\n    LeaderElectionBean jmxLeaderElectionBean;\n    QuorumCnxManager qcm;\n    QuorumAuthServer authServer;\n    QuorumAuthLearner authLearner;\n    // VisibleForTesting. This flag is used to know whether qLearner's and\n    // qServer's login context has been initialized as ApacheDS has concurrency\n    // issues. Refer https://issues.apache.org/jira/browse/ZOOKEEPER-2712\n    private boolean authInitialized = false;\n\n    /* ZKDatabase is a top level member of quorumpeer \n     * which will be used in all the zookeeperservers\n     * instantiated later. Also, it is created once on \n     * bootup and only thrown away in case of a truncate\n     * message from the leader\n     */\n    private ZKDatabase zkDb;\n\n    public static class QuorumServer {\n        private QuorumServer(long id, InetSocketAddress addr,\n                InetSocketAddress electionAddr) {\n            this.id = id;\n            this.addr = addr;\n            this.electionAddr = electionAddr;\n        }\n\n        // VisibleForTesting\n        public QuorumServer(long id, InetSocketAddress addr) {\n            this.id = id;\n            this.addr = addr;\n            this.electionAddr = null;\n        }\n        \n        private QuorumServer(long id, InetSocketAddress addr,\n                    InetSocketAddress electionAddr, LearnerType type) {\n            this.id = id;\n            this.addr = addr;\n            this.electionAddr = electionAddr;\n            this.type = type;\n        }\n        \n        public QuorumServer(long id, String hostname,\n                            Integer port, Integer electionPort,\n                            LearnerType type) {\n\t    this.id = id;\n\t    this.hostname=hostname;\n\t    if (port!=null){\n                this.port=port;\n\t    }\n\t    if (electionPort!=null){\n                this.electionPort=electionPort;\n\t    }\n\t    if (type!=null){\n                this.type = type;\n\t    }\n\t    this.recreateSocketAddresses();\n\t}\n\n        /**\n         * Performs a DNS lookup of hostname and (re)creates the this.addr and\n         * this.electionAddr InetSocketAddress objects as appropriate\n         *\n         * If the DNS lookup fails, this.addr and electionAddr remain\n         * unmodified, unless they were never set. If this.addr is null, then\n         * it is set with an unresolved InetSocketAddress object. this.electionAddr\n         * is handled similarly.\n         */\n        public void recreateSocketAddresses() {\n            InetAddress address = null;\n            try {\n                // the time, in milliseconds, before {@link InetAddress#isReachable} aborts\n                // in {@link #getReachableAddress}.\n                int ipReachableTimeout = 0;\n                String ipReachableValue = System.getProperty(\"zookeeper.ipReachableTimeout\");\n                if (ipReachableValue != null) {\n                    try {\n                        ipReachableTimeout = Integer.parseInt(ipReachableValue);\n                    } catch (NumberFormatException e) {\n                        LOG.error(\"{} is not a valid number\", ipReachableValue);\n                    }\n                }\n                // zookeeper.ipReachableTimeout is not defined\n                if (ipReachableTimeout <= 0) {\n                    address = InetAddress.getByName(this.hostname);\n                } else {\n                    address = getReachableAddress(this.hostname, ipReachableTimeout);\n                }\n                LOG.info(\"Resolved hostname: {} to address: {}\", this.hostname, address);\n                this.addr = new InetSocketAddress(address, this.port);\n                if (this.electionPort > 0){\n                    this.electionAddr = new InetSocketAddress(address, this.electionPort);\n                }\n            } catch (UnknownHostException ex) {\n                LOG.warn(\"Failed to resolve address: {}\", this.hostname, ex);\n                // Have we succeeded in the past?\n                if (this.addr != null) {\n                    // Yes, previously the lookup succeeded. Leave things as they are\n                    return;\n                }\n                // The hostname has never resolved. Create our InetSocketAddress(es) as unresolved\n                this.addr = InetSocketAddress.createUnresolved(this.hostname, this.port);\n                if (this.electionPort > 0){\n                    this.electionAddr = InetSocketAddress.createUnresolved(this.hostname,\n                                                                           this.electionPort);\n                }\n            }\n        }\n\n        /**\n         * Resolve the hostname to IP addresses, and find one reachable address.\n         *\n         * @param hostname the name of the host\n         * @param timeout the time, in milliseconds, before {@link InetAddress#isReachable}\n         *                aborts\n         * @return a reachable IP address. If no such IP address can be found,\n         *         just return the first IP address of the hostname.\n         *\n         * @exception UnknownHostException\n         */\n        public InetAddress getReachableAddress(String hostname, int timeout) \n                throws UnknownHostException {\n            InetAddress[] addresses = InetAddress.getAllByName(hostname);\n            for (InetAddress a : addresses) {\n                try {\n                    if (a.isReachable(timeout)) {\n                        return a;\n                    } \n                } catch (IOException e) {\n                    LOG.warn(\"IP address {} is unreachable\", a);\n                }\n            }\n            // All the IP addresses are unreachable, just return the first one.\n            return addresses[0];\n        }\n\n        public InetSocketAddress addr;\n\n        public InetSocketAddress electionAddr;\n        \n        public String hostname;\n\n        public int port=2888;\n\n        public int electionPort=-1;\n\n        public long id;\n        \n        public LearnerType type = LearnerType.PARTICIPANT;\n    }\n\n    public enum ServerState {\n        LOOKING, FOLLOWING, LEADING, OBSERVING;\n    }\n    \n    /*\n     * A peer can either be participating, which implies that it is willing to\n     * both vote in instances of consensus and to elect or become a Leader, or\n     * it may be observing in which case it isn't.\n     * \n     * We need this distinction to decide which ServerState to move to when \n     * conditions change (e.g. which state to become after LOOKING). \n     */\n    public enum LearnerType {\n        PARTICIPANT, OBSERVER;\n    }\n    \n    /*\n     * To enable observers to have no identifier, we need a generic identifier\n     * at least for QuorumCnxManager. We use the following constant to as the\n     * value of such a generic identifier. \n     */\n    \n    static final long OBSERVER_ID = Long.MAX_VALUE;\n\n    /*\n     * Record leader election time\n     */\n    public long start_fle, end_fle;\n    \n    /*\n     * Default value of peer is participant\n     */\n    private LearnerType learnerType = LearnerType.PARTICIPANT;\n    \n    public LearnerType getLearnerType() {\n        return learnerType;\n    }\n    \n    /**\n     * Sets the LearnerType both in the QuorumPeer and in the peerMap\n     */\n    public void setLearnerType(LearnerType p) {\n        learnerType = p;\n        if (quorumPeers.containsKey(this.myid)) {\n            this.quorumPeers.get(myid).type = p;\n        } else {\n            LOG.error(\"Setting LearnerType to \" + p + \" but \" + myid \n                    + \" not in QuorumPeers. \");\n        }\n        \n    }\n    /**\n     * The servers that make up the cluster\n     */\n    protected Map<Long, QuorumServer> quorumPeers;\n    public int getQuorumSize(){\n        return getVotingView().size();\n    }\n    \n    /**\n     * QuorumVerifier implementation; default (majority). \n     */\n    \n    private QuorumVerifier quorumConfig;\n    \n    /**\n     * My id\n     */\n    private long myid;\n\n\n    /**\n     * get the id of this quorum peer.\n     */\n    public long getId() {\n        return myid;\n    }\n\n    /**\n     * This is who I think the leader currently is.\n     */\n    volatile private Vote currentVote;\n    \n    /**\n     * ... and its counterpart for backward compatibility\n     */\n    volatile private Vote bcVote;\n        \n    public synchronized Vote getCurrentVote(){\n        return currentVote;\n    }\n       \n    public synchronized void setCurrentVote(Vote v){\n        currentVote = v;\n    }\n    \n    synchronized Vote getBCVote() {\n        if (bcVote == null) {\n            return currentVote;\n        } else {\n            return bcVote;\n        }\n    }\n\n    synchronized void setBCVote(Vote v) {\n        bcVote = v;\n    }\n    \n    volatile boolean running = true;\n\n    /**\n     * The number of milliseconds of each tick\n     */\n    protected int tickTime;\n\n    /**\n     * Minimum number of milliseconds to allow for session timeout.\n     * A value of -1 indicates unset, use default.\n     */\n    protected int minSessionTimeout = -1;\n\n    /**\n     * Maximum number of milliseconds to allow for session timeout.\n     * A value of -1 indicates unset, use default.\n     */\n    protected int maxSessionTimeout = -1;\n\n    /**\n     * The number of ticks that the initial synchronization phase can take\n     */\n    protected int initLimit;\n\n    /**\n     * The number of ticks that can pass between sending a request and getting\n     * an acknowledgment\n     */\n    protected int syncLimit;\n    \n    /**\n     * Enables/Disables sync request processor. This option is enabled\n     * by default and is to be used with observers.\n     */\n    protected boolean syncEnabled = true;\n\n    /**\n     * The current tick\n     */\n    protected AtomicInteger tick = new AtomicInteger();\n\n    /**\n     * Whether or not to listen on all IPs for the two quorum ports\n     * (broadcast and fast leader election).\n     */\n    protected boolean quorumListenOnAllIPs = false;\n\n    /**\n     * Enable/Disables quorum authentication using sasl. Defaulting to false.\n     */\n    protected boolean quorumSaslEnableAuth;\n\n    /**\n     * If this is false, quorum peer server will accept another quorum peer client\n     * connection even if the authentication did not succeed. This can be used while\n     * upgrading ZooKeeper server. Defaulting to false (required).\n     */\n    protected boolean quorumServerSaslAuthRequired;\n\n    /**\n     * If this is false, quorum peer learner will talk to quorum peer server\n     * without authentication. This can be used while upgrading ZooKeeper\n     * server. Defaulting to false (required).\n     */\n    protected boolean quorumLearnerSaslAuthRequired;\n\n    /**\n     * Kerberos quorum service principal. Defaulting to 'zkquorum/localhost'.\n     */\n    protected String quorumServicePrincipal;\n\n    /**\n     * Quorum learner login context name in jaas-conf file to read the kerberos\n     * security details. Defaulting to 'QuorumLearner'.\n     */\n    protected String quorumLearnerLoginContext;\n\n    /**\n     * Quorum server login context name in jaas-conf file to read the kerberos\n     * security details. Defaulting to 'QuorumServer'.\n     */\n    protected String quorumServerLoginContext;\n\n    // TODO: need to tune the default value of thread size\n    private static final int QUORUM_CNXN_THREADS_SIZE_DEFAULT_VALUE = 20;\n    /**\n     * The maximum number of threads to allow in the connectionExecutors thread\n     * pool which will be used to initiate quorum server connections.\n     */\n    protected int quorumCnxnThreadsSize = QUORUM_CNXN_THREADS_SIZE_DEFAULT_VALUE;\n\n    /**\n     * Keeps time taken for leader election in milliseconds. Sets the value to\n     * this variable only after the completion of leader election.\n     */\n    private long electionTimeTaken = -1;\n\n    /**\n     * @deprecated As of release 3.4.0, this class has been deprecated, since\n     * it is used with one of the udp-based versions of leader election, which\n     * we are also deprecating. \n     * \n     * This class simply responds to requests for the current leader of this\n     * node.\n     * <p>\n     * The request contains just an xid generated by the requestor.\n     * <p>\n     * The response has the xid, the id of this server, the id of the leader,\n     * and the zxid of the leader.\n     *\n     *\n     */\n    @Deprecated\n    class ResponderThread extends ZooKeeperThread {\n        ResponderThread() {\n            super(\"ResponderThread\");\n        }\n\n        volatile boolean running = true;\n        \n        @Override\n        public void run() {\n            try {\n                byte b[] = new byte[36];\n                ByteBuffer responseBuffer = ByteBuffer.wrap(b);\n                DatagramPacket packet = new DatagramPacket(b, b.length);\n                while (running) {\n                    udpSocket.receive(packet);\n                    if (packet.getLength() != 4) {\n                        LOG.warn(\"Got more than just an xid! Len = \"\n                                + packet.getLength());\n                    } else {\n                        responseBuffer.clear();\n                        responseBuffer.getInt(); // Skip the xid\n                        responseBuffer.putLong(myid);\n                        Vote current = getCurrentVote();\n                        switch (getPeerState()) {\n                        case LOOKING:\n                            responseBuffer.putLong(current.getId());\n                            responseBuffer.putLong(current.getZxid());\n                            break;\n                        case LEADING:\n                            responseBuffer.putLong(myid);\n                            try {\n                                long proposed;\n                                synchronized(leader) {\n                                    proposed = leader.lastProposed;\n                                }\n                                responseBuffer.putLong(proposed);\n                            } catch (NullPointerException npe) {\n                                // This can happen in state transitions,\n                                // just ignore the request\n                            }\n                            break;\n                        case FOLLOWING:\n                            responseBuffer.putLong(current.getId());\n                            try {\n                                responseBuffer.putLong(follower.getZxid());\n                            } catch (NullPointerException npe) {\n                                // This can happen in state transitions,\n                                // just ignore the request\n                            }\n                            break;\n                        case OBSERVING:\n                            // Do nothing, Observers keep themselves to\n                            // themselves. \n                            break;\n                        }\n                        packet.setData(b);\n                        udpSocket.send(packet);\n                    }\n                    packet.setLength(b.length);\n                }\n            } catch (RuntimeException e) {\n                LOG.warn(\"Unexpected runtime exception in ResponderThread\",e);\n            } catch (IOException e) {\n                LOG.warn(\"Unexpected IO exception in ResponderThread\",e);\n            } finally {\n                LOG.warn(\"QuorumPeer responder thread exited\");\n            }\n        }\n    }\n\n    private ServerState state = ServerState.LOOKING;\n\n    public synchronized void setPeerState(ServerState newState){\n        state=newState;\n    }\n\n    public synchronized ServerState getPeerState(){\n        return state;\n    }\n\n    DatagramSocket udpSocket;\n\n    private InetSocketAddress myQuorumAddr;\n\n    public InetSocketAddress getQuorumAddress(){\n        return myQuorumAddr;\n    }\n\n    private int electionType;\n\n    Election electionAlg;\n\n    ServerCnxnFactory cnxnFactory;\n    private FileTxnSnapLog logFactory = null;\n\n    private final QuorumStats quorumStats;\n\n    public static QuorumPeer testingQuorumPeer() throws SaslException {\n        return new QuorumPeer();\n    }\n\n    protected QuorumPeer() throws SaslException {\n        super(\"QuorumPeer\");\n        quorumStats = new QuorumStats(this);\n        initialize();\n    }\n    \n   \n    /**\n     * For backward compatibility purposes, we instantiate QuorumMaj by default.\n     */\n    \n    public QuorumPeer(Map<Long, QuorumServer> quorumPeers, File dataDir,\n            File dataLogDir, int electionType,\n            long myid, int tickTime, int initLimit, int syncLimit,\n            ServerCnxnFactory cnxnFactory) throws IOException {\n        this(quorumPeers, dataDir, dataLogDir, electionType, myid, tickTime, \n        \t\tinitLimit, syncLimit, false, cnxnFactory, \n        \t\tnew QuorumMaj(countParticipants(quorumPeers)));\n    }\n    \n    public QuorumPeer(Map<Long, QuorumServer> quorumPeers, File dataDir,\n            File dataLogDir, int electionType,\n            long myid, int tickTime, int initLimit, int syncLimit,\n            boolean quorumListenOnAllIPs,\n            ServerCnxnFactory cnxnFactory, \n            QuorumVerifier quorumConfig) throws IOException {\n        this();\n        this.cnxnFactory = cnxnFactory;\n        this.quorumPeers = quorumPeers;\n        this.electionType = electionType;\n        this.myid = myid;\n        this.tickTime = tickTime;\n        this.initLimit = initLimit;\n        this.syncLimit = syncLimit;        \n        this.quorumListenOnAllIPs = quorumListenOnAllIPs;\n        this.logFactory = new FileTxnSnapLog(dataLogDir, dataDir);\n        this.zkDb = new ZKDatabase(this.logFactory);\n        if(quorumConfig == null)\n            this.quorumConfig = new QuorumMaj(countParticipants(quorumPeers));\n        else this.quorumConfig = quorumConfig;\n    }\n\n    public void initialize() throws SaslException {\n        // init quorum auth server & learner\n        if (isQuorumSaslAuthEnabled()) {\n            Set<String> authzHosts = new HashSet<String>();\n            for (QuorumServer qs : getView().values()) {\n                authzHosts.add(qs.hostname);\n            }\n            authServer = new SaslQuorumAuthServer(isQuorumServerSaslAuthRequired(),\n                    quorumServerLoginContext, authzHosts);\n            authLearner = new SaslQuorumAuthLearner(isQuorumLearnerSaslAuthRequired(),\n                    quorumServicePrincipal, quorumLearnerLoginContext);\n            authInitialized = true;\n        } else {\n            authServer = new NullQuorumAuthServer();\n            authLearner = new NullQuorumAuthLearner();\n        }\n    }\n\n    QuorumStats quorumStats() {\n        return quorumStats;\n    }\n    \n    @Override\n    public synchronized void start() {\n        loadDataBase();\n        cnxnFactory.start();        \n        startLeaderElection();\n        super.start();\n    }\n\n    private void loadDataBase() {\n        File updating = new File(getTxnFactory().getSnapDir(),\n                                 UPDATING_EPOCH_FILENAME);\n\t\ttry {\n            zkDb.loadDataBase();\n\n            // load the epochs\n            long lastProcessedZxid = zkDb.getDataTree().lastProcessedZxid;\n    \t\tlong epochOfZxid = ZxidUtils.getEpochFromZxid(lastProcessedZxid);\n            try {\n            \tcurrentEpoch = readLongFromFile(CURRENT_EPOCH_FILENAME);\n                if (epochOfZxid > currentEpoch && updating.exists()) {\n                    LOG.info(\"{} found. The server was terminated after \" +\n                             \"taking a snapshot but before updating current \" +\n                             \"epoch. Setting current epoch to {}.\",\n                             UPDATING_EPOCH_FILENAME, epochOfZxid);\n                    setCurrentEpoch(epochOfZxid);\n                    if (!updating.delete()) {\n                        throw new IOException(\"Failed to delete \" +\n                                              updating.toString());\n                    }\n                }\n            } catch(FileNotFoundException e) {\n            \t// pick a reasonable epoch number\n            \t// this should only happen once when moving to a\n            \t// new code version\n            \tcurrentEpoch = epochOfZxid;\n            \tLOG.info(CURRENT_EPOCH_FILENAME\n            \t        + \" not found! Creating with a reasonable default of {}. This should only happen when you are upgrading your installation\",\n            \t        currentEpoch);\n            \twriteLongToFile(CURRENT_EPOCH_FILENAME, currentEpoch);\n            }\n            if (epochOfZxid > currentEpoch) {\n            \tthrow new IOException(\"The current epoch, \" + ZxidUtils.zxidToString(currentEpoch) + \", is older than the last zxid, \" + lastProcessedZxid);\n            }\n            try {\n            \tacceptedEpoch = readLongFromFile(ACCEPTED_EPOCH_FILENAME);\n            } catch(FileNotFoundException e) {\n            \t// pick a reasonable epoch number\n            \t// this should only happen once when moving to a\n            \t// new code version\n            \tacceptedEpoch = epochOfZxid;\n            \tLOG.info(ACCEPTED_EPOCH_FILENAME\n            \t        + \" not found! Creating with a reasonable default of {}. This should only happen when you are upgrading your installation\",\n            \t        acceptedEpoch);\n            \twriteLongToFile(ACCEPTED_EPOCH_FILENAME, acceptedEpoch);\n            }\n            if (acceptedEpoch < currentEpoch) {\n            \tthrow new IOException(\"The accepted epoch, \" + ZxidUtils.zxidToString(acceptedEpoch) + \" is less than the current epoch, \" + ZxidUtils.zxidToString(currentEpoch));\n            }\n        } catch(IOException ie) {\n            LOG.error(\"Unable to load database on disk\", ie);\n            throw new RuntimeException(\"Unable to run quorum server \", ie);\n        }\n\t}\n\n    ResponderThread responder;\n    \n    synchronized public void stopLeaderElection() {\n        responder.running = false;\n        responder.interrupt();\n    }\n    synchronized public void startLeaderElection() {\n    \ttry {\n    \t\tcurrentVote = new Vote(myid, getLastLoggedZxid(), getCurrentEpoch());\n    \t} catch(IOException e) {\n    \t\tRuntimeException re = new RuntimeException(e.getMessage());\n    \t\tre.setStackTrace(e.getStackTrace());\n    \t\tthrow re;\n    \t}\n        for (QuorumServer p : getView().values()) {\n            if (p.id == myid) {\n                myQuorumAddr = p.addr;\n                break;\n            }\n        }\n        if (myQuorumAddr == null) {\n            throw new RuntimeException(\"My id \" + myid + \" not in the peer list\");\n        }\n        if (electionType == 0) {\n            try {\n                udpSocket = new DatagramSocket(myQuorumAddr.getPort());\n                responder = new ResponderThread();\n                responder.start();\n            } catch (SocketException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        this.electionAlg = createElectionAlgorithm(electionType);\n    }\n    \n    /**\n     * Count the number of nodes in the map that could be followers.\n     * @param peers\n     * @return The number of followers in the map\n     */\n    protected static int countParticipants(Map<Long,QuorumServer> peers) {\n      int count = 0;\n      for (QuorumServer q : peers.values()) {\n          if (q.type == LearnerType.PARTICIPANT) {\n              count++;\n          }\n      }\n      return count;\n    }\n    \n    /**\n     * This constructor is only used by the existing unit test code.\n     * It defaults to FileLogProvider persistence provider.\n     */\n    public QuorumPeer(Map<Long,QuorumServer> quorumPeers, File snapDir,\n            File logDir, int clientPort, int electionAlg,\n            long myid, int tickTime, int initLimit, int syncLimit)\n        throws IOException\n    {\n        this(quorumPeers, snapDir, logDir, electionAlg,\n                myid,tickTime, initLimit,syncLimit, false,\n                ServerCnxnFactory.createFactory(new InetSocketAddress(clientPort), -1),\n                new QuorumMaj(countParticipants(quorumPeers)));\n    }\n    \n    /**\n     * This constructor is only used by the existing unit test code.\n     * It defaults to FileLogProvider persistence provider.\n     */\n    public QuorumPeer(Map<Long,QuorumServer> quorumPeers, File snapDir,\n            File logDir, int clientPort, int electionAlg,\n            long myid, int tickTime, int initLimit, int syncLimit, \n            QuorumVerifier quorumConfig)\n        throws IOException\n    {\n        this(quorumPeers, snapDir, logDir, electionAlg,\n                myid,tickTime, initLimit,syncLimit, false,\n                ServerCnxnFactory.createFactory(new InetSocketAddress(clientPort), -1),\n                quorumConfig);\n    }\n    \n    /**\n     * returns the highest zxid that this host has seen\n     * \n     * @return the highest zxid for this host\n     */\n    public long getLastLoggedZxid() {\n        if (!zkDb.isInitialized()) {\n        \tloadDataBase();\n        }\n        return zkDb.getDataTreeLastProcessedZxid();\n    }\n    \n    public Follower follower;\n    public Leader leader;\n    public Observer observer;\n\n    protected Follower makeFollower(FileTxnSnapLog logFactory) throws IOException {\n        return new Follower(this, new FollowerZooKeeperServer(logFactory, \n                this,new ZooKeeperServer.BasicDataTreeBuilder(), this.zkDb));\n    }\n     \n    protected Leader makeLeader(FileTxnSnapLog logFactory) throws IOException {\n        return new Leader(this, new LeaderZooKeeperServer(logFactory,\n                this,new ZooKeeperServer.BasicDataTreeBuilder(), this.zkDb));\n    }\n    \n    protected Observer makeObserver(FileTxnSnapLog logFactory) throws IOException {\n        return new Observer(this, new ObserverZooKeeperServer(logFactory,\n                this, new ZooKeeperServer.BasicDataTreeBuilder(), this.zkDb));\n    }\n\n    protected Election createElectionAlgorithm(int electionAlgorithm){\n        Election le=null;\n                \n        //TODO: use a factory rather than a switch\n        switch (electionAlgorithm) {\n        case 0:\n            le = new LeaderElection(this);\n            break;\n        case 1:\n            le = new AuthFastLeaderElection(this);\n            break;\n        case 2:\n            le = new AuthFastLeaderElection(this, true);\n            break;\n        case 3:\n            qcm = createCnxnManager();\n            QuorumCnxManager.Listener listener = qcm.listener;\n            if(listener != null){\n                listener.start();\n                le = new FastLeaderElection(this, qcm);\n            } else {\n                LOG.error(\"Null listener when initializing cnx manager\");\n            }\n            break;\n        default:\n            assert false;\n        }\n        return le;\n    }\n\n    protected Election makeLEStrategy(){\n        LOG.debug(\"Initializing leader election protocol...\");\n        if (getElectionType() == 0) {\n            electionAlg = new LeaderElection(this);\n        }        \n        return electionAlg;\n    }\n\n    synchronized protected void setLeader(Leader newLeader){\n        leader=newLeader;\n    }\n\n    synchronized protected void setFollower(Follower newFollower){\n        follower=newFollower;\n    }\n    \n    synchronized protected void setObserver(Observer newObserver){\n        observer=newObserver;\n    }\n\n    synchronized public ZooKeeperServer getActiveServer(){\n        if(leader!=null)\n            return leader.zk;\n        else if(follower!=null)\n            return follower.zk;\n        else if (observer != null)\n            return observer.zk;\n        return null;\n    }\n\n    @Override\n    public void run() {\n        setName(\"QuorumPeer\" + \"[myid=\" + getId() + \"]\" +\n                cnxnFactory.getLocalAddress());\n\n        LOG.debug(\"Starting quorum peer\");\n        try {\n            jmxQuorumBean = new QuorumBean(this);\n            MBeanRegistry.getInstance().register(jmxQuorumBean, null);\n            for(QuorumServer s: getView().values()){\n                ZKMBeanInfo p;\n                if (getId() == s.id) {\n                    p = jmxLocalPeerBean = new LocalPeerBean(this);\n                    try {\n                        MBeanRegistry.getInstance().register(p, jmxQuorumBean);\n                    } catch (Exception e) {\n                        LOG.warn(\"Failed to register with JMX\", e);\n                        jmxLocalPeerBean = null;\n                    }\n                } else {\n                    p = new RemotePeerBean(s);\n                    try {\n                        MBeanRegistry.getInstance().register(p, jmxQuorumBean);\n                    } catch (Exception e) {\n                        LOG.warn(\"Failed to register with JMX\", e);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxQuorumBean = null;\n        }\n\n        try {\n            /*\n             * Main loop\n             */\n            while (running) {\n                switch (getPeerState()) {\n                case LOOKING:\n                    LOG.info(\"LOOKING\");\n\n                    if (Boolean.getBoolean(\"readonlymode.enabled\")) {\n                        LOG.info(\"Attempting to start ReadOnlyZooKeeperServer\");\n\n                        // Create read-only server but don't start it immediately\n                        final ReadOnlyZooKeeperServer roZk = new ReadOnlyZooKeeperServer(\n                                logFactory, this,\n                                new ZooKeeperServer.BasicDataTreeBuilder(),\n                                this.zkDb);\n    \n                        // Instead of starting roZk immediately, wait some grace\n                        // period before we decide we're partitioned.\n                        //\n                        // Thread is used here because otherwise it would require\n                        // changes in each of election strategy classes which is\n                        // unnecessary code coupling.\n                        Thread roZkMgr = new Thread() {\n                            public void run() {\n                                try {\n                                    // lower-bound grace period to 2 secs\n                                    sleep(Math.max(2000, tickTime));\n                                    if (ServerState.LOOKING.equals(getPeerState())) {\n                                        roZk.startup();\n                                    }\n                                } catch (InterruptedException e) {\n                                    LOG.info(\"Interrupted while attempting to start ReadOnlyZooKeeperServer, not started\");\n                                } catch (Exception e) {\n                                    LOG.error(\"FAILED to start ReadOnlyZooKeeperServer\", e);\n                                }\n                            }\n                        };\n                        try {\n                            roZkMgr.start();\n                            setBCVote(null);\n                            setCurrentVote(makeLEStrategy().lookForLeader());\n                        } catch (Exception e) {\n                            LOG.warn(\"Unexpected exception\",e);\n                            setPeerState(ServerState.LOOKING);\n                        } finally {\n                            // If the thread is in the the grace period, interrupt\n                            // to come out of waiting.\n                            roZkMgr.interrupt();\n                            roZk.shutdown();\n                        }\n                    } else {\n                        try {\n                            setBCVote(null);\n                            setCurrentVote(makeLEStrategy().lookForLeader());\n                        } catch (Exception e) {\n                            LOG.warn(\"Unexpected exception\", e);\n                            setPeerState(ServerState.LOOKING);\n                        }\n                    }\n                    break;\n                case OBSERVING:\n                    try {\n                        LOG.info(\"OBSERVING\");\n                        setObserver(makeObserver(logFactory));\n                        observer.observeLeader();\n                    } catch (Exception e) {\n                        LOG.warn(\"Unexpected exception\",e );                        \n                    } finally {\n                        observer.shutdown();\n                        setObserver(null);\n                        setPeerState(ServerState.LOOKING);\n                    }\n                    break;\n                case FOLLOWING:\n                    try {\n                        LOG.info(\"FOLLOWING\");\n                        setFollower(makeFollower(logFactory));\n                        follower.followLeader();\n                    } catch (Exception e) {\n                        LOG.warn(\"Unexpected exception\",e);\n                    } finally {\n                        follower.shutdown();\n                        setFollower(null);\n                        setPeerState(ServerState.LOOKING);\n                    }\n                    break;\n                case LEADING:\n                    LOG.info(\"LEADING\");\n                    try {\n                        setLeader(makeLeader(logFactory));\n                        leader.lead();\n                        setLeader(null);\n                    } catch (Exception e) {\n                        LOG.warn(\"Unexpected exception\",e);\n                    } finally {\n                        if (leader != null) {\n                            leader.shutdown(\"Forcing shutdown\");\n                            setLeader(null);\n                        }\n                        setPeerState(ServerState.LOOKING);\n                    }\n                    break;\n                }\n            }\n        } finally {\n            LOG.warn(\"QuorumPeer main thread exited\");\n            try {\n                MBeanRegistry.getInstance().unregisterAll();\n            } catch (Exception e) {\n                LOG.warn(\"Failed to unregister with JMX\", e);\n            }\n            jmxQuorumBean = null;\n            jmxLocalPeerBean = null;\n        }\n    }\n\n    public void shutdown() {\n        running = false;\n        if (leader != null) {\n            leader.shutdown(\"quorum Peer shutdown\");\n        }\n        if (follower != null) {\n            follower.shutdown();\n        }\n        cnxnFactory.shutdown();\n        if(udpSocket != null) {\n            udpSocket.close();\n        }\n        \n        if(getElectionAlg() != null){\n            this.interrupt();\n        \tgetElectionAlg().shutdown();\n        }\n        try {\n            zkDb.close();\n        } catch (IOException ie) {\n            LOG.warn(\"Error closing logs \", ie);\n        }\n    }\n\n    /**\n     * A 'view' is a node's current opinion of the membership of the entire\n     * ensemble.\n     */\n    public Map<Long,QuorumPeer.QuorumServer> getView() {\n        return Collections.unmodifiableMap(this.quorumPeers);\n    }\n\n    /**\n     * Observers are not contained in this view, only nodes with \n     * PeerType=PARTICIPANT.\n     */\n    public Map<Long,QuorumPeer.QuorumServer> getVotingView() {\n        return QuorumPeer.viewToVotingView(getView());\n    }\n\n    static Map<Long,QuorumPeer.QuorumServer> viewToVotingView(\n            Map<Long,QuorumPeer.QuorumServer> view) {\n        Map<Long,QuorumPeer.QuorumServer> ret =\n            new HashMap<Long, QuorumPeer.QuorumServer>();\n        for (QuorumServer server : view.values()) {\n            if (server.type == LearnerType.PARTICIPANT) {\n                ret.put(server.id, server);\n            }\n        }\n        return ret;\n    }\n\n    /**\n     * Returns only observers, no followers.\n     */\n    public Map<Long,QuorumPeer.QuorumServer> getObservingView() {\n        Map<Long,QuorumPeer.QuorumServer> ret = \n            new HashMap<Long, QuorumPeer.QuorumServer>();\n        Map<Long,QuorumPeer.QuorumServer> view = getView();\n        for (QuorumServer server : view.values()) {            \n            if (server.type == LearnerType.OBSERVER) {\n                ret.put(server.id, server);\n            }\n        }        \n        return ret;\n    }\n    \n    /**\n     * Check if a node is in the current view. With static membership, the\n     * result of this check will never change; only when dynamic membership\n     * is introduced will this be more useful.\n     */\n    public boolean viewContains(Long sid) {\n        return this.quorumPeers.containsKey(sid);\n    }\n    \n    /**\n     * Only used by QuorumStats at the moment\n     */\n    public String[] getQuorumPeers() {\n        List<String> l = new ArrayList<String>();\n        synchronized (this) {\n            if (leader != null) {\n                for (LearnerHandler fh : leader.getLearners()) {\n                    if (fh.getSocket() != null) {\n                        String s = fh.getSocket().getRemoteSocketAddress().toString();\n                        if (leader.isLearnerSynced(fh))\n                            s += \"*\";\n                        l.add(s);\n                    }\n                }\n            } else if (follower != null) {\n                l.add(follower.sock.getRemoteSocketAddress().toString());\n            }\n        }\n        return l.toArray(new String[0]);\n    }\n\n    public String getServerState() {\n        switch (getPeerState()) {\n        case LOOKING:\n            return QuorumStats.Provider.LOOKING_STATE;\n        case LEADING:\n            return QuorumStats.Provider.LEADING_STATE;\n        case FOLLOWING:\n            return QuorumStats.Provider.FOLLOWING_STATE;\n        case OBSERVING:\n            return QuorumStats.Provider.OBSERVING_STATE;\n        }\n        return QuorumStats.Provider.UNKNOWN_STATE;\n    }\n\n\n    /**\n     * get the id of this quorum peer.\n     */\n    public long getMyid() {\n        return myid;\n    }\n\n    /**\n     * set the id of this quorum peer.\n     */\n    public void setMyid(long myid) {\n        this.myid = myid;\n    }\n\n    /**\n     * Get the number of milliseconds of each tick\n     */\n    public int getTickTime() {\n        return tickTime;\n    }\n\n    /**\n     * Set the number of milliseconds of each tick\n     */\n    public void setTickTime(int tickTime) {\n        LOG.info(\"tickTime set to \" + tickTime);\n        this.tickTime = tickTime;\n    }\n\n    /** Maximum number of connections allowed from particular host (ip) */\n    public int getMaxClientCnxnsPerHost() {\n        ServerCnxnFactory fac = getCnxnFactory();\n        if (fac == null) {\n            return -1;\n        }\n        return fac.getMaxClientCnxnsPerHost();\n    }\n    \n    /** minimum session timeout in milliseconds */\n    public int getMinSessionTimeout() {\n        return minSessionTimeout == -1 ? tickTime * 2 : minSessionTimeout;\n    }\n\n    /** minimum session timeout in milliseconds */\n    public void setMinSessionTimeout(int min) {\n        LOG.info(\"minSessionTimeout set to \" + min);\n        this.minSessionTimeout = min;\n    }\n\n    /** maximum session timeout in milliseconds */\n    public int getMaxSessionTimeout() {\n        return maxSessionTimeout == -1 ? tickTime * 20 : maxSessionTimeout;\n    }\n\n    /** minimum session timeout in milliseconds */\n    public void setMaxSessionTimeout(int max) {\n        LOG.info(\"maxSessionTimeout set to \" + max);\n        this.maxSessionTimeout = max;\n    }\n\n    /**\n     * Get the number of ticks that the initial synchronization phase can take\n     */\n    public int getInitLimit() {\n        return initLimit;\n    }\n\n    /**\n     * Set the number of ticks that the initial synchronization phase can take\n     */\n    public void setInitLimit(int initLimit) {\n        LOG.info(\"initLimit set to \" + initLimit);\n        this.initLimit = initLimit;\n    }\n\n    /**\n     * Get the current tick\n     */\n    public int getTick() {\n        return tick.get();\n    }\n    \n    /**\n     * Return QuorumVerifier object\n     */\n    \n    public QuorumVerifier getQuorumVerifier(){\n        return quorumConfig;\n        \n    }\n    \n    public void setQuorumVerifier(QuorumVerifier quorumConfig){\n       this.quorumConfig = quorumConfig;\n    }\n    \n    /**\n     * Get an instance of LeaderElection\n     */\n        \n    public Election getElectionAlg(){\n        return electionAlg;\n    }\n        \n    /**\n     * Get the synclimit\n     */\n    public int getSyncLimit() {\n        return syncLimit;\n    }\n\n    /**\n     * Set the synclimit\n     */\n    public void setSyncLimit(int syncLimit) {\n        this.syncLimit = syncLimit;\n    }\n    \n    \n    /**\n     * The syncEnabled can also be set via a system property.\n     */\n    public static final String SYNC_ENABLED = \"zookeeper.observer.syncEnabled\";\n    \n    /**\n     * Return syncEnabled.\n     * \n     * @return\n     */\n    public boolean getSyncEnabled() {\n        if (System.getProperty(SYNC_ENABLED) != null) {\n            LOG.info(SYNC_ENABLED + \"=\" + Boolean.getBoolean(SYNC_ENABLED));   \n            return Boolean.getBoolean(SYNC_ENABLED);\n        } else {        \n            return syncEnabled;\n        }\n    }\n    \n    /**\n     * Set syncEnabled.\n     * \n     * @param syncEnabled\n     */\n    public void setSyncEnabled(boolean syncEnabled) {\n        this.syncEnabled = syncEnabled;\n    }\n\n    /**\n     * Gets the election type\n     */\n    public int getElectionType() {\n        return electionType;\n    }\n\n    /**\n     * Sets the election type\n     */\n    public void setElectionType(int electionType) {\n        this.electionType = electionType;\n    }\n\n    public boolean getQuorumListenOnAllIPs() {\n        return quorumListenOnAllIPs;\n    }\n\n    public void setQuorumListenOnAllIPs(boolean quorumListenOnAllIPs) {\n        this.quorumListenOnAllIPs = quorumListenOnAllIPs;\n    }\n\n    public ServerCnxnFactory getCnxnFactory() {\n        return cnxnFactory;\n    }\n\n    public void setCnxnFactory(ServerCnxnFactory cnxnFactory) {\n        this.cnxnFactory = cnxnFactory;\n    }\n\n    public void setQuorumPeers(Map<Long,QuorumServer> quorumPeers) {\n        this.quorumPeers = quorumPeers;\n    }\n\n    public int getClientPort() {\n        return cnxnFactory.getLocalPort();\n    }\n\n    public void setClientPortAddress(InetSocketAddress addr) {\n    }\n \n    public void setTxnFactory(FileTxnSnapLog factory) {\n        this.logFactory = factory;\n    }\n    \n    public FileTxnSnapLog getTxnFactory() {\n        return this.logFactory;\n    }\n\n    /**\n     * set zk database for this node\n     * @param database\n     */\n    public void setZKDatabase(ZKDatabase database) {\n        this.zkDb = database;\n    }\n\n    protected ZKDatabase getZkDb() {\n        return zkDb;\n    }\n\n    public void setRunning(boolean running) {\n        this.running = running;\n    }\n\n    public boolean isRunning() {\n        return running;\n    }\n\n    /**\n     * get reference to QuorumCnxManager\n     */\n    public QuorumCnxManager getQuorumCnxManager() {\n        return qcm;\n    }\n    private long readLongFromFile(String name) throws IOException {\n    \tFile file = new File(logFactory.getSnapDir(), name);\n\t\tBufferedReader br = new BufferedReader(new FileReader(file));\n\t\tString line = \"\";\n\t\ttry {\n\t\t\tline = br.readLine();\n    \t\treturn Long.parseLong(line);\n    \t} catch(NumberFormatException e) {\n    \t\tthrow new IOException(\"Found \" + line + \" in \" + file);\n    \t} finally {\n    \t\tbr.close();\n    \t}\n    }\n\n    private long acceptedEpoch = -1;\n    private long currentEpoch = -1;\n\n\tpublic static final String CURRENT_EPOCH_FILENAME = \"currentEpoch\";\n\n\tpublic static final String ACCEPTED_EPOCH_FILENAME = \"acceptedEpoch\";\n\n    public static final String UPDATING_EPOCH_FILENAME = \"updatingEpoch\";\n\n\t/**\n\t * Write a long value to disk atomically. Either succeeds or an exception\n\t * is thrown.\n\t * @param name file name to write the long to\n\t * @param value the long value to write to the named file\n\t * @throws IOException if the file cannot be written atomically\n\t */\n    private void writeLongToFile(String name, long value) throws IOException {\n        File file = new File(logFactory.getSnapDir(), name);\n        AtomicFileOutputStream out = new AtomicFileOutputStream(file);\n        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));\n        boolean aborted = false;\n        try {\n            bw.write(Long.toString(value));\n            bw.flush();\n            \n            out.flush();\n        } catch (IOException e) {\n            LOG.error(\"Failed to write new file \" + file, e);\n            // worst case here the tmp file/resources(fd) are not cleaned up\n            //   and the caller will be notified (IOException)\n            aborted = true;\n            out.abort();\n            throw e;\n        } finally {\n            if (!aborted) {\n                // if the close operation (rename) fails we'll get notified.\n                // worst case the tmp file may still exist\n                out.close();\n            }\n        }\n    }\n\n    public long getCurrentEpoch() throws IOException {\n\t\tif (currentEpoch == -1) {\n\t\t\tcurrentEpoch = readLongFromFile(CURRENT_EPOCH_FILENAME);\n\t\t}\n\t\treturn currentEpoch;\n\t}\n\t\n\tpublic long getAcceptedEpoch() throws IOException {\n\t\tif (acceptedEpoch == -1) {\n\t\t\tacceptedEpoch = readLongFromFile(ACCEPTED_EPOCH_FILENAME);\n\t\t}\n\t\treturn acceptedEpoch;\n\t}\n\t\n\tpublic void setCurrentEpoch(long e) throws IOException {\n\t\tcurrentEpoch = e;\n\t\twriteLongToFile(CURRENT_EPOCH_FILENAME, e);\n\t\t\n\t}\n\t\n\tpublic void setAcceptedEpoch(long e) throws IOException {\n\t\tacceptedEpoch = e;\n\t\twriteLongToFile(ACCEPTED_EPOCH_FILENAME, e);\n\t}\n\n    /**\n     * Updates leader election info to avoid inconsistencies when\n     * a new server tries to join the ensemble.\n     * See ZOOKEEPER-1732 for more info.\n     */\n    protected void updateElectionVote(long newEpoch) {\n        Vote currentVote = getCurrentVote();\n        setBCVote(currentVote);\n        if (currentVote != null) {\n            setCurrentVote(new Vote(currentVote.getId(),\n                currentVote.getZxid(),\n                currentVote.getElectionEpoch(),\n                newEpoch,\n                currentVote.getState()));\n        }\n    }\n\n    void setQuorumServerSaslRequired(boolean serverSaslRequired) {\n        quorumServerSaslAuthRequired = serverSaslRequired;\n        LOG.info(\"{} set to {}\", QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED,\n                serverSaslRequired);\n    }\n\n    void setQuorumLearnerSaslRequired(boolean learnerSaslRequired) {\n        quorumLearnerSaslAuthRequired = learnerSaslRequired;\n        LOG.info(\"{} set to {}\", QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED,\n                learnerSaslRequired);\n    }\n\n    void setQuorumSaslEnabled(boolean enableAuth) {\n        quorumSaslEnableAuth = enableAuth;\n        if (!quorumSaslEnableAuth) {\n            LOG.info(\"QuorumPeer communication is not secured!\");\n        } else {\n            LOG.info(\"{} set to {}\",\n                    QuorumAuth.QUORUM_SASL_AUTH_ENABLED, enableAuth);\n        }\n    }\n\n    void setQuorumServicePrincipal(String servicePrincipal) {\n        quorumServicePrincipal = servicePrincipal;\n        LOG.info(\"{} set to {}\",QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL,\n                quorumServicePrincipal);\n    }\n\n    void setQuorumLearnerLoginContext(String learnerContext) {\n        quorumLearnerLoginContext = learnerContext;\n        LOG.info(\"{} set to {}\", QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,\n                quorumLearnerLoginContext);\n    }\n\n    void setQuorumServerLoginContext(String serverContext) {\n        quorumServerLoginContext = serverContext;\n        LOG.info(\"{} set to {}\", QuorumAuth.QUORUM_SERVER_SASL_LOGIN_CONTEXT,\n                quorumServerLoginContext);\n    }\n\n    void setQuorumCnxnThreadsSize(int qCnxnThreadsSize) {\n        if (qCnxnThreadsSize > QUORUM_CNXN_THREADS_SIZE_DEFAULT_VALUE) {\n            quorumCnxnThreadsSize = qCnxnThreadsSize;\n        }\n        LOG.info(\"quorum.cnxn.threads.size set to {}\", quorumCnxnThreadsSize);\n    }\n\n    boolean isQuorumSaslAuthEnabled() {\n        return quorumSaslEnableAuth;\n    }\n\n    private boolean isQuorumServerSaslAuthRequired() {\n        return quorumServerSaslAuthRequired;\n    }\n\n    private boolean isQuorumLearnerSaslAuthRequired() {\n        return quorumLearnerSaslAuthRequired;\n    }\n\n    // VisibleForTesting. Returns true if both the quorumlearner and\n    // quorumserver login has been finished. Otherwse, false.\n    public boolean hasAuthInitialized(){\n        return authInitialized;\n    }\n\n    public QuorumCnxManager createCnxnManager() {\n        return new QuorumCnxManager(this.getId(),\n                                    this.getView(),\n                                    this.authServer,\n                                    this.authLearner,\n                                    this.tickTime * this.syncLimit,\n                                    this.getQuorumListenOnAllIPs(),\n                                    this.quorumCnxnThreadsSize,\n                                    this.isQuorumSaslAuthEnabled());\n    }\n\n    /**\n     * Sets the time taken for leader election in milliseconds.\n     *\n     * @param electionTimeTaken\n     *            time taken for leader election\n     */\n    void setElectionTimeTaken(long electionTimeTaken) {\n        this.electionTimeTaken = electionTimeTaken;\n    }\n\n    /**\n     * @return the time taken for leader election in milliseconds.\n     */\n    long getElectionTimeTaken() {\n        return electionTimeTaken;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumPeerConfig.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Map.Entry;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuth;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumMaj;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;\n\n@InterfaceAudience.Public\npublic class QuorumPeerConfig {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumPeerConfig.class);\n\n    protected InetSocketAddress clientPortAddress;\n    protected String dataDir;\n    protected String dataLogDir;\n    protected int tickTime = ZooKeeperServer.DEFAULT_TICK_TIME;\n    protected int maxClientCnxns = 60;\n    /** defaults to -1 if not set explicitly */\n    protected int minSessionTimeout = -1;\n    /** defaults to -1 if not set explicitly */\n    protected int maxSessionTimeout = -1;\n\n    protected int initLimit;\n    protected int syncLimit;\n    protected int electionAlg = 3;\n    protected int electionPort = 2182;\n    protected boolean quorumListenOnAllIPs = false;\n    protected final HashMap<Long,QuorumServer> servers =\n        new HashMap<Long, QuorumServer>();\n    protected final HashMap<Long,QuorumServer> observers =\n        new HashMap<Long, QuorumServer>();\n\n    protected long serverId;\n    protected HashMap<Long, Long> serverWeight = new HashMap<Long, Long>();\n    protected HashMap<Long, Long> serverGroup = new HashMap<Long, Long>();\n    protected int numGroups = 0;\n    protected QuorumVerifier quorumVerifier;\n    protected int snapRetainCount = 3;\n    protected int purgeInterval = 0;\n    protected boolean syncEnabled = true;\n\n    protected LearnerType peerType = LearnerType.PARTICIPANT;\n\n    /** Configurations for the quorumpeer-to-quorumpeer sasl authentication */\n    protected boolean quorumServerRequireSasl = false;\n    protected boolean quorumLearnerRequireSasl = false;\n    protected boolean quorumEnableSasl = false;\n    protected String quorumServicePrincipal = QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE;\n    protected String quorumLearnerLoginContext = QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT_DFAULT_VALUE;\n    protected String quorumServerLoginContext = QuorumAuth.QUORUM_SERVER_SASL_LOGIN_CONTEXT_DFAULT_VALUE;\n    protected int quorumCnxnThreadsSize;\n\n    /**\n     * Minimum snapshot retain count.\n     * @see org.apache.zookeeper.server.PurgeTxnLog#purge(File, File, int)\n     */\n    private final int MIN_SNAP_RETAIN_COUNT = 3;\n\n    @SuppressWarnings(\"serial\")\n    public static class ConfigException extends Exception {\n        public ConfigException(String msg) {\n            super(msg);\n        }\n        public ConfigException(String msg, Exception e) {\n            super(msg, e);\n        }\n    }\n\n    private static String[] splitWithLeadingHostname(String s)\n            throws ConfigException\n    {\n        /* Does it start with an IPv6 literal? */\n        if (s.startsWith(\"[\")) {\n            int i = s.indexOf(\"]:\");\n            if (i < 0) {\n                throw new ConfigException(s + \" starts with '[' but has no matching ']:'\");\n            }\n\n            String[] sa = s.substring(i + 2).split(\":\");\n            String[] nsa = new String[sa.length + 1];\n            nsa[0] = s.substring(1, i);\n            System.arraycopy(sa, 0, nsa, 1, sa.length);\n\n            return nsa;\n        } else {\n            return s.split(\":\");\n        }\n    }\n\n    /**\n     * Parse a ZooKeeper configuration file\n     * @param path the patch of the configuration file\n     * @throws ConfigException error processing configuration\n     */\n    public void parse(String path) throws ConfigException {\n        File configFile = new File(path);\n\n        LOG.info(\"Reading configuration from: \" + configFile);\n\n        try {\n            if (!configFile.exists()) {\n                throw new IllegalArgumentException(configFile.toString()\n                        + \" file is missing\");\n            }\n\n            Properties cfg = new Properties();\n            FileInputStream in = new FileInputStream(configFile);\n            try {\n                cfg.load(in);\n            } finally {\n                in.close();\n            }\n\n            parseProperties(cfg);\n        } catch (IOException e) {\n            throw new ConfigException(\"Error processing \" + path, e);\n        } catch (IllegalArgumentException e) {\n            throw new ConfigException(\"Error processing \" + path, e);\n        }\n    }\n\n    /**\n     * Parse config from a Properties.\n     * @param zkProp Properties to parse from.\n     * @throws IOException\n     * @throws ConfigException\n     */\n    public void parseProperties(Properties zkProp)\n    throws IOException, ConfigException {\n        int clientPort = 0;\n        String clientPortAddress = null;\n        for (Entry<Object, Object> entry : zkProp.entrySet()) {\n            String key = entry.getKey().toString().trim();\n            String value = entry.getValue().toString().trim();\n            if (key.equals(\"dataDir\")) {\n                dataDir = value;\n            } else if (key.equals(\"dataLogDir\")) {\n                dataLogDir = value;\n            } else if (key.equals(\"clientPort\")) {\n                clientPort = Integer.parseInt(value);\n            } else if (key.equals(\"clientPortAddress\")) {\n                clientPortAddress = value.trim();\n            } else if (key.equals(\"tickTime\")) {\n                tickTime = Integer.parseInt(value);\n            } else if (key.equals(\"maxClientCnxns\")) {\n                maxClientCnxns = Integer.parseInt(value);\n            } else if (key.equals(\"minSessionTimeout\")) {\n                minSessionTimeout = Integer.parseInt(value);\n            } else if (key.equals(\"maxSessionTimeout\")) {\n                maxSessionTimeout = Integer.parseInt(value);\n            } else if (key.equals(\"initLimit\")) {\n                initLimit = Integer.parseInt(value);\n            } else if (key.equals(\"syncLimit\")) {\n                syncLimit = Integer.parseInt(value);\n            } else if (key.equals(\"electionAlg\")) {\n                electionAlg = Integer.parseInt(value);\n            } else if (key.equals(\"quorumListenOnAllIPs\")) {\n                quorumListenOnAllIPs = Boolean.parseBoolean(value);\n            } else if (key.equals(\"peerType\")) {\n                if (value.toLowerCase().equals(\"observer\")) {\n                    peerType = LearnerType.OBSERVER;\n                } else if (value.toLowerCase().equals(\"participant\")) {\n                    peerType = LearnerType.PARTICIPANT;\n                } else\n                {\n                    throw new ConfigException(\"Unrecognised peertype: \" + value);\n                }\n            } else if (key.equals( \"syncEnabled\" )) {\n                syncEnabled = Boolean.parseBoolean(value);\n            } else if (key.equals(\"autopurge.snapRetainCount\")) {\n                snapRetainCount = Integer.parseInt(value);\n            } else if (key.equals(\"autopurge.purgeInterval\")) {\n                purgeInterval = Integer.parseInt(value);\n            } else if (key.startsWith(\"server.\")) {\n                int dot = key.indexOf('.');\n                long sid = Long.parseLong(key.substring(dot + 1));\n                String parts[] = splitWithLeadingHostname(value);\n                if ((parts.length != 2) && (parts.length != 3) && (parts.length !=4)) {\n                    LOG.error(value\n                       + \" does not have the form host:port or host:port:port \" +\n                       \" or host:port:port:type\");\n                }\n                LearnerType type = null;\n                String hostname = parts[0];\n                Integer port = Integer.parseInt(parts[1]);\n                Integer electionPort = null;\n                if (parts.length > 2){\n                \telectionPort=Integer.parseInt(parts[2]);\n                }\n                if (parts.length > 3){\n                    if (parts[3].toLowerCase().equals(\"observer\")) {\n                        type = LearnerType.OBSERVER;\n                    } else if (parts[3].toLowerCase().equals(\"participant\")) {\n                        type = LearnerType.PARTICIPANT;\n                    } else {\n                        throw new ConfigException(\"Unrecognised peertype: \" + value);\n                    }\n                }\n                if (type == LearnerType.OBSERVER){\n                    observers.put(Long.valueOf(sid), new QuorumServer(sid, hostname, port, electionPort, type));\n                } else {\n                    servers.put(Long.valueOf(sid), new QuorumServer(sid, hostname, port, electionPort, type));\n                }\n            } else if (key.startsWith(\"group\")) {\n                int dot = key.indexOf('.');\n                long gid = Long.parseLong(key.substring(dot + 1));\n\n                numGroups++;\n\n                String parts[] = value.split(\":\");\n                for(String s : parts){\n                    long sid = Long.parseLong(s);\n                    if(serverGroup.containsKey(sid))\n                        throw new ConfigException(\"Server \" + sid + \"is in multiple groups\");\n                    else\n                        serverGroup.put(sid, gid);\n                }\n\n            } else if(key.startsWith(\"weight\")) {\n                int dot = key.indexOf('.');\n                long sid = Long.parseLong(key.substring(dot + 1));\n                serverWeight.put(sid, Long.parseLong(value));\n            } else if (key.equals(QuorumAuth.QUORUM_SASL_AUTH_ENABLED)) {\n                quorumEnableSasl = Boolean.parseBoolean(value);\n            } else if (key.equals(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED)) {\n                quorumServerRequireSasl = Boolean.parseBoolean(value);\n            } else if (key.equals(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED)) {\n                quorumLearnerRequireSasl = Boolean.parseBoolean(value);\n            } else if (key.equals(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT)) {\n                quorumLearnerLoginContext = value;\n            } else if (key.equals(QuorumAuth.QUORUM_SERVER_SASL_LOGIN_CONTEXT)) {\n                quorumServerLoginContext = value;\n            } else if (key.equals(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL)) {\n                quorumServicePrincipal = value;\n            } else if (key.equals(\"quorum.cnxn.threads.size\")) {\n                quorumCnxnThreadsSize = Integer.parseInt(value);\n            } else {\n                System.setProperty(\"zookeeper.\" + key, value);\n            }\n        }\n        if (!quorumEnableSasl && quorumServerRequireSasl) {\n            throw new IllegalArgumentException(\n                    QuorumAuth.QUORUM_SASL_AUTH_ENABLED\n                    + \" is disabled, so cannot enable \"\n                    + QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED);\n        }\n        if (!quorumEnableSasl && quorumLearnerRequireSasl) {\n            throw new IllegalArgumentException(\n                    QuorumAuth.QUORUM_SASL_AUTH_ENABLED\n                    + \" is disabled, so cannot enable \"\n                    + QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED);\n        }\n        // If quorumpeer learner is not auth enabled then self won't be able to\n        // join quorum. So this condition is ensuring that the quorumpeer learner\n        // is also auth enabled while enabling quorum server require sasl.\n        if (!quorumLearnerRequireSasl && quorumServerRequireSasl) {\n            throw new IllegalArgumentException(\n                    QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED\n                    + \" is disabled, so cannot enable \"\n                    + QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED);\n        }\n        // Reset to MIN_SNAP_RETAIN_COUNT if invalid (less than 3)\n        // PurgeTxnLog.purge(File, File, int) will not allow to purge less\n        // than 3.\n        if (snapRetainCount < MIN_SNAP_RETAIN_COUNT) {\n            LOG.warn(\"Invalid autopurge.snapRetainCount: \" + snapRetainCount\n                    + \". Defaulting to \" + MIN_SNAP_RETAIN_COUNT);\n            snapRetainCount = MIN_SNAP_RETAIN_COUNT;\n        }\n\n        if (dataDir == null) {\n            throw new IllegalArgumentException(\"dataDir is not set\");\n        }\n        if (dataLogDir == null) {\n            dataLogDir = dataDir;\n        }\n        if (clientPort == 0) {\n            throw new IllegalArgumentException(\"clientPort is not set\");\n        }\n        if (clientPortAddress != null) {\n            this.clientPortAddress = new InetSocketAddress(\n                    InetAddress.getByName(clientPortAddress), clientPort);\n        } else {\n            this.clientPortAddress = new InetSocketAddress(clientPort);\n        }\n\n        if (tickTime == 0) {\n            throw new IllegalArgumentException(\"tickTime is not set\");\n        }\n        if (minSessionTimeout > maxSessionTimeout) {\n            throw new IllegalArgumentException(\n                    \"minSessionTimeout must not be larger than maxSessionTimeout\");\n        }\n        if (servers.size() == 0) {\n            if (observers.size() > 0) {\n                throw new IllegalArgumentException(\"Observers w/o participants is an invalid configuration\");\n            }\n            // Not a quorum configuration so return immediately - not an error\n            // case (for b/w compatibility), server will default to standalone\n            // mode.\n            return;\n        } else if (servers.size() == 1) {\n            if (observers.size() > 0) {\n                throw new IllegalArgumentException(\"Observers w/o quorum is an invalid configuration\");\n            }\n\n            // HBase currently adds a single server line to the config, for\n            // b/w compatibility reasons we need to keep this here.\n            LOG.error(\"Invalid configuration, only one server specified (ignoring)\");\n            servers.clear();\n        } else if (servers.size() > 1) {\n            if (servers.size() == 2) {\n                LOG.warn(\"No server failure will be tolerated. \" +\n                    \"You need at least 3 servers.\");\n            } else if (servers.size() % 2 == 0) {\n                LOG.warn(\"Non-optimial configuration, consider an odd number of servers.\");\n            }\n            if (initLimit == 0) {\n                throw new IllegalArgumentException(\"initLimit is not set\");\n            }\n            if (syncLimit == 0) {\n                throw new IllegalArgumentException(\"syncLimit is not set\");\n            }\n            /*\n             * If using FLE, then every server requires a separate election\n             * port.\n             */\n            if (electionAlg != 0) {\n                for (QuorumServer s : servers.values()) {\n                    if (s.electionAddr == null)\n                        throw new IllegalArgumentException(\n                                \"Missing election port for server: \" + s.id);\n                }\n            }\n\n            /*\n             * Default of quorum config is majority\n             */\n            if(serverGroup.size() > 0){\n                if(servers.size() != serverGroup.size())\n                    throw new ConfigException(\"Every server must be in exactly one group\");\n                /*\n                 * The deafult weight of a server is 1\n                 */\n                for(QuorumServer s : servers.values()){\n                    if(!serverWeight.containsKey(s.id))\n                        serverWeight.put(s.id, (long) 1);\n                }\n\n                /*\n                 * Set the quorumVerifier to be QuorumHierarchical\n                 */\n                quorumVerifier = new QuorumHierarchical(numGroups,\n                        serverWeight, serverGroup);\n            } else {\n                /*\n                 * The default QuorumVerifier is QuorumMaj\n                 */\n\n                LOG.info(\"Defaulting to majority quorums\");\n                quorumVerifier = new QuorumMaj(servers.size());\n            }\n\n            // Now add observers to servers, once the quorums have been\n            // figured out\n            servers.putAll(observers);\n\n            File myIdFile = new File(dataDir, \"myid\");\n            if (!myIdFile.exists()) {\n                throw new IllegalArgumentException(myIdFile.toString()\n                        + \" file is missing\");\n            }\n            BufferedReader br = new BufferedReader(new FileReader(myIdFile));\n            String myIdString;\n            try {\n                myIdString = br.readLine();\n            } finally {\n                br.close();\n            }\n            try {\n                serverId = Long.parseLong(myIdString);\n                MDC.put(\"myid\", myIdString);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\"serverid \" + myIdString\n                        + \" is not a number\");\n            }\n            \n            // Warn about inconsistent peer type\n            LearnerType roleByServersList = observers.containsKey(serverId) ? LearnerType.OBSERVER\n                    : LearnerType.PARTICIPANT;\n            if (roleByServersList != peerType) {\n                LOG.warn(\"Peer type from servers list (\" + roleByServersList\n                        + \") doesn't match peerType (\" + peerType\n                        + \"). Defaulting to servers list.\");\n    \n                peerType = roleByServersList;\n            }\n        }\n    }\n\n    public InetSocketAddress getClientPortAddress() { return clientPortAddress; }\n    public String getDataDir() { return dataDir; }\n    public String getDataLogDir() { return dataLogDir; }\n    public int getTickTime() { return tickTime; }\n    public int getMaxClientCnxns() { return maxClientCnxns; }\n    public int getMinSessionTimeout() { return minSessionTimeout; }\n    public int getMaxSessionTimeout() { return maxSessionTimeout; }\n\n    public int getInitLimit() { return initLimit; }\n    public int getSyncLimit() { return syncLimit; }\n    public int getElectionAlg() { return electionAlg; }\n    public int getElectionPort() { return electionPort; }\n    \n    public int getSnapRetainCount() {\n        return snapRetainCount;\n    }\n\n    public int getPurgeInterval() {\n        return purgeInterval;\n    }\n    \n    public boolean getSyncEnabled() {\n        return syncEnabled;\n    }\n\n    public QuorumVerifier getQuorumVerifier() {\n        return quorumVerifier;\n    }\n\n    public Map<Long,QuorumServer> getServers() {\n        return Collections.unmodifiableMap(servers);\n    }\n\n    public long getServerId() { return serverId; }\n\n    public boolean isDistributed() { return servers.size() > 1; }\n\n    public LearnerType getPeerType() {\n        return peerType;\n    }\n\n    public Boolean getQuorumListenOnAllIPs() {\n        return quorumListenOnAllIPs;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumPeerMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport javax.management.JMException;\nimport javax.security.sasl.SaslException;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.jmx.ManagedUtil;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.DatadirCleanupManager;\nimport org.apache.zookeeper.server.ZooKeeperServerMain;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;\n\n/**\n *\n * <h2>Configuration file</h2>\n *\n * When the main() method of this class is used to start the program, the first\n * argument is used as a path to the config file, which will be used to obtain\n * configuration information. This file is a Properties file, so keys and\n * values are separated by equals (=) and the key/value pairs are separated\n * by new lines. The following is a general summary of keys used in the\n * configuration file. For full details on this see the documentation in\n * docs/index.html\n * <ol>\n * <li>dataDir - The directory where the ZooKeeper data is stored.</li>\n * <li>dataLogDir - The directory where the ZooKeeper transaction log is stored.</li>\n * <li>clientPort - The port used to communicate with clients.</li>\n * <li>tickTime - The duration of a tick in milliseconds. This is the basic\n * unit of time in ZooKeeper.</li>\n * <li>initLimit - The maximum number of ticks that a follower will wait to\n * initially synchronize with a leader.</li>\n * <li>syncLimit - The maximum number of ticks that a follower will wait for a\n * message (including heartbeats) from the leader.</li>\n * <li>server.<i>id</i> - This is the host:port[:port] that the server with the\n * given id will use for the quorum protocol.</li>\n * </ol>\n * In addition to the config file. There is a file in the data directory called\n * \"myid\" that contains the server id as an ASCII decimal value.\n *\n */\n@InterfaceAudience.Public\npublic class QuorumPeerMain {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumPeerMain.class);\n\n    private static final String USAGE = \"Usage: QuorumPeerMain configfile\";\n\n    protected QuorumPeer quorumPeer;\n\n    /**\n     * To start the replicated server specify the configuration file name on\n     * the command line.\n     * @param args path to the configfile\n     */\n    public static void main(String[] args) {\n        QuorumPeerMain main = new QuorumPeerMain();\n        try {\n            main.initializeAndRun(args);\n        } catch (IllegalArgumentException e) {\n            LOG.error(\"Invalid arguments, exiting abnormally\", e);\n            LOG.info(USAGE);\n            System.err.println(USAGE);\n            System.exit(2);\n        } catch (ConfigException e) {\n            LOG.error(\"Invalid config, exiting abnormally\", e);\n            System.err.println(\"Invalid config, exiting abnormally\");\n            System.exit(2);\n        } catch (Exception e) {\n            LOG.error(\"Unexpected exception, exiting abnormally\", e);\n            System.exit(1);\n        }\n        LOG.info(\"Exiting normally\");\n        System.exit(0);\n    }\n\n    protected void initializeAndRun(String[] args)\n        throws ConfigException, IOException\n    {\n        QuorumPeerConfig config = new QuorumPeerConfig();\n        if (args.length == 1) {\n            config.parse(args[0]);\n        }\n\n        // Start and schedule the the purge task\n        DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config\n                .getDataDir(), config.getDataLogDir(), config\n                .getSnapRetainCount(), config.getPurgeInterval());\n        purgeMgr.start();\n\n        if (args.length == 1 && config.servers.size() > 0) {\n            runFromConfig(config);\n        } else {\n            LOG.warn(\"Either no config or no quorum defined in config, running \"\n                    + \" in standalone mode\");\n            // there is only server in the quorum -- run as standalone\n            ZooKeeperServerMain.main(args);\n        }\n    }\n\n    public void runFromConfig(QuorumPeerConfig config) throws IOException {\n      try {\n          ManagedUtil.registerLog4jMBeans();\n      } catch (JMException e) {\n          LOG.warn(\"Unable to register log4j JMX control\", e);\n      }\n  \n      LOG.info(\"Starting quorum peer\");\n      try {\n          ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();\n          cnxnFactory.configure(config.getClientPortAddress(),\n                                config.getMaxClientCnxns());\n\n          quorumPeer = getQuorumPeer();\n\n          quorumPeer.setQuorumPeers(config.getServers());\n          quorumPeer.setTxnFactory(new FileTxnSnapLog(\n                  new File(config.getDataLogDir()),\n                  new File(config.getDataDir())));\n          quorumPeer.setElectionType(config.getElectionAlg());\n          quorumPeer.setMyid(config.getServerId());\n          quorumPeer.setTickTime(config.getTickTime());\n          quorumPeer.setInitLimit(config.getInitLimit());\n          quorumPeer.setSyncLimit(config.getSyncLimit());\n          quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs());\n          quorumPeer.setCnxnFactory(cnxnFactory);\n          quorumPeer.setQuorumVerifier(config.getQuorumVerifier());\n          quorumPeer.setClientPortAddress(config.getClientPortAddress());\n          quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout());\n          quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout());\n          quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory()));\n          quorumPeer.setLearnerType(config.getPeerType());\n          quorumPeer.setSyncEnabled(config.getSyncEnabled());\n\n          // sets quorum sasl authentication configurations\n          quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl);\n          if(quorumPeer.isQuorumSaslAuthEnabled()){\n              quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl);\n              quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl);\n              quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal);\n              quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext);\n              quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext);\n          }\n\n          quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize);\n          quorumPeer.initialize();\n\n          quorumPeer.start();\n          quorumPeer.join();\n      } catch (InterruptedException e) {\n          // warn, but generally this is ok\n          LOG.warn(\"Quorum Peer interrupted\", e);\n      }\n    }\n\n    // @VisibleForTesting\n    protected QuorumPeer getQuorumPeer() throws SaslException {\n        return new QuorumPeer();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumStats.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\npublic class QuorumStats {\n    private final Provider provider;\n    \n    public interface Provider {\n        static public final String UNKNOWN_STATE = \"unknown\";\n        static public final String LOOKING_STATE = \"leaderelection\";\n        static public final String LEADING_STATE = \"leading\";\n        static public final String FOLLOWING_STATE = \"following\";\n        static public final String OBSERVING_STATE = \"observing\";\n        public String[] getQuorumPeers();\n        public String getServerState();\n    }\n    \n    protected QuorumStats(Provider provider) {\n        this.provider = provider;\n    }\n    \n    public String getServerState(){\n        return provider.getServerState();\n    }\n    \n    public String[] getQuorumPeers(){\n        return provider.getQuorumPeers();\n    }\n\n    @Override\n    public String toString(){\n        StringBuilder sb=new StringBuilder(super.toString());\n        String state=getServerState();\n        if(state.equals(Provider.LEADING_STATE)){\n            sb.append(\"Followers:\");\n            for(String f: getQuorumPeers()){\n                sb.append(\" \").append(f);\n            }\n            sb.append(\"\\n\");            \n        }else if(state.equals(Provider.FOLLOWING_STATE) \n                || state.equals(Provider.OBSERVING_STATE)){\n            sb.append(\"Leader: \");\n            String[] ldr=getQuorumPeers();\n            if(ldr.length>0)\n                sb.append(ldr[0]);\n            else\n                sb.append(\"not connected\");\n            sb.append(\"\\n\");\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/QuorumZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.PrintWriter;\n\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * Abstract base class for all ZooKeeperServers that participate in\n * a quorum.\n */\npublic abstract class QuorumZooKeeperServer extends ZooKeeperServer {\n    protected final QuorumPeer self;\n\n    protected QuorumZooKeeperServer(FileTxnSnapLog logFactory, int tickTime,\n            int minSessionTimeout, int maxSessionTimeout,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb, QuorumPeer self)\n    {\n        super(logFactory, tickTime, minSessionTimeout, maxSessionTimeout,\n                treeBuilder, zkDb);\n        this.self = self;\n    }\n\n    @Override\n    public void dumpConf(PrintWriter pwriter) {\n        super.dumpConf(pwriter);\n\n        pwriter.print(\"initLimit=\");\n        pwriter.println(self.getInitLimit());\n        pwriter.print(\"syncLimit=\");\n        pwriter.println(self.getSyncLimit());\n        pwriter.print(\"electionAlg=\");\n        pwriter.println(self.getElectionType());\n        pwriter.print(\"electionPort=\");\n        pwriter.println(self.quorumPeers.get(self.getId()).electionAddr\n                .getPort());\n        pwriter.print(\"quorumPort=\");\n        pwriter.println(self.quorumPeers.get(self.getId()).addr.getPort());\n        pwriter.print(\"peerType=\");\n        pwriter.println(self.getLearnerType().ordinal());\n    }\n\n    @Override\n    protected void setState(State state) {\n        this.state = state;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ReadOnlyBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooKeeperServerBean;\n\n/**\n * ReadOnly MX Bean interface, implemented by ReadOnlyBean\n *\n */\npublic class ReadOnlyBean extends ZooKeeperServerBean {\n\n    public ReadOnlyBean(ZooKeeperServer zks) {\n        super(zks);\n    }\n\n    public String getName() {\n        return \"ReadOnlyServer\";\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ReadOnlyRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.IOException;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperCriticalThread;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.quorum.Leader.XidRolloverException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This processor is at the beginning of the ReadOnlyZooKeeperServer's\n * processors chain. All it does is, it passes read-only operations (e.g.\n * OpCode.getData, OpCode.exists) through to the next processor, but drops\n * state-changing operations (e.g. OpCode.create, OpCode.setData).\n */\npublic class ReadOnlyRequestProcessor extends ZooKeeperCriticalThread implements RequestProcessor {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyRequestProcessor.class);\n\n    private LinkedBlockingQueue<Request> queuedRequests = new LinkedBlockingQueue<Request>();\n\n    private boolean finished = false;\n\n    private RequestProcessor nextProcessor;\n\n    private ZooKeeperServer zks;\n\n    public ReadOnlyRequestProcessor(ZooKeeperServer zks,\n            RequestProcessor nextProcessor) {\n        super(\"ReadOnlyRequestProcessor:\" + zks.getServerId(), zks\n                .getZooKeeperServerListener());\n        this.zks = zks;\n        this.nextProcessor = nextProcessor;\n    }\n\n    public void run() {\n        try {\n            while (!finished) {\n                Request request = queuedRequests.take();\n\n                // log request\n                long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;\n                if (request.type == OpCode.ping) {\n                    traceMask = ZooTrace.CLIENT_PING_TRACE_MASK;\n                }\n                if (LOG.isTraceEnabled()) {\n                    ZooTrace.logRequest(LOG, traceMask, 'R', request, \"\");\n                }\n                if (Request.requestOfDeath == request) {\n                    break;\n                }\n\n                // filter read requests\n                switch (request.type) {\n                case OpCode.sync:\n                case OpCode.create:\n                case OpCode.delete:\n                case OpCode.setData:\n                case OpCode.setACL:\n                case OpCode.multi:\n                case OpCode.check:\n                    ReplyHeader hdr = new ReplyHeader(request.cxid, zks.getZKDatabase()\n                            .getDataTreeLastProcessedZxid(), Code.NOTREADONLY.intValue());\n                    try {\n                        request.cnxn.sendResponse(hdr, null, null);\n                    } catch (IOException e) {\n                        LOG.error(\"IO exception while sending response\", e);\n                    }\n                    continue;\n                }\n\n                // proceed to the next processor\n                if (nextProcessor != null) {\n                    nextProcessor.processRequest(request);\n                }\n            }\n        } catch (RequestProcessorException e) {\n            if (e.getCause() instanceof XidRolloverException) {\n                LOG.info(e.getCause().getMessage());\n            }\n            handleException(this.getName(), e);\n        } catch (Exception e) {\n            handleException(this.getName(), e);\n        }\n        LOG.info(\"ReadOnlyRequestProcessor exited loop!\");\n    }\n\n    @Override\n    public void processRequest(Request request) {\n        if (!finished) {\n            queuedRequests.add(request);\n        }\n    }\n\n    @Override\n    public void shutdown() {\n        finished = true;\n        queuedRequests.clear();\n        queuedRequests.add(Request.requestOfDeath);\n        nextProcessor.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ReadOnlyZooKeeperServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.apache.zookeeper.server.DataTreeBean;\nimport org.apache.zookeeper.server.FinalRequestProcessor;\nimport org.apache.zookeeper.server.PrepRequestProcessor;\nimport org.apache.zookeeper.server.RequestProcessor;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooKeeperServerBean;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * A ZooKeeperServer which comes into play when peer is partitioned from the\n * majority. Handles read-only clients, but drops connections from not-read-only\n * ones.\n * <p>\n * The very first processor in the chain of request processors is a\n * ReadOnlyRequestProcessor which drops state-changing requests.\n */\npublic class ReadOnlyZooKeeperServer extends QuorumZooKeeperServer {\n\n    private volatile boolean shutdown = false;\n    ReadOnlyZooKeeperServer(FileTxnSnapLog logFactory, QuorumPeer self,\n            DataTreeBuilder treeBuilder, ZKDatabase zkDb) {\n        super(logFactory, self.tickTime, self.minSessionTimeout, self.maxSessionTimeout,\n                treeBuilder, zkDb, self);\n    }\n\n    @Override\n    protected void setupRequestProcessors() {\n        RequestProcessor finalProcessor = new FinalRequestProcessor(this);\n        RequestProcessor prepProcessor = new PrepRequestProcessor(this, finalProcessor);\n        ((PrepRequestProcessor) prepProcessor).start();\n        firstProcessor = new ReadOnlyRequestProcessor(this, prepProcessor);\n        ((ReadOnlyRequestProcessor) firstProcessor).start();\n    }\n\n    @Override\n    public synchronized void startup() {\n        // check to avoid startup follows shutdown\n        if (shutdown) {\n            LOG.warn(\"Not starting Read-only server as startup follows shutdown!\");\n            return;\n        }\n        registerJMX(new ReadOnlyBean(this), self.jmxLocalPeerBean);\n        super.startup();\n        self.cnxnFactory.setZooKeeperServer(this);\n        LOG.info(\"Read-only server started\");\n    }\n\n    @Override\n    protected void registerJMX() {\n        // register with JMX\n        try {\n            jmxDataTreeBean = new DataTreeBean(getZKDatabase().getDataTree());\n            MBeanRegistry.getInstance().register(jmxDataTreeBean, jmxServerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxDataTreeBean = null;\n        }\n    }\n\n    public void registerJMX(ZooKeeperServerBean serverBean, LocalPeerBean localPeerBean) {\n        // register with JMX\n        try {\n            jmxServerBean = serverBean;\n            MBeanRegistry.getInstance().register(serverBean, localPeerBean);\n        } catch (Exception e) {\n            LOG.warn(\"Failed to register with JMX\", e);\n            jmxServerBean = null;\n        }\n    }\n\n    @Override\n    protected void setState(State state) {\n        this.state = state;\n    }\n\n    @Override\n    protected void unregisterJMX() {\n        // unregister from JMX\n        try {\n            if (jmxDataTreeBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxDataTreeBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxDataTreeBean = null;\n    }\n\n    protected void unregisterJMX(ZooKeeperServer zks) {\n        // unregister from JMX\n        try {\n            if (jmxServerBean != null) {\n                MBeanRegistry.getInstance().unregister(jmxServerBean);\n            }\n        } catch (Exception e) {\n            LOG.warn(\"Failed to unregister with JMX\", e);\n        }\n        jmxServerBean = null;\n    }\n\n    @Override\n    public String getState() {\n        return \"read-only\";\n    }\n\n    /**\n     * Returns the id of the associated QuorumPeer, which will do for a unique\n     * id of this server.\n     */\n    @Override\n    public long getServerId() {\n        return self.getId();\n    }\n\n    @Override\n    public synchronized void shutdown() {\n        if (!canShutdown()) {\n            LOG.debug(\"ZooKeeper server is not running, so not proceeding to shutdown!\");\n            return;\n        }\n        shutdown = true;\n        unregisterJMX(this);\n\n        // set peer's server to null\n        self.cnxnFactory.setZooKeeperServer(null);\n        // clear all the connections\n        self.cnxnFactory.closeAll();\n\n        // shutdown the server itself\n        super.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/RemotePeerBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\n\n/**\n * A remote peer bean only provides limited information about the remote peer,\n * and the peer cannot be managed remotely. \n */\npublic class RemotePeerBean implements RemotePeerMXBean,ZKMBeanInfo {\n    private QuorumPeer.QuorumServer peer;\n    \n    public RemotePeerBean(QuorumPeer.QuorumServer peer){\n        this.peer=peer;\n    }\n    public String getName() {\n        return \"replica.\"+peer.id;\n    }\n    public boolean isHidden() {\n        return false;\n    }\n\n    public String getQuorumAddress() {\n        return peer.addr.getHostName()+\":\"+peer.addr.getPort();\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/RemotePeerMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n/**\n * A proxy for a remote quorum peer.\n */\npublic interface RemotePeerMXBean {\n    /**\n     * @return name of the peer\n     */\n    public String getName();\n    /**\n     * @return IP address of the quorum peer \n     */\n    public String getQuorumAddress();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/SendAckRequestProcessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.Flushable;\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.RequestProcessor;\n\npublic class SendAckRequestProcessor implements RequestProcessor, Flushable {\n    private static final Logger LOG = LoggerFactory.getLogger(SendAckRequestProcessor.class);\n    \n    Learner learner;\n\n    SendAckRequestProcessor(Learner peer) {\n        this.learner = peer;\n    }\n\n    public void processRequest(Request si) {\n        if(si.type != OpCode.sync){\n            QuorumPacket qp = new QuorumPacket(Leader.ACK, si.hdr.getZxid(), null,\n                null);\n            try {\n                learner.writePacket(qp, false);\n            } catch (IOException e) {\n                LOG.warn(\"Closing connection to leader, exception during packet send\", e);\n                try {\n                    if (!learner.sock.isClosed()) {\n                        learner.sock.close();\n                    }\n                } catch (IOException e1) {\n                    // Nothing to do, we are shutting things down, so an exception here is irrelevant\n                    LOG.debug(\"Ignoring error closing the connection\", e1);\n                }\n            }\n        }\n    }\n    \n    public void flush() throws IOException {\n        try {\n            learner.writePacket(null, true);\n        } catch(IOException e) {\n            LOG.warn(\"Closing connection to leader, exception during packet send\", e);\n            try {\n                if (!learner.sock.isClosed()) {\n                    learner.sock.close();\n                }\n            } catch (IOException e1) {\n                    // Nothing to do, we are shutting things down, so an exception here is irrelevant\n                    LOG.debug(\"Ignoring error closing the connection\", e1);\n            }\n        }\n    }\n\n    public void shutdown() {\n        // Nothing needed\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ServerBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.util.Date;\n\nimport org.apache.zookeeper.jmx.ZKMBeanInfo;\n\n/**\n * An abstract base class for the leader and follower MBeans.\n */\npublic abstract class ServerBean implements ServerMXBean, ZKMBeanInfo {\n    private final Date startTime=new Date();\n    \n    public boolean isHidden() {\n        return false;\n    }\n\n    public String getStartTime() {\n        return startTime.toString();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/ServerMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n/**\n * A quorum server MBean.\n */\npublic interface ServerMXBean {\n    /**\n     * @return name of the server MBean\n     */\n    public String getName();\n    /**\n     * @return the start time the server \n     */\n    public String getStartTime();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/StateSummary.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\n/**\n * This class encapsulates the state comparison logic. Specifically,\n * how two different states are compared.\n */\npublic class StateSummary {\n\tprivate long currentEpoch;\n\tprivate long lastZxid;\n\tpublic StateSummary(long currentEpoch, long lastZxid) {\n\t\tthis.currentEpoch = currentEpoch;\n\t\tthis.lastZxid = lastZxid;\n\t}\n\t\n\tpublic long getCurrentEpoch() {\n\t\treturn currentEpoch;\n\t}\n\t\n\tpublic long getLastZxid() {\n\t\treturn lastZxid;\n\t}\n\t\n\tpublic boolean isMoreRecentThan(StateSummary ss) {\n\t\treturn (currentEpoch > ss.currentEpoch) || (currentEpoch == ss.currentEpoch && lastZxid > ss.lastZxid);\n\t}\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (!(obj instanceof StateSummary)) {\n\t\t\treturn false;\n\t\t}\n\t\tStateSummary ss = (StateSummary)obj;\n\t\treturn currentEpoch == ss.currentEpoch && lastZxid == ss.lastZxid;\n\t}\n\t\n\t@Override\n\tpublic int hashCode() {\n\t\treturn (int)(currentEpoch ^ lastZxid);\n\t}\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/Vote.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\npublic class Vote {\n    private static final Logger LOG = LoggerFactory.getLogger(Vote.class);\n    \n    public Vote(long id, \n                    long zxid) {\n        this.version = 0x0;\n        this.id = id;\n        this.zxid = zxid;\n        this.electionEpoch = -1;\n        this.peerEpoch = -1;\n        this.state = ServerState.LOOKING;\n    }\n    \n    public Vote(long id, \n                    long zxid, \n                    long peerEpoch) {\n        this.version = 0x0;\n        this.id = id;\n        this.zxid = zxid;\n        this.electionEpoch = -1;\n        this.peerEpoch = peerEpoch;\n        this.state = ServerState.LOOKING;\n    }\n\n    public Vote(long id, \n                    long zxid, \n                    long electionEpoch, \n                    long peerEpoch) {\n        this.version = 0x0;\n        this.id = id;\n        this.zxid = zxid;\n        this.electionEpoch = electionEpoch;\n        this.peerEpoch = peerEpoch;\n        this.state = ServerState.LOOKING;\n    }\n    \n    public Vote(int version,\n                    long id, \n                    long zxid, \n                    long electionEpoch, \n                    long peerEpoch, \n                    ServerState state) {\n        this.version = version;\n        this.id = id;\n        this.zxid = zxid;\n        this.electionEpoch = electionEpoch;\n        this.state = state;\n        this.peerEpoch = peerEpoch;\n    }\n    \n    public Vote(long id, \n                    long zxid, \n                    long electionEpoch, \n                    long peerEpoch, \n                    ServerState state) {\n        this.id = id;\n        this.zxid = zxid;\n        this.electionEpoch = electionEpoch;\n        this.state = state;\n        this.peerEpoch = peerEpoch;\n        this.version = 0x0;\n    }\n    \n    final private int version;\n    \n    final private long id;\n    \n    final private long zxid;\n    \n    final private long electionEpoch;\n    \n    final private long peerEpoch;\n    \n    public int getVersion() {\n        return version;\n    }\n    \n    public long getId() {\n        return id;\n    }\n\n    public long getZxid() {\n        return zxid;\n    }\n\n    public long getElectionEpoch() {\n        return electionEpoch;\n    }\n\n    public long getPeerEpoch() {\n        return peerEpoch;\n    }\n\n    public ServerState getState() {\n        return state;\n    }\n\n    final private ServerState state;\n    \n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof Vote)) {\n            return false;\n        }\n        Vote other = (Vote) o;\n        \n        \n        /*\n         * There are two things going on in the logic below.\n         * First, we compare votes of servers out of election\n         * using only id and peer epoch. Second, if one version\n         * is 0x0 and the other isn't, then we only use the\n         * leader id. This case is here to enable rolling upgrades.\n         * \n         * {@see https://issues.apache.org/jira/browse/ZOOKEEPER-1805}\n         */\n        if ((state == ServerState.LOOKING) ||\n                (other.state == ServerState.LOOKING)) {\n            return (id == other.id\n                    && zxid == other.zxid\n                    && electionEpoch == other.electionEpoch\n                    && peerEpoch == other.peerEpoch);\n        } else {\n            if ((version > 0x0) ^ (other.version > 0x0)) {\n                return id == other.id;\n            } else {\n                return (id == other.id\n                        && peerEpoch == other.peerEpoch);\n            }\n        } \n    }\n\n    @Override\n    public int hashCode() {\n        return (int) (id & zxid);\n    }\n\n    public String toString() {\n        return String.format(\"(%d, %s, %s)\",\n                                id,\n                                Long.toHexString(zxid),\n                                Long.toHexString(peerEpoch));\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/NullQuorumAuthLearner.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.net.Socket;\n\n/**\n * This class represents no authentication learner, it just return\n * without performing any authentication.\n */\npublic class NullQuorumAuthLearner implements QuorumAuthLearner {\n\n    @Override\n    public void authenticate(Socket sock, String hostname) {\n        return; // simply return don't require auth\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/NullQuorumAuthServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.DataInputStream;\nimport java.net.Socket;\n\n/**\n * This class represents no authentication server, it just return\n * without performing any authentication.\n */\npublic class NullQuorumAuthServer implements QuorumAuthServer {\n\n    @Override\n    public void authenticate(final Socket sock, final DataInputStream din) {\n        return; // simply return don't require auth\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/QuorumAuth.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport org.apache.jute.BinaryInputArchive;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.quorum.QuorumAuthPacket;\n\npublic class QuorumAuth {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumAuth.class);\n\n    public static final String QUORUM_SASL_AUTH_ENABLED = \"quorum.auth.enableSasl\";\n    public static final String QUORUM_SERVER_SASL_AUTH_REQUIRED = \"quorum.auth.serverRequireSasl\";\n    public static final String QUORUM_LEARNER_SASL_AUTH_REQUIRED = \"quorum.auth.learnerRequireSasl\";\n\n    public static final String QUORUM_KERBEROS_SERVICE_PRINCIPAL = \"quorum.auth.kerberos.servicePrincipal\";\n    public static final String QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE = \"zkquorum/localhost\";\n\n    public static final String QUORUM_LEARNER_SASL_LOGIN_CONTEXT = \"quorum.auth.learner.saslLoginContext\";\n    public static final String QUORUM_LEARNER_SASL_LOGIN_CONTEXT_DFAULT_VALUE = \"QuorumLearner\";\n\n    public static final String QUORUM_SERVER_SASL_LOGIN_CONTEXT = \"quorum.auth.server.saslLoginContext\";\n    public static final String QUORUM_SERVER_SASL_LOGIN_CONTEXT_DFAULT_VALUE = \"QuorumServer\";\n\n    static final String QUORUM_SERVER_PROTOCOL_NAME = \"zookeeper-quorum\";\n    static final String QUORUM_SERVER_SASL_DIGEST = \"zk-quorum-sasl-md5\";\n    static final String QUORUM_AUTH_MESSAGE_TAG = \"qpconnect\";\n\n    // this is negative, so that if a learner that does auth, connects to a\n    // server, it'll think the received packet is an authentication packet\n    public static final long QUORUM_AUTH_MAGIC_NUMBER = -0xa0dbcafecafe1234L;\n\n    public enum Status {\n         IN_PROGRESS(0), SUCCESS(1), ERROR(-1);\n        private int status;\n\n        Status(int status) {\n            this.status = status;\n        }\n\n        static Status getStatus(int status) {\n            switch (status) {\n            case 0:\n                return IN_PROGRESS;\n            case 1:\n                return SUCCESS;\n            case -1:\n                return ERROR;\n            default:\n                LOG.error(\"Unknown status:{}!\", status);\n                assert false : \"Unknown status!\";\n                return ERROR;\n            }\n        }\n\n        int status() {\n            return status;\n        }\n    }\n\n    public static QuorumAuthPacket createPacket(Status status, byte[] response) {\n        return new QuorumAuthPacket(QUORUM_AUTH_MAGIC_NUMBER,\n                                    status.status(), response);\n    }\n\n    public static boolean nextPacketIsAuth(DataInputStream din)\n            throws IOException {\n        din.mark(32);\n        BinaryInputArchive bia = new BinaryInputArchive(din);\n        boolean firstIsAuth = (bia.readLong(\"NO_TAG\")\n                               == QuorumAuth.QUORUM_AUTH_MAGIC_NUMBER);\n        din.reset();\n        return firstIsAuth;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/QuorumAuthLearner.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.IOException;\nimport java.net.Socket;\n\n/**\n * Interface for quorum learner authentication mechanisms.\n */\npublic interface QuorumAuthLearner {\n\n    /**\n     * Performs an authentication step for the given socket connection.\n     *\n     * @param sock\n     *            socket connection to other quorum peer server\n     * @param hostname\n     *            host name of other quorum peer server\n     * @throws IOException\n     *             if there is an authentication failure\n     */\n    public void authenticate(Socket sock, String hostname) throws IOException;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/QuorumAuthServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.net.Socket;\n\n/**\n * Interface for quorum server authentication mechanisms.\n */\npublic interface QuorumAuthServer {\n\n    /**\n     * Performs an authentication step for the given socket connection.\n     *\n     * @param sock\n     *            socket connection to other quorum peer\n     * @param din\n     *            stream used to read auth data send by the quorum learner\n     * @throws IOException if the server fails to authenticate connecting quorum learner\n     */\n    public void authenticate(Socket sock, DataInputStream din)\n            throws IOException;\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthLearner.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.BufferedOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.Socket;\nimport java.security.PrivilegedActionException;\nimport java.security.PrivilegedExceptionAction;\n\nimport javax.security.auth.Subject;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginException;\nimport javax.security.sasl.SaslClient;\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.Login;\nimport org.apache.zookeeper.SaslClientCallbackHandler;\nimport org.apache.zookeeper.server.quorum.QuorumAuthPacket;\nimport org.apache.zookeeper.util.SecurityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SaslQuorumAuthLearner implements QuorumAuthLearner {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(SaslQuorumAuthLearner.class);\n\n    private final Login learnerLogin;\n    private final boolean quorumRequireSasl;\n    private final String quorumServicePrincipal;\n\n    public SaslQuorumAuthLearner(boolean quorumRequireSasl,\n            String quorumServicePrincipal, String loginContext)\n                    throws SaslException {\n        this.quorumRequireSasl = quorumRequireSasl;\n        this.quorumServicePrincipal = quorumServicePrincipal;\n        try {\n            AppConfigurationEntry entries[] = Configuration\n                .getConfiguration()\n                .getAppConfigurationEntry(loginContext);\n            if (entries == null || entries.length == 0) {\n                throw new LoginException(\"SASL-authentication failed because\"\n                                         + \" the specified JAAS configuration \"\n                                         + \"section '\" + loginContext\n                                         + \"' could not be found.\");\n            }\n            this.learnerLogin = new Login(loginContext,\n                                    new SaslClientCallbackHandler(null, \"QuorumLearner\"));\n            this.learnerLogin.startThreadIfNeeded();\n        } catch (LoginException e) {\n            throw new SaslException(\"Failed to initialize authentication mechanism using SASL\", e);\n        }\n    }\n\n    @Override\n    public void authenticate(Socket sock, String hostName) throws IOException {\n        if (!quorumRequireSasl) { // let it through, we don't require auth\n            LOG.info(\"Skipping SASL authentication as {}={}\",\n                    QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED,\n                    quorumRequireSasl);\n            return;\n        }\n        SaslClient sc = null;\n        String principalConfig = SecurityUtils\n                .getServerPrincipal(quorumServicePrincipal, hostName);\n        try {\n            DataOutputStream dout = new DataOutputStream(\n                    sock.getOutputStream());\n            DataInputStream din = new DataInputStream(sock.getInputStream());\n            byte[] responseToken = new byte[0];\n            sc = SecurityUtils.createSaslClient(learnerLogin.getSubject(),\n                    principalConfig,\n                    QuorumAuth.QUORUM_SERVER_PROTOCOL_NAME,\n                    QuorumAuth.QUORUM_SERVER_SASL_DIGEST, LOG, \"QuorumLearner\");\n\n            if (sc.hasInitialResponse()) {\n                responseToken = createSaslToken(new byte[0], sc, learnerLogin);\n            }\n            send(dout, responseToken);\n            QuorumAuthPacket authPacket = receive(din);\n            QuorumAuth.Status qpStatus = QuorumAuth.Status\n                    .getStatus(authPacket.getStatus());\n            while (!sc.isComplete()) {\n                switch (qpStatus) {\n                case SUCCESS:\n                    responseToken = createSaslToken(authPacket.getToken(), sc,\n                            learnerLogin);\n                    // we're done; don't expect to send another BIND\n                    if (responseToken != null) {\n                        throw new SaslException(\n                                \"Protocol error: attempting to send response after completion\"\n                                        + \". Server addr: \"\n                                        + sock.getRemoteSocketAddress());\n                    }\n                    break;\n                case IN_PROGRESS:\n                    responseToken = createSaslToken(authPacket.getToken(), sc,\n                            learnerLogin);\n                    send(dout, responseToken);\n                    authPacket = receive(din);\n                    qpStatus = QuorumAuth.Status\n                            .getStatus(authPacket.getStatus());\n                    break;\n                case ERROR:\n                    throw new SaslException(\n                            \"Authentication failed against server addr: \"\n                                    + sock.getRemoteSocketAddress());\n                default:\n                    LOG.warn(\"Unknown status:{}!\", qpStatus);\n                    throw new SaslException(\n                            \"Authentication failed against server addr: \"\n                                    + sock.getRemoteSocketAddress());\n                }\n            }\n\n            // Validate status code at the end of authentication exchange.\n            checkAuthStatus(sock, qpStatus);\n        } finally {\n            if (sc != null) {\n                try {\n                    sc.dispose();\n                } catch (SaslException e) {\n                    LOG.error(\"SaslClient dispose() failed\", e);\n                }\n            }\n        }\n        return;\n    }\n\n    private void checkAuthStatus(Socket sock, QuorumAuth.Status qpStatus)\n            throws SaslException {\n        if (qpStatus == QuorumAuth.Status.SUCCESS) {\n            LOG.info(\"Successfully completed the authentication using SASL. server addr: {}, status: {}\",\n                    sock.getRemoteSocketAddress(), qpStatus);\n        } else {\n            throw new SaslException(\"Authentication failed against server addr: \"\n                            + sock.getRemoteSocketAddress() + \", qpStatus: \"\n                            + qpStatus);\n        }\n    }\n\n    private QuorumAuthPacket receive(DataInputStream din) throws IOException {\n        QuorumAuthPacket authPacket = new QuorumAuthPacket();\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(din);\n        authPacket.deserialize(bia, QuorumAuth.QUORUM_AUTH_MESSAGE_TAG);\n        return authPacket;\n    }\n\n    private void send(DataOutputStream dout, byte[] response)\n            throws IOException {\n        QuorumAuthPacket authPacket;\n        BufferedOutputStream bufferedOutput = new BufferedOutputStream(dout);\n        BinaryOutputArchive boa = BinaryOutputArchive\n                .getArchive(bufferedOutput);\n        authPacket = QuorumAuth.createPacket(\n                QuorumAuth.Status.IN_PROGRESS, response);\n        boa.writeRecord(authPacket, QuorumAuth.QUORUM_AUTH_MESSAGE_TAG);\n        bufferedOutput.flush();\n    }\n\n    // TODO: need to consolidate the #createSaslToken() implementation between ZooKeeperSaslClient#createSaslToken().\n    private byte[] createSaslToken(final byte[] saslToken,\n            final SaslClient saslClient, final Login login)\n                    throws SaslException {\n        if (saslToken == null) {\n            throw new SaslException(\n                    \"Error in authenticating with a Zookeeper Quorum member: the quorum member's saslToken is null.\");\n        }\n        if (login.getSubject() != null) {\n            synchronized (login) {\n                try {\n                    final byte[] retval = Subject.doAs(login.getSubject(),\n                            new PrivilegedExceptionAction<byte[]>() {\n                                public byte[] run() throws SaslException {\n                                    LOG.debug(\"saslClient.evaluateChallenge(len=\"\n                                                    + saslToken.length + \")\");\n                                    return saslClient.evaluateChallenge(saslToken);\n                                }\n                            });\n                    return retval;\n                } catch (PrivilegedActionException e) {\n                    String error = \"An error: (\" + e\n                            + \") occurred when evaluating Zookeeper Quorum Member's \"\n                            + \" received SASL token.\";\n                    // Try to provide hints to use about what went wrong so they\n                    // can fix their configuration.\n                    // TODO: introspect about e: look for GSS information.\n                    final String UNKNOWN_SERVER_ERROR_TEXT = \"(Mechanism level: Server not found in Kerberos database (7) - UNKNOWN_SERVER)\";\n                    if (e.toString().indexOf(UNKNOWN_SERVER_ERROR_TEXT) > -1) {\n                        error += \" This may be caused by Java's being unable to resolve the Zookeeper Quorum Member's\"\n                                + \" hostname correctly. You may want to try to adding\"\n                                + \" '-Dsun.net.spi.nameservice.provider.1=dns,sun' to your server's JVMFLAGS environment.\";\n                    }\n                    LOG.error(error);\n                    throw new SaslException(error);\n                }\n            }\n        } else {\n            throw new SaslException(\n                    \"Cannot make SASL token without subject defined. \"\n                            + \"For diagnosis, please look for WARNs and ERRORs in your log related to the Login class.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthServer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.BufferedOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.Socket;\nimport java.util.Set;\n\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginException;\nimport javax.security.sasl.SaslException;\nimport javax.security.sasl.SaslServer;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.Login;\nimport org.apache.zookeeper.server.quorum.QuorumAuthPacket;\nimport org.apache.zookeeper.util.SecurityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SaslQuorumAuthServer implements QuorumAuthServer {\n\n    private static final Logger LOG = LoggerFactory\n            .getLogger(SaslQuorumAuthServer.class);\n\n    private final static int MAX_RETRIES = 5;\n    private final Login serverLogin;\n    private final boolean quorumRequireSasl;\n\n    public SaslQuorumAuthServer(boolean quorumRequireSasl, String loginContext, Set<String> authzHosts)\n            throws SaslException {\n        this.quorumRequireSasl = quorumRequireSasl;\n        try {\n            AppConfigurationEntry entries[] = Configuration.getConfiguration()\n                    .getAppConfigurationEntry(loginContext);\n            if (entries == null || entries.length == 0) {\n                throw new LoginException(\"SASL-authentication failed\"\n                        + \" because the specified JAAS configuration \"\n                        + \"section '\" + loginContext + \"' could not be found.\");\n            }\n            SaslQuorumServerCallbackHandler saslServerCallbackHandler = new SaslQuorumServerCallbackHandler(\n                    Configuration.getConfiguration(), loginContext, authzHosts);\n            serverLogin = new Login(loginContext, saslServerCallbackHandler);\n            serverLogin.startThreadIfNeeded();\n        } catch (Throwable e) {\n            throw new SaslException(\n                    \"Failed to initialize authentication mechanism using SASL\",\n                    e);\n        }\n    }\n\n    @Override\n    public void authenticate(Socket sock, DataInputStream din)\n            throws SaslException {\n        DataOutputStream dout = null;\n        SaslServer ss = null;\n        try {\n            if (!QuorumAuth.nextPacketIsAuth(din)) {\n                if (quorumRequireSasl) {\n                    throw new SaslException(\n                            \"Learner \" + sock.getRemoteSocketAddress()\n                                    + \" not trying to authenticate\"\n                                    + \" and authentication is required\");\n                } else {\n                    // let it through, we don't require auth\n                    return;\n                }\n            }\n\n            byte[] token = receive(din);\n            int tries = 0;\n            dout = new DataOutputStream(sock.getOutputStream());\n            byte[] challenge = null;\n            ss = SecurityUtils.createSaslServer(serverLogin.getSubject(),\n                    QuorumAuth.QUORUM_SERVER_PROTOCOL_NAME,\n                    QuorumAuth.QUORUM_SERVER_SASL_DIGEST, serverLogin.callbackHandler,\n                    LOG);\n            while (!ss.isComplete()) {\n                challenge = ss.evaluateResponse(token);\n                if (!ss.isComplete()) {\n                    // limited number of retries.\n                    if (++tries > MAX_RETRIES) {\n                        send(dout, challenge, QuorumAuth.Status.ERROR);\n                        LOG.warn(\"Failed to authenticate using SASL, server addr: {}, retries={} exceeded.\",\n                                sock.getRemoteSocketAddress(), tries);\n                        break;\n                    }\n                    send(dout, challenge, QuorumAuth.Status.IN_PROGRESS);\n                    token = receive(din);\n                }\n            }\n            // Authentication exchange has completed\n            if (ss.isComplete()) {\n                send(dout, challenge, QuorumAuth.Status.SUCCESS);\n                LOG.info(\"Successfully completed the authentication using SASL. learner addr: {}\",\n                        sock.getRemoteSocketAddress());\n            }\n        } catch (Exception e) {\n            try {\n                if (dout != null) {\n                    // send error message to the learner\n                    send(dout, new byte[0], QuorumAuth.Status.ERROR);\n                }\n            } catch (IOException ioe) {\n                LOG.warn(\"Exception while sending failed status\", ioe);\n            }\n            // If sasl is not required, when a server initializes a\n            // connection it will try to log in, but it will also\n            // accept connections that do not start with a sasl\n            // handshake.\n            if (quorumRequireSasl) {\n                LOG.error(\"Failed to authenticate using SASL\", e);\n                throw new SaslException(\n                        \"Failed to authenticate using SASL: \" + e.getMessage());\n            } else {\n                LOG.warn(\"Failed to authenticate using SASL\", e);\n                LOG.warn(\"Maintaining learner connection despite SASL authentication failure.\"\n                                + \" server addr: {}, {}: {}\",\n                        new Object[] { sock.getRemoteSocketAddress(),\n                                QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED,\n                                quorumRequireSasl });\n                return; // let it through, we don't require auth\n            }\n        } finally {\n            if (ss != null) {\n                try {\n                    ss.dispose();\n                } catch (SaslException e) {\n                    LOG.error(\"SaslServer dispose() failed\", e);\n                }\n            }\n        }\n        return;\n    }\n\n    private byte[] receive(DataInputStream din) throws IOException {\n        QuorumAuthPacket authPacket = new QuorumAuthPacket();\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(din);\n        authPacket.deserialize(bia, QuorumAuth.QUORUM_AUTH_MESSAGE_TAG);\n        return authPacket.getToken();\n    }\n\n    private void send(DataOutputStream dout, byte[] challenge,\n            QuorumAuth.Status s) throws IOException {\n        BufferedOutputStream bufferedOutput = new BufferedOutputStream(dout);\n        BinaryOutputArchive boa = BinaryOutputArchive\n                .getArchive(bufferedOutput);\n        QuorumAuthPacket authPacket;\n        if (challenge == null && s != QuorumAuth.Status.SUCCESS) {\n            authPacket = QuorumAuth.createPacket(\n                    QuorumAuth.Status.IN_PROGRESS, null);\n        } else {\n            authPacket = QuorumAuth.createPacket(s, challenge);\n        }\n\n        boa.writeRecord(authPacket, QuorumAuth.QUORUM_AUTH_MESSAGE_TAG);\n        bufferedOutput.flush();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/auth/SaslQuorumServerCallbackHandler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.security.auth.callback.Callback;\nimport javax.security.auth.callback.CallbackHandler;\nimport javax.security.auth.callback.NameCallback;\nimport javax.security.auth.callback.PasswordCallback;\nimport javax.security.auth.callback.UnsupportedCallbackException;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.sasl.AuthorizeCallback;\nimport javax.security.sasl.RealmCallback;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This is used by the SASL mechanisms to get further information to complete\n * the authentication. For example, a SASL mechanism might use this callback\n * handler to do verification operation. This is used by the QuorumServer to\n * perform the mutual quorum peer authentication.\n */\npublic class SaslQuorumServerCallbackHandler implements CallbackHandler {\n    private static final String USER_PREFIX = \"user_\";\n    private static final Logger LOG = LoggerFactory.getLogger(SaslQuorumServerCallbackHandler.class);\n\n    private String userName;\n    private final Map<String,String> credentials = new HashMap<String,String>();\n    private final Set<String> authzHosts;\n\n    public SaslQuorumServerCallbackHandler(Configuration configuration,\n            String serverSection, Set<String> authzHosts) throws IOException {\n        AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(serverSection);\n\n        if (configurationEntries == null) {\n            String errorMessage = \"Could not find a '\" + serverSection + \"' entry in this configuration: Server cannot start.\";\n            LOG.error(errorMessage);\n            throw new IOException(errorMessage);\n        }\n        credentials.clear();\n        for(AppConfigurationEntry entry: configurationEntries) {\n            Map<String,?> options = entry.getOptions();\n            // Populate DIGEST-MD5 user -> password map with JAAS configuration entries from the \"QuorumServer\" section.\n            // Usernames are distinguished from other options by prefixing the username with a \"user_\" prefix.\n            for(Map.Entry<String, ?> pair : options.entrySet()) {\n                String key = pair.getKey();\n                if (key.startsWith(USER_PREFIX)) {\n                    String userName = key.substring(USER_PREFIX.length());\n                    credentials.put(userName,(String)pair.getValue());\n                }\n            }\n        }\n\n        // authorized host lists\n        this.authzHosts = authzHosts;\n    }\n\n    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {\n        for (Callback callback : callbacks) {\n            if (callback instanceof NameCallback) {\n                handleNameCallback((NameCallback) callback);\n            } else if (callback instanceof PasswordCallback) {\n                handlePasswordCallback((PasswordCallback) callback);\n            } else if (callback instanceof RealmCallback) {\n                handleRealmCallback((RealmCallback) callback);\n            } else if (callback instanceof AuthorizeCallback) {\n                handleAuthorizeCallback((AuthorizeCallback) callback);\n            }\n        }\n    }\n\n    private void handleNameCallback(NameCallback nc) {\n        // check to see if this user is in the user password database.\n        if (credentials.get(nc.getDefaultName()) == null) {\n            LOG.warn(\"User '{}' not found in list of DIGEST-MD5 authenticateable users.\",\n                    nc.getDefaultName());\n            return;\n        }\n        nc.setName(nc.getDefaultName());\n        userName = nc.getDefaultName();\n    }\n\n    private void handlePasswordCallback(PasswordCallback pc) {\n        if (credentials.containsKey(userName) ) {\n            pc.setPassword(credentials.get(userName).toCharArray());\n        } else {\n            LOG.warn(\"No password found for user: {}\", userName);\n        }\n    }\n\n    private void handleRealmCallback(RealmCallback rc) {\n        LOG.debug(\"QuorumLearner supplied realm: {}\", rc.getDefaultText());\n        rc.setText(rc.getDefaultText());\n    }\n\n    private void handleAuthorizeCallback(AuthorizeCallback ac) {\n        String authenticationID = ac.getAuthenticationID();\n        String authorizationID = ac.getAuthorizationID();\n\n        boolean authzFlag = false;\n        // 1. Matches authenticationID and authorizationID\n        authzFlag = authenticationID.equals(authorizationID);\n\n        // 2. Verify whether the connecting host is present in authorized hosts.\n        // If not exists, then connecting peer is not authorized to join the\n        // ensemble and will reject it.\n        if (authzFlag) {\n            String[] components = authorizationID.split(\"[/@]\");\n            if (components.length == 3) {\n                authzFlag = authzHosts.contains(components[1]);\n            }\n            if (!authzFlag) {\n                LOG.error(\"SASL authorization completed, {} is not authorized to connect\",\n                        components[1]);\n            }\n        }\n\n        // Sets authorization flag\n        ac.setAuthorized(authzFlag);\n        if (ac.isAuthorized()) {\n            ac.setAuthorizedID(authorizationID);\n            LOG.info(\"Successfully authenticated learner: authenticationID={};  authorizationID={}.\",\n                    authenticationID, authorizationID);\n        }\n        LOG.debug(\"SASL authorization completed, authorized flag set to {}\", ac.isAuthorized());\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.flexible;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.HashMap;\nimport java.util.Properties;\nimport java.util.Map.Entry;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;\n\n\n/**\n * This class implements a validator for hierarchical quorums. With this\n * construction, zookeeper servers are split into disjoint groups, and \n * each server has a weight. We obtain a quorum if we get more than half\n * of the total weight of a group for a majority of groups.\n * \n * The configuration of quorums uses two parameters: group and weight. \n * Groups are sets of ZooKeeper servers, and we set a group by passing\n * a colon-separated list of server ids. It is also necessary to assign\n * weights to server. Here is an example of a configuration that creates\n * three groups and assigns a weight of 1 to each server:\n * \n *  group.1=1:2:3\n *  group.2=4:5:6\n *  group.3=7:8:9\n *  \n *  weight.1=1\n *  weight.2=1\n *  weight.3=1\n *  weight.4=1\n *  weight.5=1\n *  weight.6=1\n *  weight.7=1\n *  weight.8=1\n *  weight.9=1\n * \n * Note that it is still necessary to define peers using the server keyword.\n */\n\npublic class QuorumHierarchical implements QuorumVerifier {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumHierarchical.class);\n\n    HashMap<Long, Long> serverWeight;\n    HashMap<Long, Long> serverGroup;\n    HashMap<Long, Long> groupWeight;\n    \n    int numGroups;\n   \n    /**\n     * This contructor requires the quorum configuration\n     * to be declared in a separate file, and it takes the\n     * file as an input parameter.\n     */\n    public QuorumHierarchical(String filename)\n    throws ConfigException {\n        this.serverWeight = new HashMap<Long, Long>();\n        this.serverGroup = new HashMap<Long, Long>();\n        this.groupWeight = new HashMap<Long, Long>();\n        this.numGroups = 0;\n        \n        readConfigFile(filename);\n    }\n    \n    /**\n     * This constructor takes a set of properties. We use\n     * it in the unit test for this feature.\n     */\n    \n    public QuorumHierarchical(Properties qp)\n    throws ConfigException {\n        this.serverWeight = new HashMap<Long, Long>();\n        this.serverGroup = new HashMap<Long, Long>();\n        this.groupWeight = new HashMap<Long, Long>();\n        this.numGroups = 0;\n        \n        parse(qp);\n        \n        LOG.info(serverWeight.size() + \", \" + serverGroup.size() + \", \" + groupWeight.size());\n    }\n    \n   /**\n    *  This contructor takes the two hash maps needed to enable \n    *  validating quorums. We use it with QuorumPeerConfig. That is,\n    *  we declare weights and groups in the server configuration\n    *  file along with the other parameters.\n    * @param numGroups\n    * @param serverWeight\n    * @param serverGroup\n    */\n    public QuorumHierarchical(int numGroups,\n            HashMap<Long, Long> serverWeight,\n            HashMap<Long, Long> serverGroup)\n    {\n        this.serverWeight = serverWeight;\n        this.serverGroup = serverGroup;\n        this.groupWeight = new HashMap<Long, Long>();\n        \n        this.numGroups = numGroups;\n        computeGroupWeight();   \n    }\n    \n    \n    /**\n     * Returns the weight of a server.\n     * \n     * @param id\n     */\n    public long getWeight(long id){\n        return serverWeight.get(id);\n    }\n    \n    /**\n     * Reads a configration file. Called from the constructor\n     * that takes a file as an input.\n     */\n    private void readConfigFile(String filename)\n    throws ConfigException{\n        File configFile = new File(filename);\n\n        LOG.info(\"Reading configuration from: \" + configFile);\n\n        try {\n            if (!configFile.exists()) {\n                throw new IllegalArgumentException(configFile.toString()\n                        + \" file is missing\");\n            }\n    \n            Properties cfg = new Properties();\n            FileInputStream in = new FileInputStream(configFile);\n            try {\n                cfg.load(in);\n            } finally {\n                in.close();\n            }\n    \n            parse(cfg);\n        } catch (IOException e) {\n            throw new ConfigException(\"Error processing \" + filename, e);\n        } catch (IllegalArgumentException e) {\n            throw new ConfigException(\"Error processing \" + filename, e);\n        }\n        \n    }\n    \n    \n    /**\n     * Parse properties if configuration given in a separate file.\n     */\n    private void parse(Properties quorumProp){\n        for (Entry<Object, Object> entry : quorumProp.entrySet()) {\n            String key = entry.getKey().toString();\n            String value = entry.getValue().toString(); \n            if (key.startsWith(\"group\")) {\n                int dot = key.indexOf('.');\n                long gid = Long.parseLong(key.substring(dot + 1));\n                \n                numGroups++;\n                \n                String parts[] = value.split(\":\");\n                for(String s : parts){\n                    long sid = Long.parseLong(s);\n                    serverGroup.put(sid, gid);\n                }\n                    \n                \n            } else if(key.startsWith(\"weight\")) {\n                int dot = key.indexOf('.');\n                long sid = Long.parseLong(key.substring(dot + 1));\n                serverWeight.put(sid, Long.parseLong(value));\n            }\n        }\n        \n        computeGroupWeight();\n    }\n    \n    /**\n     * This method pre-computes the weights of groups to speed up processing\n     * when validating a given set. We compute the weights of groups in \n     * different places, so we have a separate method.\n     */\n    private void computeGroupWeight(){\n        for(Entry<Long, Long> entry : serverGroup.entrySet()){\n            Long sid = entry.getKey();\n            Long gid = entry.getValue();\n            if(!groupWeight.containsKey(gid))\n                groupWeight.put(gid, serverWeight.get(sid));\n            else {\n                long totalWeight = serverWeight.get(sid) + groupWeight.get(gid);\n                groupWeight.put(gid, totalWeight);\n            } \n        }    \n        \n        /*\n         * Do not consider groups with weight zero\n         */\n        for(long weight: groupWeight.values()){\n            LOG.debug(\"Group weight: \" + weight);\n            if(weight == ((long) 0)){\n                numGroups--;\n                LOG.debug(\"One zero-weight group: \" + 1 + \", \" + numGroups);\n            }\n        }\n    }\n    \n    /**\n     * Verifies if a given set is a quorum.\n     */\n    public boolean containsQuorum(HashSet<Long> set){\n        HashMap<Long, Long> expansion = new HashMap<Long, Long>();\n        \n        /*\n         * Adds up weights per group\n         */\n        if(set.size() == 0) return false;\n        else LOG.debug(\"Set size: \" + set.size());\n        \n        for(long sid : set){\n            Long gid = serverGroup.get(sid);\n            if(!expansion.containsKey(gid))\n                expansion.put(gid, serverWeight.get(sid));\n            else {\n                long totalWeight = serverWeight.get(sid) + expansion.get(gid);\n                expansion.put(gid, totalWeight);\n            }\n        }\n  \n        /*\n         * Check if all groups have majority\n         */\n        int majGroupCounter = 0;\n        for(Entry<Long, Long> entry : expansion.entrySet()) {\n            Long gid = entry.getKey();\n            LOG.debug(\"Group info: \" + entry.getValue() + \", \" + gid + \", \" + groupWeight.get(gid));\n            if(entry.getValue() > (groupWeight.get(gid) / 2) )\n                majGroupCounter++;\n        }\n        \n        LOG.debug(\"Majority group counter: \" + majGroupCounter + \", \" + numGroups); \n        if((majGroupCounter > (numGroups / 2))){\n            LOG.debug(\"Positive set size: \" + set.size());\n            return true;\n        }\n        else {\n            LOG.debug(\"Negative set size: \" + set.size());\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumMaj.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.flexible;\n\nimport java.util.HashSet;\n\n//import org.apache.zookeeper.server.quorum.QuorumCnxManager;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class implements a validator for majority quorums. The \n * implementation is straightforward.\n *\n */\npublic class QuorumMaj implements QuorumVerifier {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumMaj.class);\n    \n    int half;\n    \n    /**\n     * Defines a majority to avoid computing it every time.\n     * \n     * @param n number of servers\n     */\n    public QuorumMaj(int n){\n        this.half = n/2;\n    }\n    \n    /**\n     * Returns weight of 1 by default.\n     * \n     * @param id \n     */\n    public long getWeight(long id){\n        return (long) 1;\n    }\n    \n    /**\n     * Verifies if a set is a majority.\n     */\n    public boolean containsQuorum(HashSet<Long> set){\n        return (set.size() > half);\n    }\n    \n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumVerifier.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.flexible;\n\nimport java.util.HashSet;\n\n/**\n * All quorum validators have to implement a method called\n * containsQuorum, which verifies if a HashSet of server \n * identifiers constitutes a quorum.\n *\n */\n\npublic interface QuorumVerifier {\n    long getWeight(long id);\n    boolean containsQuorum(HashSet<Long> set);\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/upgrade/DataNodeV1.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.upgrade;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\n\nimport org.apache.jute.Index;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.data.StatPersistedV1;\n\n/**\n * This class contains the data for a node in the data tree.\n * <p>\n * A data node contains a reference to its parent, a byte array as its data, an\n * array of ACLs, a stat object, and a set of its children's paths.\n * \n */\npublic class DataNodeV1 implements Record {\n    DataNodeV1() {\n        // default rather than public constructor\n    }\n\n    DataNodeV1(DataNodeV1 parent, byte data[], List<ACL> acl, StatPersistedV1 stat) {\n        this.parent = parent;\n        this.data = data;\n        this.acl = acl;\n        this.stat = stat;\n        this.children = new HashSet<String>();\n    }\n    \n\n    /**\n     * convenience method for creating DataNode\n     * fully\n     * @param children\n     */\n    public void setChildren(HashSet<String> children) {\n        this.children = children;\n    }\n    \n    /**\n     * convenience methods to get the children\n     * @return the children of this datanode\n     */\n    public HashSet<String> getChildren() {\n        return this.children;\n    }\n    \n    DataNodeV1 parent;\n\n    byte data[];\n\n    public List<ACL> acl;\n\n    public StatPersistedV1 stat;\n\n    HashSet<String> children = new HashSet<String>();\n\n    public void copyStat(Stat to) {\n        to.setAversion(stat.getAversion());\n        to.setCtime(stat.getCtime());\n        to.setCversion(stat.getCversion());\n        to.setCzxid(stat.getCzxid());\n        to.setMtime(stat.getMtime());\n        to.setMzxid(stat.getMzxid());\n        to.setVersion(stat.getVersion());\n        to.setEphemeralOwner(stat.getEphemeralOwner());\n        to.setDataLength(data.length);\n        to.setNumChildren(children.size());\n    }\n\n    public void deserialize(InputArchive archive, String tag)\n            throws IOException {\n        archive.startRecord(\"node\");\n        data = archive.readBuffer(\"data\");\n        Index i = archive.startVector(\"acl\");\n        if (i != null) {\n            acl = new ArrayList<ACL>();\n            while (!i.done()) {\n                ACL a = new ACL();\n                a.deserialize(archive, \"aclEntry\");\n                acl.add(a);\n                i.incr();\n            }\n        }\n        archive.endVector(\"acl\");\n        stat = new StatPersistedV1();\n        stat.deserialize(archive, \"stat\");\n        archive.endRecord(\"node\");\n    }\n\n    synchronized public void serialize(OutputArchive archive, String tag)\n            throws IOException {\n        archive.startRecord(this, \"node\");\n        archive.writeBuffer(data, \"data\");\n        archive.startVector(acl, \"acl\");\n        if (acl != null) {\n            for (ACL a : acl) {\n                a.serialize(archive, \"aclEntry\");\n            }\n        }\n        archive.endVector(acl, \"acl\");\n        stat.serialize(archive, \"stat\");\n        archive.endRecord(this, \"node\");\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/upgrade/DataTreeV1.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.upgrade;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.Watcher.Event;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.data.StatPersistedV1;\nimport org.apache.zookeeper.server.WatchManager;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This class maintains the tree data structure. It doesn't have any networking\n * or client connection code in it so that it can be tested in a stand alone\n * way.\n * <p>\n * The tree maintains two parallel data structures: a hashtable that maps from\n * full paths to DataNodes and a tree of DataNodes. All accesses to a path is\n * through the hashtable. The tree is traversed only when serializing to disk.\n */\npublic class DataTreeV1 {\n    private static final Logger LOG = LoggerFactory.getLogger(DataTreeV1.class);\n\n    /**\n     * This hashtable provides a fast lookup to the datanodes. The tree is the\n     * source of truth and is where all the locking occurs\n     */\n    private ConcurrentHashMap<String, DataNodeV1> nodes = new ConcurrentHashMap<String, DataNodeV1>();\n\n    private WatchManager dataWatches = new WatchManager();\n\n    private WatchManager childWatches = new WatchManager();\n\n    /**\n     * This hashtable lists the paths of the ephemeral nodes of a session.\n     */\n    private Map<Long, HashSet<String>> ephemerals = new ConcurrentHashMap<Long, HashSet<String>>();\n\n    /**\n     * return the ephemerals for this tree\n     * @return the ephemerals for this tree\n     */\n    public Map<Long, HashSet<String>>  getEphemeralsMap() {\n        return this.ephemerals;\n    }\n    \n    public void setEphemeralsMap(Map<Long, HashSet<String>> ephemerals) {\n        this.ephemerals = ephemerals;\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    public HashSet<String> getEphemerals(long sessionId) {\n        HashSet<String> retv = ephemerals.get(sessionId);\n        if (retv == null) {\n            return new HashSet<String>();\n        }\n        HashSet<String> cloned = null;\n        synchronized(retv) {\n            cloned =  (HashSet<String>) retv.clone();\n        }\n        return cloned;\n    }\n    \n    public Collection<Long> getSessions() {\n        return ephemerals.keySet();\n    }\n\n    public DataNodeV1 getNode(String path) {\n        return nodes.get(path);\n    }\n\n    /**\n     * This is a pointer to the root of the DataTree. It is the source of truth,\n     * but we usually use the nodes hashmap to find nodes in the tree.\n     */\n    private DataNodeV1 root = new DataNodeV1(null, new byte[0], null, new StatPersistedV1());\n\n    public DataTreeV1() {\n        /* Rather than fight it, let root have an alias */\n        nodes.put(\"\", root);\n        nodes.put(\"/\", root);\n    }\n\n    static public void copyStatPersisted(StatPersistedV1 from, StatPersistedV1 to) {\n        to.setAversion(from.getAversion());\n        to.setCtime(from.getCtime());\n        to.setCversion(from.getCversion());\n        to.setCzxid(from.getCzxid());\n        to.setMtime(from.getMtime());\n        to.setMzxid(from.getMzxid());\n        to.setVersion(from.getVersion());\n        to.setEphemeralOwner(from.getEphemeralOwner());\n    }\n\n    static public void copyStat(Stat from, Stat to) {\n        to.setAversion(from.getAversion());\n        to.setCtime(from.getCtime());\n        to.setCversion(from.getCversion());\n        to.setCzxid(from.getCzxid());\n        to.setMtime(from.getMtime());\n        to.setMzxid(from.getMzxid());\n        to.setVersion(from.getVersion());\n        to.setEphemeralOwner(from.getEphemeralOwner());\n        to.setDataLength(from.getDataLength());\n        to.setNumChildren(from.getNumChildren());\n    }\n\n\n    // public void remooveInterest(String path, Watcher nw) {\n    // DataNode n = nodes.get(path);\n    // if (n == null) {\n    // synchronized (nonExistentWatches) {\n    // HashSet<Watcher> list = nonExistentWatches.get(path);\n    // if (list != null) {\n    // list.remove(nw);\n    // }\n    // }\n    // }\n    // synchronized (n) {\n    // n.dataWatchers.remove(nw);\n    // n.childWatchers.remove(nw);\n    // }\n    // }\n\n    /**\n     * @param path\n     * @param data\n     * @param acl\n     * @param ephemeralOwner\n     *                the session id that owns this node. -1 indicates this is\n     *                not an ephemeral node.\n     * @param zxid\n     * @param time\n     * @return the patch of the created node\n     * @throws KeeperException\n     */\n    public String createNode(String path, byte data[], List<ACL> acl,\n            long ephemeralOwner, long zxid, long time) \n            throws KeeperException.NoNodeException, KeeperException.NodeExistsException {\n        int lastSlash = path.lastIndexOf('/');\n        String parentName = path.substring(0, lastSlash);\n        String childName = path.substring(lastSlash + 1);\n        StatPersistedV1 stat = new StatPersistedV1();\n        stat.setCtime(time);\n        stat.setMtime(time);\n        stat.setCzxid(zxid);\n        stat.setMzxid(zxid);\n        stat.setVersion(0);\n        stat.setAversion(0);\n        stat.setEphemeralOwner(ephemeralOwner);\n        DataNodeV1 parent = nodes.get(parentName);\n        if (parent == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (parent) {\n            if (parent.children.contains(childName)) {\n                throw new KeeperException.NodeExistsException();\n            }\n            int cver = parent.stat.getCversion();\n            cver++;\n            parent.stat.setCversion(cver);\n            DataNodeV1 child = new DataNodeV1(parent, data, acl, stat);\n            parent.children.add(childName);\n            nodes.put(path, child);\n            if (ephemeralOwner != 0) {\n                HashSet<String> list = ephemerals.get(ephemeralOwner);\n                if (list == null) {\n                    list = new HashSet<String>();\n                    ephemerals.put(ephemeralOwner, list);\n                }\n                synchronized(list) {\n                    list.add(path);\n                }\n            }\n        }\n        dataWatches.triggerWatch(path, Event.EventType.NodeCreated);\n        childWatches.triggerWatch(parentName.equals(\"\")?\"/\":parentName, Event.EventType.NodeChildrenChanged);\n        return path;\n    }\n\n    public void deleteNode(String path) throws KeeperException.NoNodeException {\n        int lastSlash = path.lastIndexOf('/');\n        String parentName = path.substring(0, lastSlash);\n        String childName = path.substring(lastSlash + 1);\n        DataNodeV1 node = nodes.get(path);\n        if (node == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        nodes.remove(path);\n        DataNodeV1 parent = nodes.get(parentName);\n        if (parent == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (parent) {\n            parent.children.remove(childName);\n            parent.stat.setCversion(parent.stat.getCversion() + 1);\n            long eowner = node.stat.getEphemeralOwner();\n            if (eowner != 0) {\n                HashSet<String> nodes = ephemerals.get(eowner);\n                if (nodes != null) {\n                    synchronized(nodes) {\n                        nodes.remove(path);\n                    }\n                }\n            }\n            node.parent = null;\n        }\n        Set<Watcher> processed =\n        dataWatches.triggerWatch(path, EventType.NodeDeleted);\n        childWatches.triggerWatch(path, EventType.NodeDeleted, processed);\n        childWatches.triggerWatch(parentName.equals(\"\")?\"/\":parentName, EventType.NodeChildrenChanged);\n    }\n\n    public Stat setData(String path, byte data[], int version, long zxid,\n            long time) throws KeeperException.NoNodeException {\n        Stat s = new Stat();\n        DataNodeV1 n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.data = data;\n            n.stat.setMtime(time);\n            n.stat.setMzxid(zxid);\n            n.stat.setVersion(version);\n            n.copyStat(s);\n        }\n        dataWatches.triggerWatch(path, EventType.NodeDataChanged);\n        return s;\n    }\n\n    public byte[] getData(String path, Stat stat, Watcher watcher) throws KeeperException.NoNodeException {\n        DataNodeV1 n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            if (watcher != null) {\n                dataWatches.addWatch(path, watcher);\n            }\n            return n.data;\n        }\n    }\n\n    public Stat statNode(String path, Watcher watcher) throws KeeperException.NoNodeException {\n        Stat stat = new Stat();\n        DataNodeV1 n = nodes.get(path);\n        if (watcher != null) {\n            dataWatches.addWatch(path, watcher);\n        }\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            return stat;\n        }\n    }\n\n    public ArrayList<String> getChildren(String path, Stat stat, Watcher watcher) throws KeeperException.NoNodeException {\n        DataNodeV1 n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            ArrayList<String> children = new ArrayList<String>();\n            children.addAll(n.children);\n            if (watcher != null) {\n                childWatches.addWatch(path, watcher);\n            }\n            return children;\n        }\n    }\n\n    public Stat setACL(String path, List<ACL> acl, int version) throws KeeperException.NoNodeException {\n        Stat stat = new Stat();\n        DataNodeV1 n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.stat.setAversion(version);\n            n.acl = acl;\n            n.copyStat(stat);\n            return stat;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List<ACL> getACL(String path, Stat stat) throws KeeperException.NoNodeException {\n        DataNodeV1 n = nodes.get(path);\n        if (n == null) {\n            throw new KeeperException.NoNodeException();\n        }\n        synchronized (n) {\n            n.copyStat(stat);\n            return new ArrayList<ACL>(n.acl);\n        }\n    }\n\n    static public class ProcessTxnResult {\n        public long clientId;\n\n        public int cxid;\n\n        public long zxid;\n\n        /**\n         * Equality is defined as the clientId and the cxid being the same. This\n         * allows us to use hash tables to track completion of transactions.\n         *\n         * @see java.lang.Object#equals(java.lang.Object)\n         */\n        @Override\n        public boolean equals(Object o) {\n            if (o instanceof ProcessTxnResult) {\n                ProcessTxnResult other = (ProcessTxnResult) o;\n                return other.clientId == clientId && other.cxid == cxid;\n            }\n            return false;\n        }\n\n        /**\n         * See equals() to find the rational for how this hashcode is generated.\n         *\n         * @see ProcessTxnResult#equals(Object)\n         * @see java.lang.Object#hashCode()\n         */\n        @Override\n        public int hashCode() {\n            return (int) ((clientId ^ cxid) % Integer.MAX_VALUE);\n        }\n\n    }\n\n    public volatile long lastProcessedZxid = 0;\n\n    @SuppressWarnings(\"unchecked\")\n    public ProcessTxnResult processTxn(TxnHeader header, Record txn) {\n        ProcessTxnResult rc = new ProcessTxnResult();\n\n        String debug = \"\";\n        try {\n            rc.clientId = header.getClientId();\n            rc.cxid = header.getCxid();\n            rc.zxid = header.getZxid();\n            if (rc.zxid > lastProcessedZxid) {\n                lastProcessedZxid = rc.zxid;\n            }\n            switch (header.getType()) {\n            case OpCode.create:\n                CreateTxn createTxn = (CreateTxn) txn;\n                debug = \"Create transaction for \" + createTxn.getPath();\n                createNode(createTxn.getPath(), createTxn.getData(), createTxn\n                        .getAcl(), createTxn.getEphemeral() ? header\n                        .getClientId() : 0, header.getZxid(), header.getTime());\n                break;\n            case OpCode.delete:\n                DeleteTxn deleteTxn = (DeleteTxn) txn;\n                debug = \"Delete transaction for \" + deleteTxn.getPath();\n                deleteNode(deleteTxn.getPath());\n                break;\n            case OpCode.setData:\n                SetDataTxn setDataTxn = (SetDataTxn) txn;\n                debug = \"Set data for  transaction for \" + setDataTxn.getPath();\n                break;\n            case OpCode.setACL:\n                SetACLTxn setACLTxn = (SetACLTxn) txn;\n                debug = \"Set ACL for  transaction for \" + setACLTxn.getPath();\n                break;\n            case OpCode.closeSession:\n                killSession(header.getClientId());\n                break;\n            case OpCode.error:\n                ErrorTxn errTxn = (ErrorTxn) txn;\n                break;\n            }\n        } catch (KeeperException e) {\n            // These are expected errors since we take a lazy snapshot\n            if (initialized\n                    || (e.code() != Code.NONODE \n                            && e.code() != Code.NODEEXISTS)) {\n                LOG.warn(\"Failed:\" + debug, e);\n            }\n        }\n        return rc;\n    }\n\n    void killSession(long session) {\n        // the list is already removed from the ephemerals\n        // so we do not have to worry about synchronyzing on\n        // the list. This is only called from FinalRequestProcessor\n        // so there is no need for synchornization. The list is not\n        // changed here. Only create and delete change the list which\n        // are again called from FinalRequestProcessor in sequence.\n        HashSet<String> list = ephemerals.remove(session);\n        if (list != null) {\n            for (String path : list) {\n                try {\n                    deleteNode(path);\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Deleting ephemeral node \" + path\n                                + \" for session 0x\"\n                                + Long.toHexString(session));\n                    }\n                } catch (NoNodeException e) {\n                    LOG.warn(\"Ignoring NoNodeException for path \" + path\n                            + \" while removing ephemeral for dead session 0x\"\n                            + Long.toHexString(session));\n                }\n            }\n        }\n    }\n\n    /**\n     * this method uses a stringbuilder to create a new\n     * path for children. This is faster than string\n     * appends ( str1 + str2).\n     * @param oa OutputArchive to write to.\n     * @param path a string builder.\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    void serializeNode(OutputArchive oa, StringBuilder path)\n            throws IOException, InterruptedException {\n        String pathString = path.toString();\n        DataNodeV1 node = getNode(pathString);\n        if (node == null) {\n            return;\n        }\n        String children[] = null;\n        synchronized (node) {\n            scount++;\n            oa.writeString(pathString, \"path\");\n            oa.writeRecord(node, \"node\");\n            children = node.children.toArray(new String[node.children.size()]);\n        }\n        path.append('/');\n        int off = path.length();\n        if (children != null) {\n            for (String child : children) {\n                //since this is single buffer being resused\n                // we need\n                // to truncate the previous bytes of string.\n                path.delete(off, Integer.MAX_VALUE);\n                path.append(child);\n                serializeNode(oa, path);\n            }\n        }\n    }\n\n    int scount;\n\n    public boolean initialized = false;\n\n    public void serialize(OutputArchive oa, String tag) throws IOException,\n            InterruptedException {\n        scount = 0;\n        serializeNode(oa, new StringBuilder(\"\"));\n        // / marks end of stream\n        // we need to check if clear had been called in between the snapshot.\n        if (root != null) {\n            oa.writeString(\"/\", \"path\");\n        }\n    }\n\n    public void deserialize(InputArchive ia, String tag) throws IOException {\n        nodes.clear();\n        String path = ia.readString(\"path\");\n        while (!path.equals(\"/\")) {\n            DataNodeV1 node = new DataNodeV1();\n            ia.readRecord(node, \"node\");\n            nodes.put(path, node);\n            int lastSlash = path.lastIndexOf('/');\n            if (lastSlash == -1) {\n                root = node;\n            } else {\n                String parentPath = path.substring(0, lastSlash);\n                node.parent = nodes.get(parentPath);\n                node.parent.children.add(path.substring(lastSlash + 1));\n                long eowner = node.stat.getEphemeralOwner();\n                if (eowner != 0) {\n                    HashSet<String> list = ephemerals.get(eowner);\n                    if (list == null) {\n                        list = new HashSet<String>();\n                        ephemerals.put(eowner, list);\n                    }\n                    list.add(path);\n                }\n            }\n            path = ia.readString(\"path\");\n        }\n        nodes.put(\"/\", root);\n    }\n\n    public String dumpEphemerals() {\n        Set<Long> keys = ephemerals.keySet();\n        StringBuilder sb = new StringBuilder(\"Sessions with Ephemerals (\"\n                + keys.size() + \"):\\n\");\n        for (long k : keys) {\n            sb.append(\"0x\" + Long.toHexString(k));\n            sb.append(\":\\n\");\n            HashSet<String> tmp = ephemerals.get(k);\n            synchronized(tmp) {\n                for (String path : tmp) {\n                    sb.append(\"\\t\" + path + \"\\n\");\n                }\n            }\n        }\n        return sb.toString();\n    }\n\n    public void removeCnxn(Watcher watcher) {\n        dataWatches.removeWatcher(watcher);\n        childWatches.removeWatcher(watcher);\n    }\n\n    public void clear() {\n        root = null;\n        nodes.clear();\n        ephemerals.clear();\n        // dataWatches = null;\n        // childWatches = null;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/upgrade/UpgradeMain.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.upgrade;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.yetus.audience.InterfaceAudience;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\n\n/**\n * This class upgrades the older database \n * to a new database for the zookeeper \n * servers.\n * The way to run it is \n * java -class path zookeeper.jar Upgrade dataDir snapShotDir\n * or using zookeeper scripts with zkServer -upgrade dataDir snapShotDir \n * it creates a backup in the dataDir/.bkup and snapShotDir/.bkup which \n * can be retrieved back to the snapShotDir and dataDir \n */\n@InterfaceAudience.Public\npublic class UpgradeMain {\n    File snapShotDir;\n    File dataDir;\n    File bkupsnapShotDir;\n    File bkupdataDir;\n    File currentdataDir;\n    File currentsnapShotDir;\n    \n    private static final Logger LOG = LoggerFactory.getLogger(UpgradeMain.class);\n    private static final String USAGE = \"Usage: UpgradeMain dataDir snapShotDir\";\n    private static final int LASTVERSION = 1;\n    private static final int CURRENTVERSION = FileTxnSnapLog.VERSION;\n    private static final String dirName = FileTxnSnapLog.version;\n    private static final String manual = \"Please take manual steps to \" +\n    \t\t\"sanitize your database.\\n Please read the upgrade manual\";\n    \n     /**\n     * upgrade class that takes the two file \n     * directories.\n     * @param dataDir the directory that contains the \n     * transaction logs\n     * @param snapShotDir the directory that contains \n     * the snapshots \n     */\n    public UpgradeMain(File dataDir, File snapShotDir) {\n        this.snapShotDir = snapShotDir; \n        this.dataDir = dataDir;\n        this.bkupdataDir = new File(dataDir, dirName + LASTVERSION);\n        this.bkupsnapShotDir = new File(snapShotDir, dirName + LASTVERSION );\n        this.currentsnapShotDir = new File(snapShotDir, dirName + CURRENTVERSION);\n        this.currentdataDir = new File(dataDir, dirName + CURRENTVERSION);\n    }\n \n    /**\n     * create all the bkup directories and the current\n     * database directories\n     * @throws IOException\n     */\n    private void createAllDirs() throws IOException {\n        String error = \"backup directory \" + bkupdataDir + \" already exists\";\n        LOG.info(\"Creating previous version data dir \" + bkupdataDir);\n        if (!bkupdataDir.mkdirs()) {\n            LOG.error(error);\n            LOG.error(manual);\n            throw new IOException(error);\n        }\n        LOG.info(\"Creating previous version snapshot dir \" + bkupdataDir);\n        if (!bkupsnapShotDir.mkdirs() && !bkupsnapShotDir.exists()) {\n            LOG.error(error);\n            LOG.error(manual);\n            throw new IOException(error);\n        }\n        error = \"current directory \" + currentdataDir + \" already exists\";\n        LOG.info(\"Creating current data dir \" + currentdataDir);\n        if (!currentdataDir.mkdirs()) {\n            LOG.error(error);\n            LOG.error(manual);\n            throw new IOException(error);\n        }\n        LOG.info(\"Creating current snapshot dir \" + currentdataDir);\n        if (!currentsnapShotDir.mkdirs() && !currentsnapShotDir.exists()) {\n            LOG.error(error);\n            LOG.error(manual);\n            throw new IOException(error);\n        }\n    }\n    \n    /**\n     * copy files from srcdir to dstdir that have the string \n     * filter in the srcdir filenames\n     * @param srcDir the source directory\n     * @param dstDir the destination directory\n     * @param filter the filter of filenames that \n     * need to be copied.\n     * @throws IOException\n     */\n    void copyFiles(File srcDir, File dstDir, String filter) throws IOException {\n        File[] list = srcDir.listFiles();\n        if (list != null) {\n            for (File file: list) {\n                String name = file.getName();\n                if (name.startsWith(filter)) {\n                    // we need to copy this file\n                    File dest = new File(dstDir, name);\n                    LOG.info(\"Renaming \" + file + \" to \" + dest);\n                    if (!file.renameTo(dest)) {\n                        throw new IOException(\"Unable to rename \"\n                                + file + \" to \" +  dest);\n                    }\n                }\n            }\n        }\n    }\n    \n    /**\n     * run the upgrade\n     * @throws IOException\n     */\n    public void runUpgrade() throws IOException {\n        if (!dataDir.exists()) {\n            throw new IOException(dataDir + \" does not exist\");\n        }\n        if (!snapShotDir.exists()) {\n            throw new IOException(snapShotDir + \" does not exist\");\n        }\n        // create the bkup directorya\n        createAllDirs();\n        //copy all the files for backup\n        try {\n            copyFiles(dataDir, bkupdataDir, \"log\");\n            copyFiles(snapShotDir, bkupsnapShotDir, \"snapshot\");\n        } catch(IOException io) {\n            LOG.error(\"Failed in backing up.\");\n            throw io;\n        }\n\n        //evrything is backed up\n        // read old database and create \n        // an old snapshot\n        UpgradeSnapShotV1 upgrade = new UpgradeSnapShotV1(bkupdataDir, \n                bkupsnapShotDir);\n        LOG.info(\"Creating new data tree\");\n        DataTree dt = upgrade.getNewDataTree();\n        FileTxnSnapLog filesnapLog = new FileTxnSnapLog(dataDir, \n                snapShotDir);\n        LOG.info(\"snapshotting the new datatree\");\n        filesnapLog.save(dt, upgrade.getSessionWithTimeOuts());\n        //done saving.\n        LOG.info(\"Upgrade is complete\");\n    }\n    \n    public static void main(String[] argv) {\n        if (argv.length < 2) {\n            LOG.error(USAGE);\n            System.exit(-1);\n        }\n        try {\n            UpgradeMain upgrade = new UpgradeMain(new File(argv[0]), new File(argv[1]));\n            upgrade.runUpgrade();\n        } catch(Throwable th) {\n            LOG.error(\"Upgrade Error: Please read the \" +\n            \t\t\"docs for manual failure recovery \", th);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/upgrade/UpgradeSnapShot.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.upgrade;\n\nimport java.io.IOException;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.zookeeper.server.DataTree;\n\n/**\n * interface for snapshot conversion.\n *\n */\npublic interface UpgradeSnapShot {\n    public DataTree getNewDataTree() throws IOException;\n    public ConcurrentHashMap<Long, Integer> getSessionWithTimeOuts();\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/upgrade/UpgradeSnapShotV1.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.upgrade;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.Record;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.data.StatPersisted;\nimport org.apache.zookeeper.data.StatPersistedV1;\nimport org.apache.zookeeper.server.DataNode;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.apache.zookeeper.server.util.SerializeUtils;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\n\n/**\n * This class gets the old snapshot \n * and the old dataDir and creates \n * an brand new snapshot that is \n * then converted to the new snapshot\n * for upgrading.           \n */\npublic class UpgradeSnapShotV1 implements UpgradeSnapShot {\n    private static final Logger LOG = LoggerFactory.getLogger(UpgradeSnapShotV1.class);\n    \n    ConcurrentHashMap<Long, Integer> sessionsWithTimeouts = \n        new ConcurrentHashMap<Long, Integer>();\n    File dataDir;\n    File snapShotDir;\n    DataTreeV1 oldDataTree;\n   \n    /**\n     * upgrade from version 1 to version 2\n     * @param dataDir\n     * @param snapShotDir\n     */\n    public UpgradeSnapShotV1(File dataDir, File snapShotDir) {\n        this.dataDir = dataDir;\n        this.snapShotDir = snapShotDir;\n        oldDataTree = new DataTreeV1();\n    }\n    \n    /**\n     * deseriluize from an inputarchive\n     * @param oldTree the tree to be created\n     * @param ia the input archive to be read from\n     * @param sessions the sessions to be created\n     * @throws IOException \n     */\n    private void deserializeSnapshot(DataTreeV1 oldTree, InputArchive ia,\n            Map<Long, Integer> sessions) throws IOException {\n        int count = ia.readInt(\"count\");\n        while (count > 0) {\n            long id = ia.readLong(\"id\");\n            int to = ia.readInt(\"timeout\");\n            sessions.put(id, to);\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                        \"loadData --- session in archive: \" + id\n                        + \" with timeout: \" + to);\n            }\n            count--;\n        }\n        oldTree.deserialize(ia, \"tree\");\n    }\n    \n    /**\n     * play the log from this logstream into the datatree\n     * @param logStream\n     * @return\n     * @throws IOException\n     */\n    public long playLog(InputArchive logStream) throws IOException {\n        long highestZxid = 0;\n        try {\n            while (true) {\n                byte[] bytes = logStream.readBuffer(\"txnEntry\");\n                if (bytes.length == 0) {\n                    // Since we preallocate, we define EOF to be an\n                    // empty transaction\n                    throw new EOFException();\n                }\n                TxnHeader hdr = new TxnHeader();\n                Record txn = SerializeUtils.deserializeTxn(bytes, hdr);\n                if (logStream.readByte(\"EOR\") != 'B') {\n                    LOG.warn(\"Last transaction was partial.\");\n                    throw new EOFException(\"Last transaction was partial.\");\n                }\n                if (hdr.getZxid() <= highestZxid && highestZxid != 0) {\n                    LOG.error(highestZxid + \"(higestZxid) >= \"\n                            + hdr.getZxid() + \"(next log) for type \"\n                            + hdr.getType());\n                } else {\n                    highestZxid = hdr.getZxid();\n                }\n                switch (hdr.getType()) {\n                case OpCode.createSession:\n                    sessionsWithTimeouts.put(hdr.getClientId(),\n                            ((CreateSessionTxn) txn).getTimeOut());\n                    if (LOG.isTraceEnabled()) {\n                        ZooTrace.logTraceMessage(LOG,\n                                                 ZooTrace.SESSION_TRACE_MASK,\n                                \"playLog --- create session in log: 0x\"\n                                        + Long.toHexString(hdr.getClientId())\n                                        + \" with timeout: \"\n                                        + ((CreateSessionTxn) txn).getTimeOut());\n                    }\n                    // give dataTree a chance to sync its lastProcessedZxid\n                    oldDataTree.processTxn(hdr, txn);\n                    break;\n                case OpCode.closeSession:\n                    sessionsWithTimeouts.remove(hdr.getClientId());\n                    if (LOG.isTraceEnabled()) {\n                        ZooTrace.logTraceMessage(LOG,\n                                ZooTrace.SESSION_TRACE_MASK,\n                                \"playLog --- close session in log: 0x\"\n                                        + Long.toHexString(hdr.getClientId()));\n                    }\n                    oldDataTree.processTxn(hdr, txn);\n                    break;\n                default:\n                    oldDataTree.processTxn(hdr, txn);\n                }\n                Request r = new Request(null, 0, hdr.getCxid(), hdr.getType(),\n                        null, null);\n                r.txn = txn;\n                r.hdr = hdr;\n                r.zxid = hdr.getZxid();\n            }\n        } catch (EOFException e) {\n            // expected in some cases - see comments in try block\n        }\n        return highestZxid;\n    }\n\n   \n    \n    /**\n     * apply the log files to the datatree\n     * @param oldTree the datatreee to apply the logs to\n     * @param logFiles the logs to be applied\n     * @throws IOException\n     */\n    private long processLogFiles(DataTreeV1 oldTree, \n            File[] logFiles) throws IOException {\n        long zxid = 0;\n        for (File f: logFiles) { \n            LOG.info(\"Processing log file: \" + f);\n            InputStream logIs = \n                new BufferedInputStream(new FileInputStream(f));\n            zxid = playLog(BinaryInputArchive.getArchive(logIs));\n            logIs.close();\n        }\n        return zxid;\n    }\n    \n    /**\n     * create the old snapshot database\n     * apply logs to it and create the final\n     * database\n     * @throws IOException\n     */\n    private void loadThisSnapShot() throws IOException {  \n        // pick the most recent snapshot\n        File snapshot = findMostRecentSnapshot();\n        if (snapshot == null) {\n            throw new IOException(\"Invalid snapshots \" +\n            \t\t\"or not snapshots in \" + snapShotDir);\n        }\n        InputStream inputstream = new BufferedInputStream(\n                new FileInputStream(snapshot));\n        InputArchive ia = BinaryInputArchive.getArchive(inputstream);\n        deserializeSnapshot(oldDataTree, ia, sessionsWithTimeouts);\n        //ok done with the snapshot \n        // now apply the logs\n        long snapshotZxid = oldDataTree.lastProcessedZxid;\n        File[] files = FileTxnLog.getLogFiles(\n                dataDir.listFiles(), snapshotZxid);\n        long zxid = processLogFiles(oldDataTree, files);\n        //check for this zxid to be sane\n        if (zxid != oldDataTree.lastProcessedZxid) {\n            LOG.error(\"Zxids not equal \" + \" log zxid \" +\n                    zxid + \" datatree processed \" + oldDataTree.lastProcessedZxid);\n        }\n    }\n    \n    /**\n     * find the most recent snapshot \n     * in the snapshot directory\n     * @return\n     * @throws IOException\n     */\n    private File findMostRecentSnapshot() throws IOException {\n        List<File> files = Util.sortDataDir(snapShotDir.listFiles(),\n                \"snapshot\", false);\n        for (File f: files) {\n            try {\n                if (Util.isValidSnapshot(f))\n                    return f;\n            } catch(IOException e) {\n                LOG.info(\"Invalid snapshot \" + f, e);\n            }\n        }\n        return null;\n    }\n    \n    /**\n     * convert the old stat to new stat\n     * @param oldStat the old stat\n     * @return the new stat\n     */\n    private StatPersisted convertStat(StatPersistedV1 oldStat) {\n        StatPersisted stat = new StatPersisted();\n        stat.setAversion(oldStat.getAversion());\n        stat.setCtime(oldStat.getCtime());\n        stat.setCversion(oldStat.getCversion());\n        stat.setCzxid(oldStat.getCzxid());\n        stat.setEphemeralOwner(oldStat.getEphemeralOwner());\n        stat.setMtime(oldStat.getMtime());\n        stat.setMzxid(oldStat.getMzxid());\n        stat.setVersion(oldStat.getVersion());\n        return stat;\n    }\n    \n    /**\n     * convert a given old datanode to new datanode\n     * @param dt the new datatree\n     * @param parent the parent of the datanode to be constructed\n     * @param oldDataNode the old datanode \n     * @return the new datanode\n     */\n    private DataNode convertDataNode(DataTree dt, DataNode parent, \n            DataNodeV1 oldDataNode) {\n        StatPersisted stat = convertStat(oldDataNode.stat);\n        DataNode dataNode =  new DataNode(parent, oldDataNode.data,\n                dt.getACL(oldDataNode), stat);\n        dataNode.setChildren(oldDataNode.children);\n        return dataNode;\n    }\n    \n    /**\n     * recurse through the old datatree and construct the \n     * new data tree\n     * @param dataTree the new datatree to be constructed\n     * @param path the path to start with\n     */\n    private void recurseThroughDataTree(DataTree dataTree, String path) {\n        if (path == null)\n            return;\n        DataNodeV1 oldDataNode = oldDataTree.getNode(path);\n        HashSet<String> children = oldDataNode.children;\n        DataNode parent = null;\n        if (\"\".equals(path)) {\n            parent = null;\n        }\n        else {\n            int lastSlash = path.lastIndexOf('/');\n            String parentPath = path.substring(0, lastSlash);\n            parent = dataTree.getNode(parentPath);\n        }\n        DataNode thisDatNode = convertDataNode(dataTree, parent,\n                                    oldDataNode);\n        dataTree.addDataNode(path, thisDatNode);\n        if (children == null || children.size() == 0) {\n            return;\n        }\n        else {\n            for (String child: children) {\n                recurseThroughDataTree(dataTree, path + \"/\" +child);\n            }\n        }\n    }   \n    \n    private DataTree convertThisSnapShot() throws IOException {\n        // create a datatree \n        DataTree dataTree = new DataTree();\n        DataNodeV1 oldDataNode = oldDataTree.getNode(\"\");\n        if (oldDataNode == null) {\n            //should never happen\n            LOG.error(\"Upgrading from an empty snapshot.\");\n        }\n        \n        recurseThroughDataTree(dataTree, \"\");\n        dataTree.lastProcessedZxid = oldDataTree.lastProcessedZxid;\n        return dataTree;\n    }\n    \n    public DataTree getNewDataTree() throws IOException {\n        loadThisSnapShot();\n        DataTree dt = convertThisSnapShot();\n        return dt;\n    }\n    \n    public ConcurrentHashMap<Long, Integer> getSessionWithTimeOuts() {\n        return this.sessionsWithTimeouts;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/util/KerberosUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.util;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\npublic class KerberosUtil {\n\n  public static String getDefaultRealm() \n      throws ClassNotFoundException, NoSuchMethodException, \n      IllegalArgumentException, IllegalAccessException, \n      InvocationTargetException {\n    Object kerbConf;\n    Class<?> classRef;\n    Method getInstanceMethod;\n    Method getDefaultRealmMethod;\n    if (System.getProperty(\"java.vendor\").contains(\"IBM\")) {\n      classRef = Class.forName(\"com.ibm.security.krb5.internal.Config\");\n    } else {\n      classRef = Class.forName(\"sun.security.krb5.Config\");\n    }\n    getInstanceMethod = classRef.getMethod(\"getInstance\");\n    kerbConf = getInstanceMethod.invoke(classRef);\n    getDefaultRealmMethod = classRef.getDeclaredMethod(\"getDefaultRealm\");\n    return (String)getDefaultRealmMethod.invoke(kerbConf, new Object[0]);\n  }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/util/OSMXBean.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.util;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.OperatingSystemMXBean;\nimport java.lang.management.RuntimeMXBean;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.lang.reflect.Method;\n\n/**\n * This class is a wrapper for the implementation of\n * com.sun.management.UnixOperatingSystemMXBean\n * It will decide to use the sun api or its own implementation\n * depending on the runtime (vendor) used.\n */\npublic class OSMXBean\n{\n    static final Logger LOG = LoggerFactory.getLogger(OSMXBean.class);\n\n    private OperatingSystemMXBean osMbean;\n\n    private static final boolean ibmvendor =\n        System.getProperty(\"java.vendor\").contains(\"IBM\");\n    private static final boolean windows = \n        System.getProperty(\"os.name\").startsWith(\"Windows\");\n    private static final boolean linux =\n        System.getProperty(\"os.name\").startsWith(\"Linux\");\n\n    /**\n     * Constructor. Get the running Operating System instance\n     */\n    public OSMXBean () {\n        this.osMbean = ManagementFactory.getOperatingSystemMXBean();\n    }\n \n    /**\n     * Check if the OS is unix. If using the IBM java runtime, this\n     * will only work for linux.\n     * \n     * @return whether this is unix or not.\n     */\n    public boolean getUnix() {\n        if (windows) {\n            return false;\n        }\n        return (ibmvendor ? linux : true);\n    }\n\n    /**\n     * Load the implementation of UnixOperatingSystemMXBean for sun jvm\n     * and runs the desired method. \n     * @param mBeanMethodName : method to run from the interface UnixOperatingSystemMXBean\n     * @return the method result\n     */\n    private Long getOSUnixMXBeanMethod (String mBeanMethodName)\n    {\n        Object unixos;\n        Class<?> classRef;\n        Method mBeanMethod;\n\n        try {\n            classRef = Class.forName(\"com.sun.management.UnixOperatingSystemMXBean\");\n            if (classRef.isInstance(osMbean)) {\n                mBeanMethod = classRef.getDeclaredMethod(mBeanMethodName);\n                unixos = classRef.cast(osMbean);\n                return (Long)mBeanMethod.invoke(unixos);\n            }\n        } catch(Exception e) {\n            LOG.warn(\"Not able to load class or method for com.sun.managment.UnixOperatingSystemMXBean.\", e);\n        }\n        return null;\n    }\n\n    /**\n     * Get the number of opened filed descriptor for the runtime jvm.\n     * If sun java, it will use the com.sun.management interfaces.\n     * Otherwise, this methods implements it (linux only).  \n     * @return number of open file descriptors for the jvm\n     */\n    public long getOpenFileDescriptorCount() \n    {\n        Long ofdc;\n    \n        if (!ibmvendor) {\n            ofdc = getOSUnixMXBeanMethod(\"getOpenFileDescriptorCount\");\n            return (ofdc != null ? ofdc.longValue () : -1);\n        }\n        \n        try {\n            //need to get the PID number of the process first\n            RuntimeMXBean rtmbean = ManagementFactory.getRuntimeMXBean();\n            String rtname = rtmbean.getName();\n            String[] pidhost = rtname.split(\"@\");\n\n            //using linux bash commands to retrieve info\n            Process p = Runtime.getRuntime().exec(\n                    new String[] { \"bash\", \"-c\",\n                    \"ls /proc/\" + pidhost[0] + \"/fdinfo | wc -l\" });\n            InputStream in = p.getInputStream();\n            BufferedReader output = new BufferedReader(\n                    new InputStreamReader(in));\n\n            try {\n                String openFileDesCount;\n                if ((openFileDesCount = output.readLine()) != null) {\n                    return Long.parseLong(openFileDesCount);\n                }\n            } finally {\n                if (output != null) {\n                    output.close();\n                }\n            }\n        } catch (IOException ie) {\n            LOG.warn(\"Not able to get the number of open file descriptors\", ie);\n        }\n        return -1;\n    }\n\n    /**\n     * Get the number of the maximum file descriptors the system can use.\n     * If sun java, it will use the com.sun.management interfaces.\n     * Otherwise, this methods implements it (linux only).  \n     * @return max number of file descriptors the operating system can use.\n     */\n    public long getMaxFileDescriptorCount()\n    {\n        Long mfdc;\n\n        if (!ibmvendor) {\n            mfdc = getOSUnixMXBeanMethod(\"getMaxFileDescriptorCount\");\n            return (mfdc != null ? mfdc.longValue () : -1);\n        }\n        \n        try {\n            //using linux bash commands to retrieve info\n            Process p = Runtime.getRuntime().exec(\n                    new String[] { \"bash\", \"-c\", \"ulimit -n\" });\n            InputStream in = p.getInputStream();\n            BufferedReader output = new BufferedReader(\n                    new InputStreamReader(in));\n\n            try {\n                String maxFileDesCount;\n                if ((maxFileDesCount = output.readLine()) != null) {\n                    return Long.parseLong(maxFileDesCount);\n                }\n            } finally {\n                if (output != null) {\n                    output.close();\n                }\n            }\n        } catch (IOException ie) {\n            LOG.warn(\"Not able to get the max number of file descriptors\", ie);\n        }\n        return -1;\n    }  \n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/util/Profiler.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Profiler {\n    private static final Logger LOG = LoggerFactory.getLogger(Profiler.class);\n\n    public interface Operation<T> {\n        public T execute() throws Exception;\n    }\n\n    public static <T> T profile(Operation<T> op, long timeout, String message)\n            throws Exception {\n        long start = System.currentTimeMillis();\n        T res = op.execute();\n        long end = System.currentTimeMillis();\n        if (end - start > timeout) {\n            LOG.info(\"Elapsed \"+(end - start) + \" ms: \" + message);\n        }\n        return res;\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/util/SerializeUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.CreateTxnV0;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetACLTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.apache.zookeeper.txn.MultiTxn;\n\npublic class SerializeUtils {\n    private static final Logger LOG = LoggerFactory.getLogger(SerializeUtils.class);\n    \n    public static Record deserializeTxn(byte txnBytes[], TxnHeader hdr)\n            throws IOException {\n        final ByteArrayInputStream bais = new ByteArrayInputStream(txnBytes);\n        InputArchive ia = BinaryInputArchive.getArchive(bais);\n\n        hdr.deserialize(ia, \"hdr\");\n        bais.mark(bais.available());\n        Record txn = null;\n        switch (hdr.getType()) {\n        case OpCode.createSession:\n            // This isn't really an error txn; it just has the same\n            // format. The error represents the timeout\n            txn = new CreateSessionTxn();\n            break;\n        case OpCode.closeSession:\n            return null;\n        case OpCode.create:\n            txn = new CreateTxn();\n            break;\n        case OpCode.delete:\n            txn = new DeleteTxn();\n            break;\n        case OpCode.setData:\n            txn = new SetDataTxn();\n            break;\n        case OpCode.setACL:\n            txn = new SetACLTxn();\n            break;\n        case OpCode.error:\n            txn = new ErrorTxn();\n            break;\n        case OpCode.multi:\n            txn = new MultiTxn();\n            break;\n        default:\n            throw new IOException(\"Unsupported Txn with type=%d\" + hdr.getType());\n        }\n        if (txn != null) {\n            try {\n                txn.deserialize(ia, \"txn\");\n            } catch(EOFException e) {\n                // perhaps this is a V0 Create\n                if (hdr.getType() == OpCode.create) {\n                    CreateTxn create = (CreateTxn)txn;\n                    bais.reset();\n                    CreateTxnV0 createv0 = new CreateTxnV0();\n                    createv0.deserialize(ia, \"txn\");\n                    // cool now make it V1. a -1 parentCVersion will\n                    // trigger fixup processing in processTxn\n                    create.setPath(createv0.getPath());\n                    create.setData(createv0.getData());\n                    create.setAcl(createv0.getAcl());\n                    create.setEphemeral(createv0.getEphemeral());\n                    create.setParentCVersion(-1);\n                } else {\n                    throw e;\n                }\n            }\n        }\n        return txn;\n    }\n\n    public static void deserializeSnapshot(DataTree dt,InputArchive ia,\n            Map<Long, Integer> sessions) throws IOException {\n        int count = ia.readInt(\"count\");\n        while (count > 0) {\n            long id = ia.readLong(\"id\");\n            int to = ia.readInt(\"timeout\");\n            sessions.put(id, to);\n            if (LOG.isTraceEnabled()) {\n                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                        \"loadData --- session in archive: \" + id\n                        + \" with timeout: \" + to);\n            }\n            count--;\n        }\n        dt.deserialize(ia, \"tree\");\n    }\n\n    public static void serializeSnapshot(DataTree dt,OutputArchive oa,\n            Map<Long, Integer> sessions) throws IOException {\n        HashMap<Long, Integer> sessSnap = new HashMap<Long, Integer>(sessions);\n        oa.writeInt(sessSnap.size(), \"count\");\n        for (Entry<Long, Integer> entry : sessSnap.entrySet()) {\n            oa.writeLong(entry.getKey().longValue(), \"id\");\n            oa.writeInt(entry.getValue().intValue(), \"timeout\");\n        }\n        dt.serialize(oa, \"tree\");\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/server/util/ZxidUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.util;\n\npublic class ZxidUtils {\n\tstatic public long getEpochFromZxid(long zxid) {\n\t\treturn zxid >> 32L;\n\t}\n\tstatic public long getCounterFromZxid(long zxid) {\n\t\treturn zxid & 0xffffffffL;\n\t}\n\tstatic public long makeZxid(long epoch, long counter) {\n\t\treturn (epoch << 32L) | (counter & 0xffffffffL);\n\t}\n\tstatic public String zxidToString(long zxid) {\n\t\treturn Long.toHexString(zxid);\n\t}\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/util/SecurityUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.util;\n\nimport java.security.Principal;\nimport java.security.PrivilegedActionException;\nimport java.security.PrivilegedExceptionAction;\n\nimport javax.security.auth.Subject;\nimport javax.security.auth.callback.CallbackHandler;\nimport javax.security.sasl.Sasl;\nimport javax.security.sasl.SaslClient;\nimport javax.security.sasl.SaslException;\nimport javax.security.sasl.SaslServer;\n\nimport org.apache.zookeeper.SaslClientCallbackHandler;\nimport org.apache.zookeeper.server.auth.KerberosName;\nimport org.ietf.jgss.GSSContext;\nimport org.ietf.jgss.GSSCredential;\nimport org.ietf.jgss.GSSException;\nimport org.ietf.jgss.GSSManager;\nimport org.ietf.jgss.GSSName;\nimport org.ietf.jgss.Oid;\nimport org.slf4j.Logger;\n\npublic final class SecurityUtils {\n\n    public static final String QUORUM_HOSTNAME_PATTERN = \"_HOST\";\n\n    /**\n     * Create an instance of a SaslClient. It will return null if there is an exception.\n     *\n     * @param subject subject\n     * @param servicePrincipal principal\n     * @param protocol name of the protocol for which the authentication is being performed\n     * @param serverName name of the server to authenticate to\n     * @param LOG logger\n     * @param entity can be either zookeeper client or quorum learner\n     *\n     * @return saslclient object\n     * @throws SaslException\n     */\n    public static SaslClient createSaslClient(final Subject subject,\n            final String servicePrincipal, final String protocol,\n            final String serverName, final Logger LOG, final String entity) throws SaslException {\n        SaslClient saslClient;\n        // Use subject.getPrincipals().isEmpty() as an indication of which SASL\n        // mechanism to use: if empty, use DIGEST-MD5; otherwise, use GSSAPI.\n        if (subject.getPrincipals().isEmpty()) {\n            // no principals: must not be GSSAPI: use DIGEST-MD5 mechanism\n            // instead.\n            LOG.info(\"{} will use DIGEST-MD5 as SASL mechanism.\", entity);\n            String[] mechs = { \"DIGEST-MD5\" };\n            String username = (String) (subject.getPublicCredentials()\n                    .toArray()[0]);\n            String password = (String) (subject.getPrivateCredentials()\n                    .toArray()[0]);\n            // 'domain' parameter is hard-wired between the server and client\n            saslClient = Sasl.createSaslClient(mechs, username, protocol,\n                    serverName, null, new SaslClientCallbackHandler(password, entity));\n            return saslClient;\n        } else { // GSSAPI.\n            final Object[] principals = subject.getPrincipals().toArray();\n            // determine client principal from subject.\n            final Principal clientPrincipal = (Principal) principals[0];\n            boolean usingNativeJgss = Boolean\n                    .getBoolean(\"sun.security.jgss.native\");\n            if (usingNativeJgss) {\n                // http://docs.oracle.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html\n                // \"\"\"\n                // In addition, when performing operations as a particular\n                // Subject, e.g. Subject.doAs(...) or\n                // Subject.doAsPrivileged(...),\n                // the to-be-used GSSCredential should be added to Subject's\n                // private credential set. Otherwise, the GSS operations will\n                // fail since no credential is found.\n                // \"\"\"\n                try {\n                    GSSManager manager = GSSManager.getInstance();\n                    Oid krb5Mechanism = new Oid(\"1.2.840.113554.1.2.2\");\n                    GSSCredential cred = manager.createCredential(null,\n                            GSSContext.DEFAULT_LIFETIME, krb5Mechanism,\n                            GSSCredential.INITIATE_ONLY);\n                    subject.getPrivateCredentials().add(cred);\n                    LOG.debug(\"Added private credential to {} principal name: '{}'\",\n                            entity, clientPrincipal);\n                } catch (GSSException ex) {\n                    LOG.warn(\"Cannot add private credential to subject; \"\n                                    + \"authentication at the server may fail\", ex);\n                }\n            }\n            final KerberosName clientKerberosName = new KerberosName(\n                    clientPrincipal.getName());\n            // assume that server and client are in the same realm (by default;\n            // unless the system property\n            // \"zookeeper.server.realm\" is set).\n            String serverRealm = System.getProperty(\"zookeeper.server.realm\",\n                    clientKerberosName.getRealm());\n            KerberosName serviceKerberosName = new KerberosName(\n                    servicePrincipal + \"@\" + serverRealm);\n            final String serviceName = serviceKerberosName.getServiceName();\n            final String serviceHostname = serviceKerberosName.getHostName();\n            final String clientPrincipalName = clientKerberosName.toString();\n            try {\n                saslClient = Subject.doAs(subject,\n                        new PrivilegedExceptionAction<SaslClient>() {\n                            public SaslClient run() throws SaslException {\n                                LOG.info(\"{} will use GSSAPI as SASL mechanism.\", entity);\n                                String[] mechs = { \"GSSAPI\" };\n                                LOG.debug(\"creating sasl client: {}={};service={};serviceHostname={}\",\n                                        new Object[] { entity, clientPrincipalName, serviceName, serviceHostname });\n                                SaslClient saslClient = Sasl.createSaslClient(\n                                        mechs, clientPrincipalName, serviceName,\n                                        serviceHostname, null,\n                                        new SaslClientCallbackHandler(null, entity));\n                                return saslClient;\n                            }\n                        });\n                return saslClient;\n            } catch (Exception e) {\n                LOG.error(\"Exception while trying to create SASL client\", e);\n                return null;\n            }\n        }\n    }\n\n    /**\n     * Create an instance of a SaslServer. It will return null if there is an exception.\n     *\n     * @param subject subject\n     * @param protocol protocol\n     * @param serverName server name\n     * @param callbackHandler login callback handler\n     * @param LOG logger\n     * @return sasl server object\n     */\n    public static SaslServer createSaslServer(final Subject subject,\n            final String protocol, final String serverName,\n            final CallbackHandler callbackHandler, final Logger LOG) {\n        if (subject != null) {\n            // server is using a JAAS-authenticated subject: determine service\n            // principal name and hostname from zk server's subject.\n            if (subject.getPrincipals().size() > 0) {\n                try {\n                    final Object[] principals = subject.getPrincipals()\n                            .toArray();\n                    final Principal servicePrincipal = (Principal) principals[0];\n\n                    // e.g. servicePrincipalNameAndHostname :=\n                    // \"zookeeper/myhost.foo.com@FOO.COM\"\n                    final String servicePrincipalNameAndHostname = servicePrincipal\n                            .getName();\n\n                    int indexOf = servicePrincipalNameAndHostname.indexOf(\"/\");\n\n                    // e.g. servicePrincipalName := \"zookeeper\"\n                    final String servicePrincipalName = servicePrincipalNameAndHostname\n                            .substring(0, indexOf);\n\n                    // e.g. serviceHostnameAndKerbDomain :=\n                    // \"myhost.foo.com@FOO.COM\"\n                    final String serviceHostnameAndKerbDomain = servicePrincipalNameAndHostname\n                            .substring(indexOf + 1,\n                                    servicePrincipalNameAndHostname.length());\n\n                    indexOf = serviceHostnameAndKerbDomain.indexOf(\"@\");\n                    // e.g. serviceHostname := \"myhost.foo.com\"\n                    final String serviceHostname = serviceHostnameAndKerbDomain\n                            .substring(0, indexOf);\n\n                    // TODO: should depend on zoo.cfg specified mechs, but if\n                    // subject is non-null, it can be assumed to be GSSAPI.\n                    final String mech = \"GSSAPI\";\n\n                    LOG.debug(\"serviceHostname is '\" + serviceHostname + \"'\");\n                    LOG.debug(\"servicePrincipalName is '\" + servicePrincipalName\n                            + \"'\");\n                    LOG.debug(\"SASL mechanism(mech) is '\" + mech + \"'\");\n\n                    boolean usingNativeJgss = Boolean\n                            .getBoolean(\"sun.security.jgss.native\");\n                    if (usingNativeJgss) {\n                        // http://docs.oracle.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html\n                        // \"\"\"\n                        // In addition, when performing operations as a\n                        // particular\n                        // Subject, e.g. Subject.doAs(...) or\n                        // Subject.doAsPrivileged(...), the to-be-used\n                        // GSSCredential should be added to Subject's\n                        // private credential set. Otherwise, the GSS operations\n                        // will fail since no credential is found.\n                        // \"\"\"\n                        try {\n                            GSSManager manager = GSSManager.getInstance();\n                            Oid krb5Mechanism = new Oid(\"1.2.840.113554.1.2.2\");\n                            GSSName gssName = manager.createName(\n                                    servicePrincipalName + \"@\"\n                                            + serviceHostname,\n                                    GSSName.NT_HOSTBASED_SERVICE);\n                            GSSCredential cred = manager.createCredential(\n                                    gssName, GSSContext.DEFAULT_LIFETIME,\n                                    krb5Mechanism, GSSCredential.ACCEPT_ONLY);\n                            subject.getPrivateCredentials().add(cred);\n                            LOG.debug(\"Added private credential to service principal name: '{}',\"\n                                            + \" GSSCredential name: {}\", servicePrincipalName, cred.getName());\n                        } catch (GSSException ex) {\n                            LOG.warn(\"Cannot add private credential to subject; \"\n                                            + \"clients authentication may fail\", ex);\n                        }\n                    }\n                    try {\n                        return Subject.doAs(subject,\n                                new PrivilegedExceptionAction<SaslServer>() {\n                                    public SaslServer run() {\n                                        try {\n                                            SaslServer saslServer;\n                                            saslServer = Sasl.createSaslServer(\n                                                    mech, servicePrincipalName,\n                                                    serviceHostname, null,\n                                                    callbackHandler);\n                                            return saslServer;\n                                        } catch (SaslException e) {\n                                            LOG.error(\"Zookeeper Server failed to create a SaslServer to interact with a client during session initiation: \", e);\n                                            return null;\n                                        }\n                                    }\n                                });\n                    } catch (PrivilegedActionException e) {\n                        // TODO: exit server at this point(?)\n                        LOG.error(\"Zookeeper Quorum member experienced a PrivilegedActionException exception while creating a SaslServer using a JAAS principal context:\", e);\n                    }\n                } catch (IndexOutOfBoundsException e) {\n                    LOG.error(\"server principal name/hostname determination error: \", e);\n                }\n            } else {\n                // JAAS non-GSSAPI authentication: assuming and supporting only\n                // DIGEST-MD5 mechanism for now.\n                // TODO: use 'authMech=' value in zoo.cfg.\n                try {\n                    SaslServer saslServer = Sasl.createSaslServer(\"DIGEST-MD5\",\n                            protocol, serverName, null, callbackHandler);\n                    return saslServer;\n                } catch (SaslException e) {\n                    LOG.error(\"Zookeeper Quorum member failed to create a SaslServer to interact with a client during session initiation\", e);\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Convert Kerberos principal name pattern to valid Kerberos principal name.\n     * If the principal name contains hostname pattern \"_HOST\" then it replaces\n     * with the given hostname, which should be fully-qualified domain name.\n     *\n     * @param principalConfig\n     *            the Kerberos principal name conf value to convert\n     * @param hostname\n     *            the fully-qualified domain name used for substitution\n     * @return converted Kerberos principal name\n     */\n    public static String getServerPrincipal(String principalConfig,\n            String hostname) {\n        String[] components = getComponents(principalConfig);\n        if (components == null || components.length != 2\n                || !components[1].equals(QUORUM_HOSTNAME_PATTERN)) {\n            return principalConfig;\n        } else {\n            return replacePattern(components, hostname);\n        }\n    }\n\n    private static String[] getComponents(String principalConfig) {\n        if (principalConfig == null)\n            return null;\n        return principalConfig.split(\"[/]\");\n    }\n\n    private static String replacePattern(String[] components, String hostname) {\n        return components[0] + \"/\" + hostname.toLowerCase();\n    }\n}\n"
  },
  {
    "path": "src/java/main/org/apache/zookeeper/version/util/VerGen.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.version.util;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class VerGen {\n    private static final String PACKAGE_NAME = \"org.apache.zookeeper.version\";\n    private static final String TYPE_NAME = \"Info\";\n\n    static void printUsage() {\n        System.out.print(\"Usage:\\tjava  -cp <classpath> org.apache.zookeeper.\"\n                + \"version.util.VerGen maj.min.micro[-qualifier] rev buildDate\");\n        System.exit(1);\n    }\n\n    public static void generateFile(File outputDir, Version version, String rev, String buildDate) throws IOException\n    {\n        String path = PACKAGE_NAME.replaceAll(\"\\\\.\", \"/\");\n        File pkgdir = new File(outputDir, path);\n        if (!pkgdir.exists()) {\n            // create the pkg directory\n            boolean ret = pkgdir.mkdirs();\n            if (!ret) {\n                System.out.println(\"Cannnot create directory: \" + path);\n                System.exit(1);\n            }\n        } else if (!pkgdir.isDirectory()) {\n            // not a directory\n            System.out.println(path + \" is not a directory.\");\n            System.exit(1);\n        }\n        File file = new File(pkgdir, TYPE_NAME + \".java\");\n        FileWriter w = null;\n        try {\n            w = new FileWriter(file);\n            w.write(\"// Do not edit!\\n// File generated by org.apache.zookeeper\"\n                    + \".version.util.VerGen.\\n\");\n            w.write(\"/**\\n\");\n            w.write(\"* Licensed to the Apache Software Foundation (ASF) under one\\n\");\n            w.write(\"* or more contributor license agreements.  See the NOTICE file\\n\");\n            w.write(\"* distributed with this work for additional information\\n\");\n            w.write(\"* regarding copyright ownership.  The ASF licenses this file\\n\");\n            w.write(\"* to you under the Apache License, Version 2.0 (the\\n\");\n            w.write(\"* \\\"License\\\"); you may not use this file except in compliance\\n\");\n            w.write(\"* with the License.  You may obtain a copy of the License at\\n\");\n            w.write(\"*\\n\");\n            w.write(\"*     http://www.apache.org/licenses/LICENSE-2.0\\n\");\n            w.write(\"*\\n\");\n            w.write(\"* Unless required by applicable law or agreed to in writing, software\\n\");\n            w.write(\"* distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\");\n            w.write(\"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\");\n            w.write(\"* See the License for the specific language governing permissions and\\n\");\n            w.write(\"* limitations under the License.\\n\");\n            w.write(\"*/\\n\");\n            w.write(\"\\n\");\n            w.write(\"package \" + PACKAGE_NAME + \";\\n\\n\");\n            w.write(\"public interface \" + TYPE_NAME + \" {\\n\");\n            w.write(\"    int MAJOR=\" + version.maj + \";\\n\");\n            w.write(\"    int MINOR=\" + version.min + \";\\n\");\n            w.write(\"    int MICRO=\" + version.micro + \";\\n\");\n            w.write(\"    String QUALIFIER=\"\n                    + (version.qualifier == null ? null :\n                        \"\\\"\" + version.qualifier + \"\\\"\")\n                    + \";\\n\");\n            if (rev.equals(\"-1\")) {\n                System.out.println(\"Unknown REVISION number, using \" + rev);\n            }\n            w.write(\"    int REVISION=-1; //TODO: remove as related to SVN VCS\\n\");\n            w.write(\"    String REVISION_HASH=\\\"\" + rev + \"\\\";\\n\");\n            w.write(\"    String BUILD_DATE=\\\"\" + buildDate\n                    + \"\\\";\\n\");\n            w.write(\"}\\n\");\n        } finally {\n            if (w != null) {\n                try {\n                    w.close();\n                } catch (IOException e) {\n                    System.out.println(\"Unable to close file writer\"\n                            + e.getMessage());\n                }\n            }\n        }\n    }\n\n    public static class Version {\n        public int maj;\n        public int min;\n        public int micro;\n        public String qualifier;\n    }\n\n    public static Version parseVersionString(String input) {\n        Version result = new Version();\n\n        Pattern p = Pattern.compile(\"^(\\\\d+)\\\\.(\\\\d+)\\\\.(\\\\d+)((\\\\.\\\\d+)*)(-(.+))?$\");\n        Matcher m = p.matcher(input);\n\n        if (!m.matches()) {\n            return null;\n        }\n        result.maj = Integer.parseInt(m.group(1));\n        result.min = Integer.parseInt(m.group(2));\n        result.micro = Integer.parseInt(m.group(3));\n        if (m.groupCount() == 7) {\n            result.qualifier = m.group(7);\n        } else {\n            result.qualifier = null;\n        }\n        return result;\n    }\n\n    /**\n     * Emits a org.apache.zookeeper.version.Info interface file with version and\n     * revision information constants set to the values passed in as command\n     * line parameters. The file is created in the current directory. <br>\n     * Usage: java org.apache.zookeeper.version.util.VerGen maj.min.micro[-qualifier]\n     * rev buildDate\n     *\n     * @param args\n     *            <ul>\n     *            <li>maj - major version number\n     *            <li>min - minor version number\n     *            <li>micro - minor minor version number\n     *            <li>qualifier - optional qualifier (dash followed by qualifier text)\n     *            <li>rev - current Git revision number\n     *            <li>buildDate - date the build\n     *            </ul>\n     */\n    public static void main(String[] args) {\n        if (args.length != 3)\n            printUsage();\n        try {\n            Version version = parseVersionString(args[0]);\n            if (version == null) {\n                System.err.println(\n                        \"Invalid version number format, must be \\\"x.y.z(-.*)?\\\"\");\n                System.exit(1);\n            }\n            String rev = args[1];\n            if (rev == null || rev.trim().isEmpty()) {\n                rev = \"-1\";\n            } else {\n                rev = rev.trim();\n            }\n            generateFile(new File(\".\"), version, rev, args[2]);\n        } catch (NumberFormatException e) {\n            System.err.println(\n                    \"All version-related parameters must be valid integers!\");\n            throw e;\n        } catch (IOException e) {\n            System.out.println(\"Unable to generate version.Info file: \"\n                    + e.getMessage());\n            System.exit(1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/main/overview.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<html>\n<head>\n   <title>ZooKeeper</title>\n</head>\n<body>\nZooKeeper is a service for coordinating processes of distributed applications.\n</body>\n</html>\n"
  },
  {
    "path": "src/java/systest/README.txt",
    "content": "To run the system test we need to create processing containers that we can\nspawn tasks, called Instances, in. (how is that for a dangling preposition!?!)\nStart up InstanceContainers first. Then run the system test. The system test\nfinds the InstanceContainers and directs them through ZooKeeper, so you are\ngoing to need an instance of ZooKeeper running that they can all access.\nThe easiest way to do all of this is to use the zookeeper fat jar.\n\nSteps to run system test\n------------------------\n1) transfer the fatjar from the release directory to all systems\n   participating in the test. fatjar is in contrib/fatjar directory.\n\n   (developers can generate by running \"ant jar compile-test\"\n   targets in trunk, then compiling using \"ant jar\" in src/contrib/jarjar)\n\n2) run a zookeeper standalone instance (cluster is ok too)\n\ne.g. java -jar zookeeper-<version>-fatjar.jar server <zoo.cfg>\n\nNote: you must provide zoo.cfg, see sample in conf directory\n\n3) on each host start the system test container\n\ne.g. java -jar zookeeper-<version>-fatjar.jar ic <name> <zkHostPort> /sysTest\n\nname : name of the test container - must be unique \n  typically it's a good idea to name after the host to aid debugging\n\nzkHostPort : the host:port of the server from step 2)\n\n4) initiate the system test using the fatjar:\n\njava -jar build/contrib/fatjar/zookeeper-<version>-fatjar.jar systest org.apache.zookeeper.test.system.SimpleSysTest\n\nby default it will access the zk server started in 2) on localhost:2181 \n\nor you can specify a remote host:port using\n  -DsysTest.zkHostPort=<host>:<port>,<host>:<port>,...\n\njava -DsysTest.zkHostPort=hostA:2181  -jar build/contrib/fatjar/zookeeper-<version>-fatjar.jar systest org.apache.zookeeper.test.system.SimpleSysTest\n\nwhere hostA is running the zk server started in step 2) above\n\nInstanceContainers can also be used to run a the saturation benchmark. The\nfirst two steps are the same as the system test. Step 3 is almost the same:\n\n3) start the InstanceContainer on each host:\n\ne.g. java -jar zookeeper-<version>-fatjar.jar ic <name> <zkHostPort> <prefix>\n\nnote prefix can be /sysTest or any other path. If you do use /sysTest, make\nsure the system test isn't running when you run the benchmark.\n\n4) run GenerateLoad using the following\n\njava -jar build/contrib/fatjar/zookeeper-<version>-fatjar.jar generateLoad <zkHostPort> <prefix> #servers #clients\n\nOnce GenerateLoad is started, it will read commands from stdin. Usually\nthe only command you need to know is \"percentage\" which sets the percentage\nof writes to use in the requests. Once a percentage is set, the benchmark\nwill start. \"percentage 0\" will cause only reads to be issued and\n\"percentage 100\" will cause only writes to be issued.\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/BaseSysTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\n\nimport junit.framework.TestCase;\n\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.junit.Ignore;\nimport org.junit.runner.JUnitCore;\n\n@Ignore(\"No tests in this class.\")\npublic class BaseSysTest extends TestCase {\n    private static final File testData = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"));\n    private static int fakeBasePort = 33222;\n    private static String zkHostPort;\n    protected String prefix = \"/sysTest\";\n    ZooKeeper zk;\n    static {\n        try {\n            zkHostPort = System.getProperty(\"sysTest.zkHostPort\", InetAddress.getLocalHost().getCanonicalHostName() + \":2181\");\n        } catch (UnknownHostException e) {\n            e.printStackTrace();\n        }\n    }\n    InstanceManager im;\n    @Override\n    protected void setUp() throws Exception {\n        if (!fakeMachines) {\n            String localHost = InetAddress.getLocalHost().getCanonicalHostName();\n            zk = new ZooKeeper(zkHostPort, 15000, new Watcher() {public void process(WatchedEvent e){}});\n            im = new InstanceManager(zk, prefix);\n        }\n    }\n    @Override\n    protected void tearDown() throws Exception {\n        if (null != im) {\n            im.close();\n        }\n    }\n\n    int serverCount = defaultServerCount;\n    int clientCount = defaultClientCount;\n    static int defaultServerCount = 5;\n    static int defaultClientCount = 7;\n    static {\n        defaultServerCount = Integer.parseInt(System.getProperty(\"simpleSysTest.defaultServerCount\", Integer.toString(defaultServerCount)));\n        defaultClientCount = Integer.parseInt(System.getProperty(\"simpleSysTest.defaultClientCount\", Integer.toString(defaultClientCount)));\n    }\n\n    String serverHostPort;\n    String quorumHostPort;\n    public String getHostPort() {\n        return serverHostPort;\n    }\n    public int getServerCount() {\n        return serverCount;\n    }\n    public int getClientCount() {\n        return clientCount;\n    }\n\n    public void startServers() throws IOException {\n        for(int i = 0; i < serverCount; i++) {\n            startServer(i);\n        }\n    }\n    public void stopServers() throws IOException {\n        for(int i = 0; i < serverCount; i++) {\n            stopServer(i);\n        }\n    }\n    public void startClients() throws IOException {\n        for(int i = 0; i < clientCount; i++) {\n            startClient(i);\n        }\n    }\n    public void stopClients() throws IOException {\n        for(int i = 0; i < clientCount; i++) {\n            stopClient(i);\n        }\n    }\n\n    private static boolean fakeMachines = System.getProperty(\"baseSysTest.fakeMachines\", \"no\").equals(\"yes\");\n\n    public void configureServers(int count) throws Exception {\n        serverCount = count;\n        if (fakeMachines) {\n            fakeConfigureServers(count);\n        } else {\n            distributedConfigureServers(count);\n        }\n    }\n\n    private void distributedConfigureServers(int count) throws IOException {\n        StringBuilder sbClient = new StringBuilder();\n        StringBuilder sbServer = new StringBuilder();\n        try {\n            for(int i = 0; i < count; i++) {\n                String r[] = QuorumPeerInstance.createServer(im, i);\n                if (i > 0) {\n                    sbClient.append(',');\n                    sbServer.append(',');\n                }\n                sbClient.append(r[0]);\n                sbServer.append(r[1]);\n            }\n            serverHostPort = sbClient.toString();\n            quorumHostPort = sbServer.toString();\n        } catch(Exception e) {\n            IOException ioe = new IOException(e.getMessage());\n            ioe.setStackTrace(e.getStackTrace());\n            throw ioe;\n        }\n    }\n\n    private QuorumPeer qps[];\n    private File qpsDirs[];\n    HashMap<Long,QuorumServer> peers;\n    private void fakeConfigureServers(int count) throws IOException {\n        peers = new HashMap<Long,QuorumServer>();\n        qps = new QuorumPeer[count];\n        qpsDirs = new File[count];\n        for(int i = 1; i <= count; i++) {\n            peers.put(Long.valueOf(i), new QuorumServer(\n                i, \"127.0.0.1\", fakeBasePort + i, serverCount + fakeBasePort + i, null));\n        }\n        StringBuilder sb = new StringBuilder();\n        for(int i = 0; i < count; i++) {\n            //make that testData exists otherwise it fails on windows\n            testData.mkdirs();\n            qpsDirs[i] = File.createTempFile(\"sysTest\", \".tmp\", testData);\n            qpsDirs[i].delete();\n            qpsDirs[i].mkdir();\n            int port = fakeBasePort+10+i;\n            if (sb.length() > 0) {\n                sb.append(',');\n            }\n            sb.append(\"localhost:\");\n            sb.append(port);\n        }\n        serverHostPort = sb.toString();\n    }\n    final static int tickTime = 2000;\n    final static int initLimit = 3;\n    final static int syncLimit = 3;\n\n    public void startServer(int index) throws IOException {\n        int port = fakeBasePort+10+index;\n        if (fakeMachines) {\n            qps[index] = new QuorumPeer(peers, qpsDirs[index], qpsDirs[index], port, 0, index+1, tickTime, initLimit, syncLimit);\n            qps[index].start();\n        } else {\n            try {\n                QuorumPeerInstance.startInstance(im, quorumHostPort, index);\n            } catch(Exception e) {\n                IOException ioe = new IOException(e.getClass().getName() + \": \" + e.getMessage());\n                ioe.setStackTrace(e.getStackTrace());\n                throw ioe;\n            }\n        }\n    }\n    public void stopServer(int index) throws IOException {\n        if (fakeMachines) {\n            qps[index].shutdown();\n        } else {\n            try {\n                QuorumPeerInstance.stopInstance(im, index);\n            } catch(Exception e) {\n                IOException ioe = new IOException(e.getMessage());\n                ioe.setStackTrace(e.getStackTrace());\n                throw ioe;\n            }\n        }\n    }\n\n    public void configureClients(int count, Class<? extends Instance> clazz, String params) throws Exception {\n        clientCount = count;\n        if (fakeMachines) {\n            fakeConfigureClients(count, clazz, params);\n        } else {\n            distributedConfigureClients(count, clazz, params);\n        }\n    }\n    private Class<? extends Instance> clazz;\n    String params;\n    private void distributedConfigureClients(int count, Class<? extends Instance> clazz, String params) throws IOException {\n        this.clazz = clazz;\n        this.params = params;\n\n    }\n    private Instance fakeBaseClients[];\n    private void fakeConfigureClients(int count, Class<? extends Instance> clazz, String params) throws IOException, ClassNotFoundException {\n        fakeBaseClients = new Instance[count];\n        for(int i = 0; i < count; i++) {\n            try {\n                fakeBaseClients[i] = clazz.getDeclaredConstructor().newInstance();\n            } catch (InstantiationException e) {\n                e.printStackTrace();\n                return;\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n                return;\n            } catch (NoSuchMethodException e) {\n                e.printStackTrace();\n                return;\n            } catch (InvocationTargetException e) {\n                e.printStackTrace();\n                return;\n            }\n            fakeBaseClients[i].configure(i + \" \" + params);\n        }\n    }\n    public void startClient(int index) throws IOException {\n        if (fakeMachines) {\n            fakeStartClient(index);\n        } else {\n            distributedStartClient(index);\n        }\n    }\n    private void distributedStartClient(int index) throws IOException {\n        try {\n            im.assignInstance(\"client\" + index, clazz, index + \" \" + params, 1);\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n    }\n    private void fakeStartClient(int index) {\n        fakeBaseClients[index].start();\n    }\n    public void stopClient(int index) throws IOException {\n        if (fakeMachines) {\n            fakeStopClient(index);\n        } else {\n            distributedStopClient(index);\n        }\n    }\n    private void distributedStopClient(int index) throws IOException {\n        try {\n            im.removeInstance(\"client\"+index);\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n    }\n    private void fakeStopClient(int index) {\n        fakeBaseClients[index].stop();\n    }\n    \n    static public void main(String args[]) {\n        JUnitCore.main(args);\n    }\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/DuplicateNameException.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\npublic class DuplicateNameException extends Exception {\n    private static final long serialVersionUID = 1L;\n    public DuplicateNameException(String mess) {\n        super(mess);\n    }\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/GenerateLoad.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.io.BufferedReader;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.net.InetAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.common.Time;\n\npublic class GenerateLoad {\n    protected static final Logger LOG = LoggerFactory.getLogger(GenerateLoad.class);\n\n    static ServerSocket ss;\n\n    static Set<SlaveThread> slaves = Collections\n            .synchronizedSet(new HashSet<SlaveThread>());\n\n    static Map<Long, Long> totalByTime = new HashMap<Long, Long>();\n\n    volatile static long currentInterval;\n\n    static long lastChange;\n    \n    static PrintStream sf;\n    static PrintStream tf;\n    static {\n        try {\n            tf = new PrintStream(new FileOutputStream(\"trace\"));\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n\n    static final int INTERVAL = 6000;\n\n    synchronized static void add(long time, int count, Socket s) {\n        long interval = time / INTERVAL;\n        if (currentInterval == 0 || currentInterval > interval) {\n            System.out.println(\"Dropping \" + count + \" for \" + new Date(time)\n                    + \" \" + currentInterval + \">\" + interval);\n            return;\n        }\n        // We track totals by seconds\n        Long total = totalByTime.get(interval);\n        if (total == null) {\n            totalByTime.put(interval, (long) count);\n        } else {\n            totalByTime.put(interval, total.longValue() + count);\n        }\n        tf.println(interval + \" \" + count + \" \" + s);\n    }\n\n    synchronized static long remove(long interval) {\n        Long total = totalByTime.remove(interval);\n        return total == null ? -1 : total;\n    }\n\n    static class SlaveThread extends Thread {\n        Socket s;\n\n        SlaveThread(Socket s) {\n            setDaemon(true);\n            this.s = s;\n            start();\n        }\n\n        public void run() {\n            try {\n                System.out.println(\"Connected to \" + s);\n                BufferedReader is = new BufferedReader(new InputStreamReader(s\n                        .getInputStream()));\n                String result;\n                while ((result = is.readLine()) != null) {\n                    String timePercentCount[] = result.split(\" \");\n                    if (timePercentCount.length != 5) {\n                        System.err.println(\"Got \" + result + \" from \" + s\n                                + \" exitng.\");\n                        throw new IOException(result);\n                    }\n                    long time = Long.parseLong(timePercentCount[0]);\n                    // int percent = Integer.parseInt(timePercentCount[1]);\n                    int count = Integer.parseInt(timePercentCount[2]);\n                    int errs = Integer.parseInt(timePercentCount[3]);\n                    if (errs > 0) {\n                        System.out.println(s + \" Got an error! \" + errs);\n                    }\n                    add(time, count, s);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            } finally {\n                close();\n            }\n        }\n\n        void send(int percentage) {\n            try {\n                s.getOutputStream().write((percentage + \"\\n\").getBytes());\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n\n        void close() {\n            try {\n                System.err.println(\"Closing \" + s);\n                slaves.remove(this);\n                s.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    static class AcceptorThread extends Thread {\n        AcceptorThread() {\n            setDaemon(true);\n            start();\n        }\n\n        public void run() {\n            try {\n                while (true) {\n                    Socket s = ss.accept();\n                    System.err.println(\"Accepted connection from \" + s);\n                    slaves.add(new SlaveThread(s));\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                for (Iterator<SlaveThread> it = slaves.iterator(); it.hasNext();) {\n                    SlaveThread st = it.next();\n                    it.remove();\n                    st.close();\n                }\n            }\n        }\n    }\n\n    static class ReporterThread extends Thread {\n        static int percentage;\n\n        ReporterThread() {\n            setDaemon(true);\n            start();\n        }\n\n        public void run() {\n            try {\n                currentInterval = Time.currentElapsedTime() / INTERVAL;\n                // Give things time to report;\n                Thread.sleep(INTERVAL * 2);\n                long min = 99999;\n                long max = 0;\n                long total = 0;\n                int number = 0;\n                while (true) {\n                    long now = Time.currentElapsedTime();\n                    long lastInterval = currentInterval;\n                    currentInterval += 1;\n                    long count = remove(lastInterval);\n                    count = count * 1000 / INTERVAL; // Multiply by 1000 to get\n                                                     // reqs/sec\n                    if (lastChange != 0\n                            && (lastChange + INTERVAL * 3) < now) {\n                        // We only want to print anything if things have had a\n                        // chance to change\n\n                        if (count < min) {\n                            min = count;\n                        }\n                        if (count > max) {\n                            max = count;\n                        }\n                        total += count;\n                        number++;\n                        Calendar calendar = Calendar.getInstance();\n                        calendar.setTimeInMillis(lastInterval * INTERVAL);\n                        String report = lastInterval + \" \"\n                                + calendar.get(Calendar.HOUR_OF_DAY) + \":\"\n                                + calendar.get(Calendar.MINUTE) + \":\"\n                                + calendar.get(Calendar.SECOND) + \" \"\n                                + percentage + \"% \" + count + \" \" + min + \" \"\n                                + ((double) total / (double) number) + \" \"\n                                + max;\n                        System.err.println(report);\n                        if (sf != null) {\n                            sf.println(report);\n                        }\n                    } else {\n                        max = total = 0;\n                        min = 999999999;\n                        number = 0;\n                    }\n                    Thread.sleep(INTERVAL);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n        }\n    }\n\n    synchronized static void sendChange(int percentage) {\n        long now = Time.currentElapsedTime();\n        long start = now;\n        ReporterThread.percentage = percentage;\n        for (SlaveThread st : slaves.toArray(new SlaveThread[0])) {\n            st.send(percentage);\n        }\n        now = Time.currentElapsedTime();\n        long delay = now - start;\n        if (delay > 1000) {\n            System.out.println(\"Delay of \" + delay + \" to send new percentage\");\n        }\n        lastChange = now;\n    }\n\n    static public class GeneratorInstance implements Instance {\n\n        byte bytes[];\n        \n        int percentage = -1;\n\n        int errors;\n\n        final Object statSync = new Object();\n\n        int finished;\n\n        int reads;\n\n        int writes;\n\n        int rlatency;\n\n        int wlatency;\n\n        int outstanding;\n        \n        volatile boolean alive;\n\n        class ZooKeeperThread extends Thread implements Watcher, DataCallback,\n                StatCallback {\n            String host;\n\n            ZooKeeperThread(String host) {\n                setDaemon(true);\n                alive = true;\n                this.host = host;\n                start();\n            }\n\n            static final int outstandingLimit = 100;\n\n            synchronized void incOutstanding() throws InterruptedException {\n                outstanding++;\n                while (outstanding > outstandingLimit) {\n                    wait();\n                }\n            }\n\n            synchronized void decOutstanding() {\n                outstanding--;\n                notifyAll();\n            }\n\n            Random r = new Random();\n\n            String path;\n\n            ZooKeeper zk;\n\n            boolean connected;\n\n            public void run() {\n                try {\n                    zk = new ZooKeeper(host, 60000, this);\n                    synchronized (this) {\n                        if (!connected) {\n                            wait(20000);\n                        }\n                    }\n                    for (int i = 0; i < 300; i++) {\n                        try {\n                            Thread.sleep(100);\n                            path = zk.create(\"/client\", new byte[16],\n                                    Ids.OPEN_ACL_UNSAFE,\n                                    CreateMode.EPHEMERAL_SEQUENTIAL);\n                            break;\n                        } catch (KeeperException e) {\n                            LOG.error(\"keeper exception thrown\", e);\n                        }\n                    }\n                    if (path == null) {\n                        System.err.println(\"Couldn't create a node in /!\");\n                        return;\n                    }\n                    while (alive) {\n                        if (r.nextInt(100) < percentage) {\n                            zk.setData(path, bytes, -1, this, System\n                                    .currentTimeMillis());\n                        } else {\n                            zk.getData(path, false, this, System\n                                    .currentTimeMillis());\n                        }\n                        incOutstanding();\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                } finally {\n                    alive = false;\n                    try {\n                        zk.close();\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n\n            public void process(WatchedEvent event) {\n                System.err.println(event);\n                synchronized (this) {\n                    if (event.getType() == EventType.None) {\n                        connected = (event.getState() == KeeperState.SyncConnected);\n                        notifyAll();\n                    }\n                }\n            }\n\n            public void processResult(int rc, String path, Object ctx, byte[] data,\n                    Stat stat) {\n                decOutstanding();\n                synchronized (statSync) {\n                    if (!alive) {\n                        return;\n                    }\n                    if (rc != 0) {\n                        System.err.println(\"Got rc = \" + rc);\n                        errors++;\n                    } else {\n                        finished++;\n                        rlatency += Time.currentElapsedTime() - (Long) ctx;\n                        reads++;\n                    }\n                }\n            }\n\n            public void processResult(int rc, String path, Object ctx, Stat stat) {\n                decOutstanding();\n                synchronized (statSync) {\n                    if (rc != 0) {\n                        System.err.println(\"Got rc = \" + rc);\n                        errors++;\n                    } else {\n                        finished++;\n                        wlatency += Time.currentElapsedTime() - (Long) ctx;\n                        writes++;\n                    }\n                }\n            }\n        }\n\n        class SenderThread extends Thread {\n            Socket s;\n\n            SenderThread(Socket s) {\n                this.s = s;\n                setDaemon(true);\n                start();\n            }\n\n            public void run() {\n                try {\n                    OutputStream os = s.getOutputStream();\n                    finished = 0;\n                    errors = 0;\n                    while (alive) {\n                        Thread.sleep(300);\n                        if (percentage == -1 || (finished == 0 && errors == 0)) {\n                            continue;\n                        }\n                        String report = Time.currentElapsedTime() + \" \"\n                                + percentage + \" \" + finished + \" \" + errors + \" \"\n                                + outstanding + \"\\n\";\n                       /* String subreport = reads + \" \"\n                                + (((double) rlatency) / reads) + \" \" + writes\n                                + \" \" + (((double) wlatency / writes)); */\n                        synchronized (statSync) {\n                            finished = 0;\n                            errors = 0;\n                            reads = 0;\n                            writes = 0;\n                            rlatency = 0;\n                            wlatency = 0;\n                        }\n                        os.write(report.getBytes());\n                        //System.out.println(\"Reporting \" + report + \"+\" + subreport);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n\n            }\n        }\n\n        Socket s;\n        ZooKeeperThread zkThread;\n        SenderThread sendThread;\n        Reporter r;\n\n        public void configure(final String params) {\n            System.err.println(\"Got \" + params);\n            new Thread() {\n                public void run() {\n                    try {\n                        String parts[] = params.split(\" \");\n                        String hostPort[] = parts[1].split(\":\");\n                        int bytesSize = 1024;\n                        if (parts.length == 3) {\n                            try {\n                                bytesSize = Integer.parseInt(parts[2]);\n                            } catch(Exception e) {\n                                System.err.println(\"Not an integer: \" + parts[2]);\n                            }\n                        }\n                        bytes = new byte[bytesSize];\n                        s = new Socket(hostPort[0], Integer.parseInt(hostPort[1]));\n                        zkThread = new ZooKeeperThread(parts[0]);\n                        sendThread = new SenderThread(s);\n                        BufferedReader is = new BufferedReader(new InputStreamReader(s\n                                .getInputStream()));\n                        String line;\n                        while ((line = is.readLine()) != null) {\n                            percentage = Integer.parseInt(line);\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            }.start();\n\n        }\n\n        public void setReporter(Reporter r) {\n            this.r = r;\n        }\n\n        public void start() {\n            try {\n                r.report(\"started\");\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n\n        public void stop() {\n            alive = false;\n            zkThread.interrupt();\n            sendThread.interrupt();\n            try {\n                zkThread.join();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            try {\n                sendThread.join();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            try {\n                r.report(\"stopped\");\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            try {\n                s.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n\n    }\n\n    private static class StatusWatcher implements Watcher {\n        volatile boolean connected;\n\n        public void process(WatchedEvent event) {\n            if (event.getType() == Watcher.Event.EventType.None) {\n                synchronized (this) {\n                    connected = event.getState() == Watcher.Event.KeeperState.SyncConnected;\n                    notifyAll();\n                }\n            }\n        }\n\n        public boolean isConnected() {\n            return connected;\n        }\n\n        synchronized public boolean waitConnected(long timeout)\n                throws InterruptedException {\n            long endTime = Time.currentElapsedTime() + timeout;\n            while (!connected && Time.currentElapsedTime() < endTime) {\n                wait(endTime - Time.currentElapsedTime());\n            }\n            return connected;\n        }\n    }\n\n    private static boolean leaderOnly;\n    private static boolean leaderServes;\n    \n    private static String []processOptions(String args[]) {\n        ArrayList<String> newArgs = new ArrayList<String>();\n        for(String a: args) {\n            if (a.equals(\"--leaderOnly\")) {\n                leaderOnly = true;\n                leaderServes = true;\n            } else if (a.equals(\"--leaderServes\")) {\n                leaderServes = true;\n            } else {\n                newArgs.add(a);\n            }\n        }\n        return newArgs.toArray(new String[0]);\n    }\n    \n    /**\n     * @param args\n     * @throws InterruptedException\n     * @throws KeeperException\n     * @throws DuplicateNameException\n     * @throws NoAvailableContainers\n     * @throws NoAssignmentException\n     */\n    public static void main(String[] args) throws InterruptedException,\n            KeeperException, NoAvailableContainers, DuplicateNameException,\n            NoAssignmentException {\n\n        args = processOptions(args);\n        if (args.length == 5) {\n            try {\n                StatusWatcher statusWatcher = new StatusWatcher();\n                ZooKeeper zk = new ZooKeeper(args[0], 15000, statusWatcher);\n                if (!statusWatcher.waitConnected(5000)) {\n                    System.err.println(\"Could not connect to \" + args[0]);\n                    return;\n                }\n                InstanceManager im = new InstanceManager(zk, args[1]);\n                ss = new ServerSocket(0);\n                int port = ss.getLocalPort();\n                int serverCount = Integer.parseInt(args[2]);\n                int clientCount = Integer.parseInt(args[3]);\n                StringBuilder quorumHostPort = new StringBuilder();\n                StringBuilder zkHostPort = new StringBuilder();\n                for (int i = 0; i < serverCount; i++) {\n                    String r[] = QuorumPeerInstance.createServer(im, i, leaderServes);\n                    if (i > 0) {\n                        quorumHostPort.append(',');\n                        zkHostPort.append(',');\n                    }\n                    zkHostPort.append(r[0]);\n                    quorumHostPort.append(r[1]);\n                }\n                for (int i = 0; i < serverCount; i++) {\n                    QuorumPeerInstance.startInstance(im, quorumHostPort\n                            .toString(), i);\n                }\n                if (leaderOnly) {\n                    int tries = 0;\n                    outer:\n                        while(true) {\n                            Thread.sleep(1000);\n                            IOException lastException = null;\n                            String parts[] = zkHostPort.toString().split(\",\");\n                            for(int i = 0; i < parts.length; i++) {\n                                try {\n                                    String mode = getMode(parts[i]);\n                                    if (mode.equals(\"leader\")) {\n                                        zkHostPort = new StringBuilder(parts[i]);\n                                        System.out.println(\"Connecting exclusively to \" + zkHostPort.toString());\n                                        break outer;\n                                    }\n                                } catch(IOException e) {\n                                    lastException = e;\n                                }\n                            }\n                            if (tries++ > 3) {\n                                throw lastException;\n                            }\n                        }\n                }\n                for (int i = 0; i < clientCount; i++) {\n                    im.assignInstance(\"client\" + i, GeneratorInstance.class,\n                            zkHostPort.toString()\n                                    + ' '\n                                    + InetAddress.getLocalHost()\n                                            .getCanonicalHostName() + ':'\n                                    + port, 1);\n                }\n                new AcceptorThread();\n                new ReporterThread();\n                BufferedReader is = new BufferedReader(new InputStreamReader(\n                        System.in));\n                String line;\n                while ((line = is.readLine()) != null) {\n                    try {\n                        String cmdNumber[] = line.split(\" \");\n                        if (cmdNumber[0].equals(\"percentage\")\n                                && cmdNumber.length > 1) {\n                            int number = Integer.parseInt(cmdNumber[1]);\n                            if (number < 0 || number > 100) {\n                                throw new NumberFormatException(\n                                        \"must be between 0 and 100\");\n                            }\n                            sendChange(number);\n                        } else if (cmdNumber[0].equals(\"sleep\")\n                                && cmdNumber.length > 1) {\n                            int number = Integer.parseInt(cmdNumber[1]);\n                            Thread.sleep(number * 1000);\n                        } else if (cmdNumber[0].equals(\"save\")\n                                && cmdNumber.length > 1) {\n                            sf = new PrintStream(cmdNumber[1]);\n                        } else {\n                            System.err.println(\"Commands must be:\");\n                            System.err\n                                    .println(\"\\tpercentage new_write_percentage\");\n                            System.err.println(\"\\tsleep seconds_to_sleep\");\n                            System.err.println(\"\\tsave file_to_save_output\");\n                        }\n                    } catch (NumberFormatException e) {\n                        System.out.println(\"Not a valid number: \"\n                                + e.getMessage());\n                    }\n                }\n            } catch (NumberFormatException e) {\n                doUsage();\n            } catch (IOException e) {\n                e.printStackTrace();\n                System.exit(2);\n            }\n        } else {\n            doUsage();\n        }\n\n    }\n\n    private static String getMode(String hostPort) throws NumberFormatException, UnknownHostException, IOException {\n        String parts[] = hostPort.split(\":\");\n        Socket s = new Socket(parts[0], Integer.parseInt(parts[1]));\n        s.getOutputStream().write(\"stat\".getBytes());\n        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));\n        String line;\n        try {\n          while((line = br.readLine()) != null) {\n            if (line.startsWith(\"Mode: \")) {\n              return line.substring(6);\n            }\n          }\n          return \"unknown\";\n        } finally {\n          s.close();\n        }\n    }\n\n    private static void doUsage() {\n        System.err.println(\"USAGE: \" + GenerateLoad.class.getName()\n                + \" [--leaderOnly] [--leaderServes] zookeeper_host:port containerPrefix #ofServers #ofClients requestSize\");\n        System.exit(2);\n    }\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/Instance.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport org.apache.zookeeper.KeeperException;\n\n/**\n * This interface is implemented by a class that can be run in an\n * instance container.\n *\n */\npublic interface Instance {\n    /**\n     * This object is used to report back changes in status.\n     */\n    interface Reporter {\n        void report(String report) throws KeeperException, InterruptedException;\n    }\n    /**\n     * This will be the first method invoked by the InstanceContainer after\n     * an instance of this interface has been constructed. It will only be\n     * invoked once.\n     * \n     * @param r a handle to use to report on status changes.\n     */\n    void setReporter(Reporter r);\n    /**\n     * This will be the second method invoked by the InstanceContainer. It \n     * may be invoked again if the configuration changes.\n     * \n     * @param params parameters that were passed to the InstanceManager when\n     *        this instance was scheduled.\n     */\n    void configure(String params);\n    /**\n     * Starts this instance.\n     */\n    void start();\n    /**\n     * Stops this instance.\n     */\n    void stop();\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/InstanceContainer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.KeeperException.NodeExistsException;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.test.system.Instance.Reporter;\n\n/**\n * This class starts up, \n */\npublic class InstanceContainer implements Watcher, AsyncCallback.ChildrenCallback {\n    private final class MyWatcher implements Watcher {\n        String myNode;\n        DataCallback dc;\n        MyWatcher(String myNode, DataCallback dc) {\n            this.myNode = myNode;\n            this.dc = dc;\n        }\n        public void process(WatchedEvent event) {\n            if (event.getPath() != null && event.getPath().equals(myNode)) {\n                zk.getData(myNode, this, dc, this);\n            }\n        }\n    }\n    private final class MyDataCallback implements DataCallback {\n        int lastVer;\n        String myNode;\n        Instance myInstance;\n\n        MyDataCallback(String myNode, Instance myInstance, int ver) {\n            this.myNode = myNode;\n            this.myInstance = myInstance;\n            lastVer = ver;\n        }\n        public void processResult(int rc, String path,\n                Object ctx, byte[] data, Stat stat) {\n            if (rc == KeeperException.Code.NONODE.intValue()) {\n                // we can just ignore because the child watcher takes care of this\n                return;\n            }\n            if (rc != KeeperException.Code.OK.intValue()) {\n                zk.getData(myNode, (Watcher)ctx, this, ctx);\n            }\n            int currVer = stat.getVersion();\n            if (currVer != lastVer) {\n                String parts[] = new String(data).split(\" \", 2);\n                myInstance.configure(parts[1]);\n                lastVer = currVer;\n            }\n        }\n    }\n    private final class MyReporter implements Reporter {\n        String myReportNode;\n\n        public MyReporter(String child) {\n            myReportNode = reportsNode + '/' + child;\n        }\n\n        public void report(String report) throws KeeperException, InterruptedException {\n            for(int j = 0; j < maxTries; j++) {\n                try {\n                    try {\n                        zk.setData(myReportNode, report.getBytes(), -1);\n                    } catch(NoNodeException e) {\n                        zk.create(myReportNode, report.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n                    }\n                    break;\n                } catch(ConnectionLossException e) {}\n            }\n        }\n    }\n    private static final Logger LOG = LoggerFactory.getLogger(InstanceContainer.class); \n    String name;\n    String zkHostPort;\n    // We only run if the readyNode exists\n    String prefixNode;\n    String statusNode = \"available\";\n    String reportsNode = \"reports\";\n    String assignmentsNode = \"assignments\";\n    ZooKeeper zk;\n    static final int sessTimeout = 5000;\n    static final int maxTries = 3;\n    public InstanceContainer(String name, String zkHostPort, String prefix) throws UnknownHostException {\n        if (name.length() == 0 || name.equals(\"hostname\")) {\n            name = InetAddress.getLocalHost().getCanonicalHostName();\n        }\n        this.name = name;\n        this.zkHostPort = zkHostPort;\n        this.prefixNode = prefix;\n        this.statusNode = prefix + '/' + this.statusNode + '/' + name;\n        this.reportsNode = prefix + '/' + this.reportsNode;\n        this.assignmentsNode = prefix + '/' + this.assignmentsNode + '/' + name;\n    }\n    \n    private void rmnod(String path) throws InterruptedException, KeeperException {\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.delete(path, -1);\n                lastException = null;\n                break;\n            } catch (KeeperException.NoNodeException e) {\n                // cool this is what we want\n                break;\n            } catch (KeeperException e) {\n                lastException = e;\n            }\n        }\n        if (lastException != null) {\n            throw lastException;\n        }\n    }\n    private void mknod_inner(String path, CreateMode mode) throws KeeperException, InterruptedException {\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.create(path, null, Ids.OPEN_ACL_UNSAFE, mode);\n                break;\n            } catch (NodeExistsException e) {\n                if (mode != CreateMode.EPHEMERAL) {\n                    return;\n                }\n                Stat stat = zk.exists(path, false);\n                if (stat == null) {\n                    continue;\n                }\n                if (stat.getEphemeralOwner() != zk.getSessionId()) {\n                    throw e;\n                }\n                break;\n            } catch (ConnectionLossException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n    \n    private void mknod(String path, CreateMode mode) throws KeeperException, InterruptedException {\n        String subpath[] = path.split(\"/\");\n        StringBuilder sb = new StringBuilder();\n        // We start at 1 because / will create an empty part first\n        for(int i = 1; i < subpath.length; i++) {\n            sb.append(\"/\");\n            sb.append(subpath[i]);\n            CreateMode m = CreateMode.PERSISTENT;\n            if (i == subpath.length-1) {\n                m = mode;\n            }\n            mknod_inner(sb.toString(), m);\n        }\n    }\n    \n    public void run() throws IOException, InterruptedException, KeeperException {\n        zk = new ZooKeeper(zkHostPort, sessTimeout, this);\n        mknod(assignmentsNode, CreateMode.PERSISTENT);\n        mknod(statusNode, CreateMode.EPHEMERAL);\n        mknod(reportsNode, CreateMode.PERSISTENT);\n        // Now we just start watching the assignments directory\n        zk.getChildren(assignmentsNode, true, this, null);\n    }\n    \n    /**\n     * @param args the first parameter is the instance name, the second\n     * is the ZooKeeper spec. if the instance name is the empty string\n     * or \"hostname\", the hostname will be used.\n     * @throws InterruptedException \n     * @throws IOException \n     * @throws UnknownHostException \n     * @throws KeeperException \n     */\n    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException, KeeperException {\n        if (args.length != 3) {\n            System.err.println(\"USAGE: \" + InstanceContainer.class.getName() + \" name zkHostPort znodePrefix\");\n            System.exit(2);\n        }\n        new InstanceContainer(args[0], args[1], args[2]).run();\n        while(true) {\n            Thread.sleep(1000);\n        }\n    }\n\n    public void process(WatchedEvent event) {\n        if (KeeperState.Expired == event.getState()) {\n            // It's all over\n            LOG.error(\"Lost session\");\n            System.exit(4);\n        }\n        if (event.getPath() != null && event.getPath().equals(assignmentsNode)) {\n            // children have changed, so read in the new list\n            zk.getChildren(assignmentsNode, true, this, null);\n        }\n    }\n\n    HashMap<String, Instance> instances = new HashMap<String, Instance>();\n    public void processResult(int rc, String path, Object ctx,\n            List<String> children) {\n        if (rc != KeeperException.Code.OK.intValue()) {\n            // try it again\n            zk.getChildren(assignmentsNode, true, this, null);\n            return;\n        }\n        HashMap<String, Instance> newList = new HashMap<String, Instance>();\n        // check for differences\n        Stat stat = new Stat();\n        for(String child: children) {\n            Instance i = instances.remove(child);\n            if (i == null) {\n                // Start up a new instance\n                byte data[] = null;\n                String myNode = assignmentsNode + '/' + child;\n                while(true) {\n                    try {\n                        data = zk.getData(myNode, true, stat);\n                        break;\n                    } catch (NoNodeException e) {\n                        // The node doesn't exist anymore, so skip it\n                        break;\n                    } catch (KeeperException e) {\n                        e.printStackTrace();\n                    } catch (InterruptedException e) {\n                        return;\n                    }\n                }\n                if (data != null) {\n                    String instanceSpec = new String(data);\n                    int spaceIndex = instanceSpec.indexOf(' ');\n                    String clazz;\n                    String conf;\n                    if (spaceIndex == -1) {\n                        clazz = instanceSpec;\n                        conf = null;\n                    } else {\n                        clazz = instanceSpec.substring(0, spaceIndex);\n                        conf = instanceSpec.substring(spaceIndex+1);\n                    }\n                    try {\n                        Class c = Class.forName(clazz);\n                        i = (Instance)c.getDeclaredConstructor().newInstance();\n                        Reporter reporter = new MyReporter(child);\n                        i.setReporter(reporter);\n                        i.configure(conf);\n                        i.start();\n                        newList.put(child, i);\n                        int ver = stat.getVersion();\n                        Instance myInstance = i;\n                        DataCallback dc = new MyDataCallback(myNode, myInstance, ver);\n                        Watcher watcher = new MyWatcher(myNode, dc);\n                        zk.getData(myNode, watcher, dc, watcher);\n                    } catch (Exception e) {\n                        LOG.warn(\"Skipping \" + child, e);\n                        if (e.getCause() != null) {\n                            LOG.warn(\"Caused by\", e.getCause());\n                        }\n                    }\n                    \n                }\n            } else {\n                // just move it to the new list\n                newList.put(child, i);\n            }\n        }\n        // kill anything that was removed for the children\n        for(Map.Entry<String,Instance> i: instances.entrySet()) {\n            i.getValue().stop();\n            try {\n                rmnod(reportsNode + '/' + i.getKey());\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            } catch (KeeperException e) {\n                e.printStackTrace();\n            }\n        }\n        instances = newList;\n    }\n\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/InstanceManager.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.KeeperException.NodeExistsException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * This class doles out assignments to InstanceContainers that are registered to\n * a ZooKeeper znode. The znode will have four child nodes:\n *    * ready: this znode indicates that the InstanceManager is running\n *    * available: the children of this znode are ephemeral nodes representing\n *                 running InstanceContainers\n *    * assignments: there will be a child under this znode for each available \n *                   InstanceContainer. those znodes will have a child for each\n *                   assigned instance\n *    * reports: there will be a child under this znode for each instance that is\n *               running. it will have the report string from the instance.\n */\npublic class InstanceManager implements AsyncCallback.ChildrenCallback, Watcher {\n    final private static Logger LOG = LoggerFactory.getLogger(InstanceManager.class);\n    private ZooKeeper zk;\n    private String prefixNode;\n    private String reportsNode = \"reports\";\n    private String readyNode = \"ready\";\n    private String assignmentsNode = \"assignments\";\n    private String statusNode = \"available\";\n    private static final int maxTries = 3;\n    private static final class Assigned {\n        String container;\n        String instance;\n        int weight;\n        Assigned(String container, String instance, int weight) {\n            this.container = container;\n            this.instance = instance;\n            this.weight = weight;\n        }\n    }\n    private static List<String> preferredList = new ArrayList<String>();\n    static {\n        String list = System.getProperty(\"ic.preferredList\");\n        if (list != null) {\n            preferredList = Arrays.asList(list.split(\",\"));\n            System.err.println(\"Preferred List: \" + preferredList);\n        } else {\n            System.err.println(\"Preferred List is empty\");\n        }\n    }\n    private HashMap<String, HashSet<Assigned>> assignments = new HashMap<String, HashSet<Assigned>>();\n    private HashMap<String, Assigned> instanceToAssignment = new HashMap<String, Assigned>();\n    public InstanceManager(ZooKeeper zk, String prefix) throws KeeperException, InterruptedException {\n        this.zk = zk;\n        this.prefixNode = prefix;\n        this.readyNode = prefix + '/' + this.readyNode;\n        this.assignmentsNode = prefix + '/' + this.assignmentsNode;\n        this.reportsNode = prefix + '/' + this.reportsNode;\n        this.statusNode = prefix + '/' + this.statusNode;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                setupNodes(zk);\n                break;\n            } catch(ConnectionLossException e) {}\n        }\n        ConnectionLossException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                List<String> children = zk.getChildren(statusNode, this);\n                processResult(0, statusNode, null, children);\n                lastException = null;\n                break;\n            } catch(ConnectionLossException e) {\n                lastException = e;\n            }\n        }\n        if (lastException != null) {\n            throw lastException;\n        }\n    }\n    private void setupNodes(ZooKeeper zk) throws KeeperException,\n            InterruptedException {\n        try {\n            zk.create(prefixNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(NodeExistsException e) { /* this is ok */ } \n        try {\n            zk.create(assignmentsNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(NodeExistsException e) { /* this is ok */ } \n        try { \n            zk.create(statusNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(NodeExistsException e) { /* this is ok */ } \n        try { \n            zk.create(reportsNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(NodeExistsException e) { /* this is ok */ } \n        try {\n            zk.create(readyNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch(NodeExistsException e) { /* this is ok */ } \n    }\n    \n    synchronized public void processResult(int rc, String path, Object ctx,\n            List<String> children) {\n        if (rc != KeeperException.Code.OK.intValue()) {\n            zk.getChildren(statusNode, this, this, null);\n            return;\n        }\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Got \" + children + \" children from \" + path);\n        }\n        HashMap<String, HashSet<Assigned>> newAssignments = new HashMap<String, HashSet<Assigned>>();\n        for(String c: children) {\n            HashSet<Assigned> a = assignments.remove(c);\n            if (a != null) {\n                newAssignments.put(c, a);\n            } else {\n                newAssignments.put(c, new HashSet<Assigned>());\n            }\n        }\n        // Clean up the dead machines\n        for(String dead: assignments.keySet()) {\n            try {\n                removeInstance(dead);\n            } catch (KeeperException e) {\n                e.printStackTrace();\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n        assignments = newAssignments;\n    }\n    private void removeAssignmentNode(String dead) throws KeeperException, InterruptedException {\n        String deadNode = assignmentsNode + '/' + dead;\n        List<String> children = zk.getChildren(deadNode, false);\n        for(String c: children) {\n            zk.delete(deadNode + '/' + c, -1);\n        }\n        try {\n            zk.delete(deadNode, -1);\n        } catch(NoNodeException e) { /* this is ok */ }\n    }\n    \n    public void process(WatchedEvent event) {\n        if (event.getPath().equals(statusNode)) {\n            zk.getChildren(statusNode, this, this, null);\n        }\n    }\n    synchronized public String assignInstance(String name, Class<? extends Instance> clazz, String params, int weight) throws NoAvailableContainers, DuplicateNameException, InterruptedException, KeeperException {\n        if (weight < 1) {\n            // if the weights are not above zero, things will get messed up\n            weight = 1;\n        }\n        String instanceSpec = clazz.getName() + ' ' + params;\n        if (instanceToAssignment.get(name) != null) {\n            throw new DuplicateNameException(name + \" already exists\");\n        }\n        // find most idle node\n        String mostIdle = null;\n        int mostIdleWeight = Integer.MAX_VALUE;\n        for(String preferred: preferredList) {\n            HashSet<Assigned> assignmentList = assignments.get(preferred);\n            int w = 0;\n            if (assignmentList != null) {\n                for(Assigned a: assignmentList) {\n                    w += a.weight;\n                }\n                if (w < mostIdleWeight) {\n                    mostIdleWeight = w;\n                    mostIdle = preferred;\n                }\n            }\n        }\n        for(Entry<String, HashSet<Assigned>> e: assignments.entrySet()) {\n            int w = 0;\n            for(Assigned a: e.getValue()) {\n                w += a.weight;\n            }\n            if (w < mostIdleWeight) {\n                mostIdleWeight = w;\n                mostIdle = e.getKey();\n            }\n        }\n        if (mostIdle == null) {\n            throw new NoAvailableContainers(\"No available containers\");\n        }\n        Assigned a = new Assigned(mostIdle, name, weight);\n        instanceToAssignment.put(name, a);\n        HashSet<Assigned> as = assignments.get(mostIdle);\n        if (as == null) {\n            as = new HashSet<Assigned>();\n            assignments.put(mostIdle, as);\n        }\n        as.add(a);\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.create(assignmentsNode + '/' + mostIdle + '/' + name, instanceSpec.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n                return mostIdle;\n            } catch(NodeExistsException e) {\n                return mostIdle;\n            } catch (KeeperException e) {\n                lastException = e;\n            }\n        }\n        throw lastException;\n    }\n    \n    public void reconfigureInstance(String name, String params) throws NoAssignmentException, InterruptedException, KeeperException {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Reconfiguring \" + name + \" with \" + params);\n        }\n        Assigned assigned = instanceToAssignment.get(name);\n        if (assigned == null) {\n            throw new NoAssignmentException();\n        }\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.setData(assignmentsNode + '/' + assigned.container + '/' + name, (\"update \" + params).getBytes(), -1);\n                break;\n            } catch (ConnectionLossException e) {\n                lastException = e;\n            }\n        }\n        if (lastException != null) {\n            throw lastException;\n        }\n    }\n    \n    private void doDelete(String path) throws InterruptedException, KeeperException {\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.delete(path, -1);\n                return;\n            } catch(NoNodeException e) {\n                return;\n            } catch (KeeperException e) {\n                lastException = e;\n            }\n        }\n        throw lastException;\n    }\n    synchronized public void removeInstance(String name) throws InterruptedException, KeeperException {\n        Assigned assigned = instanceToAssignment.remove(name);\n        if (assigned == null) {\n            return;\n        }\n        assignments.get(assigned.container).remove(name);\n        doDelete(assignmentsNode + '/' + assigned.container + '/' + name);\n        doDelete(reportsNode + '/' + name);\n    }\n    \n    synchronized boolean isAlive(String name) {\n        return instanceToAssignment.get(name) != null;\n    }\n    \n    public void resetStatus(String name) throws InterruptedException, KeeperException {\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries; i++) {\n            try {\n                zk.delete(reportsNode + '/' + name, -1);\n                lastException = null;\n                break;\n            } catch(ConnectionLossException e) {\n                lastException = e;\n            } catch(NoNodeException e) {\n                // great this is what we want!\n            }\n        }\n        if (lastException != null) {\n            throw lastException;\n        }\n    }\n\n    public String getStatus(String name, long timeout) throws KeeperException, InterruptedException {\n        Stat stat = new Stat();\n        byte data[] = null;\n        long endTime = System.currentTimeMillis() + timeout;\n        KeeperException lastException = null;\n        for(int i = 0; i < maxTries && endTime > System.currentTimeMillis(); i++) {\n            try {\n                data = zk.getData(reportsNode + '/' + name, false, stat);\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Got Data: \" + ((data == null) ? \"null\" : new String(data)));\n                }\n                lastException = null;\n                break;\n            } catch(ConnectionLossException e) {\n                lastException = e;\n            } catch(NoNodeException e) {\n                final Object eventObj = new Object();\n                synchronized(eventObj) {\n                    // wait for the node to appear\n                    Stat eStat = zk.exists(reportsNode + '/' + name, new Watcher() {\n                        public void process(WatchedEvent event) {\n                            synchronized(eventObj) {\n                                eventObj.notifyAll();\n                            }\n                        }});\n                    if (eStat == null) {\n                        eventObj.wait(endTime - System.currentTimeMillis());\n                    }\n                }\n                lastException = e;\n            }\n        }\n        if (lastException != null) {\n            throw lastException;\n        }\n        return new String(data);\n    }\n    synchronized public void close() throws InterruptedException {\n        for(String name: instanceToAssignment.keySet().toArray(new String[0])) {\n            try {\n                removeInstance(name);\n            } catch(KeeperException e) {\n                e.printStackTrace();\n            }\n        }\n        try {\n            doDelete(readyNode);\n        } catch (KeeperException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/NoAssignmentException.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\npublic class NoAssignmentException extends Exception {\n    private static final long serialVersionUID = 1L;\n\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/NoAvailableContainers.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\npublic class NoAvailableContainers extends Exception {\n    public NoAvailableContainers(String string) {\n        super(string);\n    }\n\n    private static final long serialVersionUID = 1L;\n\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/QuorumPeerInstance.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.HashMap;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\n\nclass QuorumPeerInstance implements Instance {\n    final private static Logger LOG = LoggerFactory.getLogger(QuorumPeerInstance.class);\n    private static final File testData = new File(\n        System.getProperty(\"test.data.dir\", \"build/test/data\"));\n\n    private static final int syncLimit = 3;\n    private static final int initLimit = 3;\n    private static final int tickTime = 2000;\n    String serverHostPort;\n    int serverId;\n    Reporter r;\n    QuorumPeer peer;\n\n    public void setReporter(Reporter r) {\n        this.r = r;\n    }\n\n    InetSocketAddress clientAddr;\n    InetSocketAddress quorumAddr;\n    HashMap<Long, QuorumServer> peers;\n    File snapDir, logDir;\n\n    public QuorumPeerInstance() {\n        try {\n            File tmpFile = File.createTempFile(\"test\", \".dir\", testData);\n            File tmpDir = tmpFile.getParentFile();\n            tmpFile.delete();\n            File zkDirs = new File(tmpDir, \"zktmp.cfg\");\n            logDir = tmpDir;\n            snapDir = tmpDir;\n            Properties p;\n            if (zkDirs.exists()) {\n                p = new Properties();\n                FileInputStream input = new FileInputStream(zkDirs);\n                try {\n                  p.load(input);\n                } finally {\n                  input.close();\n                }\n            } else {\n                p = System.getProperties();\n            }\n            logDir = new File(p.getProperty(\"logDir\", tmpDir.getAbsolutePath()));\n            snapDir = new File(p.getProperty(\"snapDir\", tmpDir.getAbsolutePath()));\n            logDir = File.createTempFile(\"zktst\", \".dir\", logDir);\n            logDir.delete();\n            logDir.mkdirs();\n            snapDir = File.createTempFile(\"zktst\", \".dir\", snapDir);\n            snapDir.delete();\n            snapDir.mkdirs();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void configure(String params) {\n        if (clientAddr == null) {\n            String parts[] = params.split(\" \");\n            // The first time we are configured, it is just to tell\n            // us which machine we are\n            serverId = Integer.parseInt(parts[0]);\n            if (LOG.isDebugEnabled()) {\n                LOG.info(\"Setting up server \" + serverId);\n            }\n            if (parts.length > 1 && parts[1].equals(\"false\")) {\n                System.setProperty(\"zookeeper.leaderServes\", \"no\");\n            } else {\n                System.setProperty(\"zookeeper.leaderServes\", \"yes\");\n            }\n            // Let's grab two ports\n            try {\n                ServerSocket ss = new ServerSocket(0, 1, InetAddress.getLocalHost());\n                clientAddr = (InetSocketAddress) ss.getLocalSocketAddress();\n                ss.close();\n            } catch(IOException e) {\n                e.printStackTrace();\n            }\n            try {\n                ServerSocket ss = new ServerSocket(0, 1, InetAddress.getLocalHost());\n                quorumAddr = (InetSocketAddress) ss.getLocalSocketAddress();\n                ss.close();\n            } catch(IOException e) {\n                e.printStackTrace();\n            }\n            String report = clientAddr.getHostName() + ':' + clientAddr.getPort() +\n            ',' + quorumAddr.getHostName() + ':' + quorumAddr.getPort();\n            try {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Reporting \" + report);\n                }\n                r.report(report);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return;\n        } else {\n            int spaceIndex = params.indexOf(' ');\n            if (spaceIndex == -1) {\n                LOG.warn(\"looking for host:port,... start|stop, but found \" + params);\n                return;\n            }\n            String quorumSpecs = params.substring(0, spaceIndex);\n            String cmd = params.substring(spaceIndex+1);\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\"Running command: \" + cmd);\n            }\n            if (!cmd.equals(\"start\")) {\n                if (peer != null) {\n                    peer.shutdown();\n                }\n                peer = null;\n                try {\n                    for(int i = 0; i < 5; i++) {\n                        Thread.sleep(500);\n                        try {\n                            // Wait until we can't connect\n                            new Socket(\"127.0.0.1\", clientAddr.getPort()).close();\n                        } catch(IOException e) { break; }\n                    }\n                    r.report(\"stopped\");\n                } catch (Exception e) {\n                    LOG.error(\"Unhandled error\", e);\n                }\n                return;\n            }\n            String parts[] = quorumSpecs.split(\",\");\n            peers = new HashMap<Long,QuorumServer>();\n            for(int i = 0; i < parts.length; i++) {\n                String subparts[] = parts[i].split(\":\");\n                peers.put(Long.valueOf(i), new QuorumServer(i, subparts[0], Integer.parseInt(subparts[1]), 0, null));\n            }\n            try {\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Starting quorumPeer \" + serverId + \" on port \" + clientAddr.getPort());\n                }\n                if (peer != null) {\n                    LOG.warn(\"Peer \" + serverId + \" already started\");\n                    return;\n                }\n                System.err.println(\"SnapDir = \" + snapDir + \" LogDir = \" + logDir);\n                peer = new QuorumPeer(peers, snapDir, logDir, clientAddr.getPort(), 0, serverId, tickTime, initLimit, syncLimit);\n                peer.start();\n                for(int i = 0; i < 5; i++) {\n                    Thread.sleep(500);\n                    try {\n                        // Wait until we can connect\n                        new Socket(\"127.0.0.1\", clientAddr.getPort()).close();\n                        break;\n                    } catch(IOException e) {}\n                }\n                r.report(\"started\");\n            } catch (Exception e) {\n                LOG.error(\"Unhandled exception\", e);\n            }\n        }\n    }\n\n    public void start() {\n    }\n\n    static private void recursiveDelete(File dir) {\n        if (!dir.isDirectory()) {\n            dir.delete();\n            return;\n        }\n        for(File f: dir.listFiles()) {\n            recursiveDelete(f);\n        }\n        dir.delete();\n    }\n    \n    public void stop() {\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Stopping peer \" + serverId);\n        }\n        if (peer != null) {\n            peer.shutdown();\n        }\n        if (logDir != null) {\n            recursiveDelete(logDir);\n        }\n        if (snapDir != null) {\n            recursiveDelete(snapDir);\n        }\n    }\n\n    /**\n     * This method is used to configure a QuorumPeerInstance\n     * \n     * @param im the InstanceManager that will be managing the new instance\n     * @param i the server number to configure (should be zero based)\n     * @throws NoAvailableContainers\n     * @throws DuplicateNameException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    public static String[] createServer(InstanceManager im, int i) throws NoAvailableContainers, DuplicateNameException, InterruptedException, KeeperException {\n        return createServer(im, i, true);\n    }\n    \n    /**\n     * This method is used to configure a QuorumPeerInstance\n     * \n     * @param im the InstanceManager that will be managing the new instance\n     * @param i the server number to configure (should be zero based)\n     * @param leaderServes if false, the leader will not accept client connections\n     * @throws NoAvailableContainers\n     * @throws DuplicateNameException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    public static String[] createServer(InstanceManager im, int i, boolean leaderServes) throws NoAvailableContainers, DuplicateNameException, InterruptedException, KeeperException {\n        im.assignInstance(\"server\"+i, QuorumPeerInstance.class, Integer.toString(i) + \" \" + leaderServes, 50);\n        return im.getStatus(\"server\"+i, 3000).split(\",\");\n        \n    }\n\n    /**\n     * Start an instance of the quorumPeer.\n     * @param im the manager of the instance\n     * @param quorumHostPort the comma-separated list of host:port pairs of quorum peers \n     * @param index the zero based index of the server to start.\n     * @throws InterruptedException\n     * @throws KeeperException\n     * @throws NoAssignmentException\n     */\n    public static void startInstance(InstanceManager im, String quorumHostPort, int index) throws InterruptedException, KeeperException, NoAssignmentException {\n        im.resetStatus(\"server\" + index);\n        im.reconfigureInstance(\"server\"+index, quorumHostPort + \" start\");\n        im.getStatus(\"server\" + index, 5000);\n    }\n\n    /**\n     * Stop an instance of the quorumPeer\n     * @param im the manager of the instance\n     * @param index the zero based index fo the server to stop\n     * @throws InterruptedException\n     * @throws KeeperException\n     * @throws NoAssignmentException\n     */\n    public static void stopInstance(InstanceManager im, int index) throws InterruptedException, KeeperException, NoAssignmentException {\n        im.resetStatus(\"server\" + index);\n        im.reconfigureInstance(\"server\"+index, Integer.toString(index) + \" stop\");\n        im.getStatus(\"server\" + index, 3000);\n   \n    }\n\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/SimpleClient.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * The client that gets spawned for the SimpleSysTest \n *\n */\npublic class SimpleClient implements Instance, Watcher, AsyncCallback.DataCallback, StringCallback, StatCallback {\n    private static final long serialVersionUID = 1L;\n    String hostPort;\n    ZooKeeper zk;\n    transient int index;\n    transient String myPath;\n    byte data[];\n    boolean createdEphemeral;\n    public void configure(String params) {\n        String parts[] = params.split(\" \");\n        hostPort = parts[1];\n        this.index = Integer.parseInt(parts[0]);\n        myPath = \"/simpleCase/\" + index;\n    }\n    \n    public void start() {\n        try {\n            zk = new ZooKeeper(hostPort, 15000, this);\n            zk.getData(\"/simpleCase\", true, this, null);\n            if (null != r) {\n                r.report(\"Client \" + index + \" connecting to \" + hostPort);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n    \n    public void stop() {\n        try {\n            if (zk != null) {\n                zk.close();\n            }\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n    public void process(WatchedEvent event) {\n        if (event.getPath() != null && event.getPath().equals(\"/simpleCase\")) {\n            zk.getData(\"/simpleCase\", true, this, null);\n        }\n    }\n    \n    public void processResult(int rc, String path, Object ctx, byte[] data,\n            Stat stat) {\n        if (rc != 0) {\n            zk.getData(\"/simpleCase\", true, this, null);\n        } else {\n            this.data = data;\n            String content = new String(data);\n            if (content.equals(\"die\")) {\n                this.stop();\n                return;\n            }\n            if (!createdEphemeral) {\n                zk.create(myPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, this, null);\n                createdEphemeral = true;\n            } else {\n                zk.setData(myPath, data, -1, this, null);\n            }\n        }            \n    }\n    \n    public void processResult(int rc, String path, Object ctx, String name) {\n        if (rc != 0) {\n            zk.create(myPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, this, null);\n        }\n    }\n    public void processResult(int rc, String path, Object ctx, Stat stat) {\n        if (rc != 0) {\n            zk.setData(myPath, data, -1, this, null);\n        }\n    }\n    @Override\n    public String toString() {\n        return SimpleClient.class.getName() + \"[\" + index + \"] using \" + hostPort;\n    }\n    \n    Reporter r;\n    public void setReporter(Reporter r) {\n        this.r = r;\n    }\n}\n"
  },
  {
    "path": "src/java/systest/org/apache/zookeeper/test/system/SimpleSysTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test.system;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Test;\n\n/**\n * This does a basic system test. It starts up an ensemble of servers and a set of clients.\n * It makes sure that all the clients come up. It kills off servers while making a change and\n * then ensures that all clients see the change. And then signals the clients to die and\n * watches them disappear.\n *\n */\npublic class SimpleSysTest extends BaseSysTest implements Watcher {\n    int maxTries = 10;\n    boolean connected;\n    final private static Logger LOG = LoggerFactory.getLogger(SimpleSysTest.class);\n    \n    synchronized private boolean waitForConnect(ZooKeeper zk, long timeout) throws InterruptedException {\n        connected = (zk.getState() == States.CONNECTED);\n        long end = System.currentTimeMillis() + timeout;\n        while(!connected && end > System.currentTimeMillis()) {\n            wait(timeout);\n            connected = (zk.getState() == States.CONNECTED);\n        }\n        return connected;\n    }\n    \n    /**\n     * This test checks the following:\n     * 1) All clients connect successfully\n     * 2) Half of the servers die (assuming odd number) and a write succeeds\n     * 3) All servers are restarted and cluster stays alive\n     * 4) Clients see a change by the server\n     * 5) Clients' ephemeral nodes are cleaned up\n     * \n     * @throws Exception\n     */\n    @Test\n    public void testSimpleCase() throws Exception {\n        configureServers(serverCount);\n        configureClients(clientCount, SimpleClient.class, getHostPort());\n        Stat stat = new Stat();\n        startServers();\n        LOG.debug(\"Connecting to \" + getHostPort());\n        ZooKeeper zk = new ZooKeeper(getHostPort(), 15000, this);\n        waitForConnect(zk, 10000);\n        zk.create(\"/simpleCase\", \"orig\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        startClients();\n        \n        // Check that all clients connect properly\n        for(int i = 0; i < getClientCount(); i++) {\n            for(int j = 0; j < maxTries; j++) {\n                try {\n                    byte b[] = zk.getData(\"/simpleCase/\" + i, false, stat);\n                    assertEquals(\"orig\", new String(b));\n                } catch(NoNodeException e) {\n                    if (j+1 == maxTries) {\n                        fail(\"Max tries exceeded on client \" + i);\n                    }\n                    Thread.sleep(1000);\n                }\n            }\n        }\n        \n        // Kill half the servers, make a change, restart the dead\n        // servers, and then bounce the other servers one by one\n        for(int i = 0; i < getServerCount(); i++) {\n            stopServer(i);\n            if (i+1 > getServerCount()/2) {\n                startServer(i);\n            } else if (i+1 == getServerCount()/2) {\n                assertTrue(\"Connection didn't recover\", waitForConnect(zk, 10000));\n                try {\n                    zk.setData(\"/simpleCase\", \"new\".getBytes(), -1);\n                } catch(ConnectionLossException e) {\n                    assertTrue(\"Connection didn't recover\", waitForConnect(zk, 10000));\n                    zk.setData(\"/simpleCase\", \"new\".getBytes(), -1);\n                }\n                for(int j = 0; j < i; j++) {\n                    LOG.info(\"Starting server \" + j);\n                    startServer(i);\n                }\n            }\n        }\n        Thread.sleep(100); // wait for things to stabilize\n        assertTrue(\"Servers didn't bounce\", waitForConnect(zk, 15000));\n        try {\n            zk.getData(\"/simpleCase\", false, stat);\n        } catch(ConnectionLossException e) {\n            assertTrue(\"Servers didn't bounce\", waitForConnect(zk, 15000));\n        }\n        \n        // check that the change has propagated to everyone\n        for(int i = 0; i < getClientCount(); i++) {\n            for(int j = 0; j < maxTries; j++) {\n                byte data[] = zk.getData(\"/simpleCase/\" + i, false, stat);\n                if (new String(data).equals(\"new\")) {\n                    break;\n                }\n                if (j+1 == maxTries) {\n                    fail(\"max tries exceeded for \" + i);\n                }\n                Thread.sleep(1000);\n            }\n        }\n        \n        // send out the kill signal\n        zk.setData(\"/simpleCase\", \"die\".getBytes(), -1);\n        \n        // watch for everyone to die\n        for(int i = 0; i < getClientCount(); i++) {\n            try {\n                for(int j = 0; j < maxTries; j++) {\n                    zk.getData(\"/simpleCase/\" + i, false, stat);\n                    if (j+1 == maxTries) {\n                        fail(\"max tries exceeded waiting for child \" + i + \" to die\");\n                    }\n                    Thread.sleep(200);\n                }\n            } catch(NoNodeException e) {\n                // Great this is what we were hoping for!\n            }\n        }\n        \n        stopClients();\n        stopServers();\n    }\n\n    public void process(WatchedEvent event) {\n        if (event.getState() == KeeperState.SyncConnected) {\n            synchronized(this) {\n                connected = true;\n                notifyAll();\n            }\n        } else if (event.getState() == KeeperState.Disconnected) {\n            synchronized(this) {\n                connected = false;\n                notifyAll();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/bin/check_compatibility.py",
    "content": "#!/usr/bin/env python\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n\n# Script which checks Java API compatibility between two revisions of the\n# Java client.\n#\n# Based on the compatibility checker from the HBase project, but ported to\n# Python for better readability.\n\n# Lifted from Kudu: https://github.com/apache/kudu/blob/master/build-support/check_compatibility.py\n\nimport logging\nimport optparse\nimport os\nimport shutil\nimport subprocess\nimport sys\n\nJAVA_ACC_GIT_URL = \"https://github.com/lvc/japi-compliance-checker.git\"\n\n# The annotations for what we consider our public API.\nPUBLIC_ANNOTATIONS = [\"org.apache.yetus.audience.InterfaceAudience.LimitedPrivate\",\n                      \"org.apache.yetus.audience.InterfaceAudience.Public\"]\n\n# Various relative paths\nPATH_TO_REPO_DIR = \"../../../../\"\nPATH_TO_BUILD_DIR = PATH_TO_REPO_DIR + \"build/compat-check\"\nPATH_TO_JACC_DIR = PATH_TO_REPO_DIR + \"build/jacc\"\n\ndef check_output(*popenargs, **kwargs):\n    # r\"\"\"Run command with arguments and return its output as a byte string.\n    # Backported from Python 2.7 as it's implemented as pure python on stdlib.\n    # >>> check_output(['/usr/bin/python', '--version'])\n    # Python 2.6.2\n    # \"\"\"\n    process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)\n    output, unused_err = process.communicate()\n    retcode = process.poll()\n    if retcode:\n        cmd = kwargs.get(\"args\")\n        if cmd is None:\n            cmd = popenargs[0]\n        error = subprocess.CalledProcessError(retcode, cmd)\n        error.output = output\n        raise error\n    return output\n\ndef get_repo_dir():\n    \"\"\" Return the path to the top of the repo. \"\"\"\n    dirname, _ = os.path.split(os.path.abspath(__file__))\n    return os.path.abspath(os.path.join(dirname, PATH_TO_REPO_DIR))\n\n\ndef get_scratch_dir():\n    \"\"\" Return the path to the scratch dir that we build within. \"\"\"\n    dirname, _ = os.path.split(os.path.abspath(__file__))\n    return os.path.abspath(os.path.join(dirname, PATH_TO_BUILD_DIR))\n\n\ndef get_java_acc_dir():\n    dirname, _ = os.path.split(os.path.abspath(__file__))\n    return os.path.abspath(os.path.join(dirname, PATH_TO_JACC_DIR))\n\n\ndef clean_scratch_dir(scratch_dir):\n    \"\"\" Clean up and re-create the scratch directory. \"\"\"\n    if os.path.exists(scratch_dir):\n        logging.info(\"Removing scratch dir %s...\", scratch_dir)\n        shutil.rmtree(scratch_dir)\n    logging.info(\"Creating empty scratch dir %s...\", scratch_dir)\n    os.makedirs(scratch_dir)\n\n\ndef checkout_tree(rev, path):\n    \"\"\" Check out the Java source tree for the given revision into the given path. \"\"\"\n    logging.info(\"Checking out %s in %s\", rev, path)\n    os.makedirs(path)\n    # Extract java source\n    subprocess.check_call([\"bash\", '-o', 'pipefail', \"-c\",\n                           (\"git archive --format=tar %s | \" +\n                            \"tar -C \\\"%s\\\" -xf -\") % (rev, path)],\n                          cwd=get_repo_dir())\n\n\ndef get_git_hash(revname):\n    \"\"\" Convert 'revname' to its SHA-1 hash. \"\"\"\n    return check_output([\"git\", \"rev-parse\", revname],\n                        cwd=get_repo_dir()).strip()\n\n\ndef build_tree(path):\n    \"\"\" Run the Java build within 'path'. \"\"\"\n    logging.info(\"Building in %s...\", path)\n    subprocess.check_call([\"ant\", \"jar\"], cwd=path)\n\n\ndef checkout_java_acc(force):\n    \"\"\"\n    Check out the Java API Compliance Checker. If 'force' is true, will re-download even if the\n    directory exists.\n    \"\"\"\n    acc_dir = get_java_acc_dir()\n    if os.path.exists(acc_dir):\n        logging.info(\"Java JAVA_ACC is already downloaded.\")\n        if not force:\n            return\n        logging.info(\"Forcing re-download.\")\n        shutil.rmtree(acc_dir)\n    logging.info(\"Checking out Java JAVA_ACC...\")\n    subprocess.check_call([\"git\", \"clone\", \"-b\", \"2.1\", \"--single-branch\", \"--depth=1\", JAVA_ACC_GIT_URL, acc_dir])\n\n\ndef find_client_jars(path):\n    \"\"\" Return a list of jars within 'path' to be checked for compatibility. \"\"\"\n    return check_output([\"find\", path, \"-name\", \"zookeeper*.jar\"]).rstrip('\\n')\n\n\ndef run_java_acc(src_name, src, dst_name, dst):\n    \"\"\" Run the compliance checker to compare 'src' and 'dst'. \"\"\"\n    src_jar = find_client_jars(src)\n    dst_jar = find_client_jars(dst)\n    logging.info(\"Will check compatibility between original jars:\\n%s\\n\" +\n                 \"and new jars:\\n%s\",\n                 src_jar, dst_jar)\n\n    annotations_path = os.path.join(get_scratch_dir(), \"annotations.txt\")\n    with file(annotations_path, \"w\") as f:\n        for ann in PUBLIC_ANNOTATIONS:\n            print >>f,  ann\n\n    java_acc_path = os.path.join(get_java_acc_dir(), \"japi-compliance-checker.pl\")\n\n    out_path = os.path.join(get_scratch_dir(), \"report.html\")\n    subprocess.check_call([\"perl\", java_acc_path,\n                           \"-lib\", \"ZooKeeper\",\n                           \"-v1\", src_name,\n                           \"-v2\", dst_name,\n                           \"-d1\", src_jar,\n                           \"-d2\", dst_jar,\n                           \"-annotations-list\", annotations_path,\n                           \"-report-path\", out_path])\n\n\ndef main(argv):\n    logging.basicConfig(level=logging.INFO)\n    parser = optparse.OptionParser(\n        usage=\"usage: %prog SRC..[DST]\")\n    parser.add_option(\"-f\", \"--force-download\", dest=\"force_download_deps\",\n                      help=(\"Download dependencies (i.e. Java JAVA_ACC) even if they are \" +\n                            \"already present\"))\n    opts, args = parser.parse_args()\n\n    if len(args) != 1:\n        parser.error(\"no src/dst revision specified\")\n        sys.exit(1)\n\n    src_rev, dst_rev = args[0].split(\"..\", 1)\n    if dst_rev == \"\":\n        dst_rev = \"HEAD\"\n    src_rev = get_git_hash(src_rev)\n    dst_rev = get_git_hash(dst_rev)\n\n    logging.info(\"Source revision: %s\", src_rev)\n    logging.info(\"Destination revision: %s\", dst_rev)\n\n    # Download deps.\n    checkout_java_acc(opts.force_download_deps)\n\n    # Set up the build.\n    scratch_dir = get_scratch_dir()\n    clean_scratch_dir(scratch_dir)\n\n    # Check out the src and dst source trees.\n    src_dir = os.path.join(scratch_dir, \"src\")\n    dst_dir = os.path.join(scratch_dir, \"dst\")\n    checkout_tree(src_rev, src_dir)\n    checkout_tree(dst_rev, dst_dir)\n\n    # Run the build in each.\n    build_tree(src_dir)\n    build_tree(dst_dir)\n\n    run_java_acc(src_rev, src_dir + \"/build\",\n                 dst_rev, dst_dir + \"/build\")\n\n\nif __name__ == \"__main__\":\n    main(sys.argv)"
  },
  {
    "path": "src/java/test/bin/test-github-pr.sh",
    "content": "#!/usr/bin/env bash\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n\n\n#set -x\n\n### Setup some variables.\n### GIT_COMMIT and BUILD_URL are set by Hudson if it is run by patch process\n### Read variables from properties file\n. `dirname $0`/test-patch.properties\n\n###############################################################################\nparseArgs() {\n  case \"$1\" in\n    QABUILD)\n      ### Set QABUILD to true to indicate that this script is being run by Hudson\n      QABUILD=true\n      if [[ $# != 14 ]] ; then\n        echo \"ERROR: usage $0 QABUILD <PATCH_DIR> <PS_CMD> <WGET_CMD> <JIRACLI> <GIT_CMD> <GREP_CMD> <PATCH_CMD> <FINDBUGS_HOME> <FORREST_HOME> <WORKSPACE_BASEDIR> <JIRA_PASSWD> <JAVA5_HOME> <CURL_CMD>\"\n        cleanupAndExit 0\n      fi\n      PATCH_DIR=$2\n      PS=$3\n      WGET=$4\n      JIRACLI=$5\n      GIT=$6\n      GREP=$7\n      PATCH=$8\n      FINDBUGS_HOME=$9\n      FORREST_HOME=${10}\n      BASEDIR=${11}\n      JIRA_PASSWD=${12}\n      JAVA5_HOME=${13}\n      CURL=${14}\n      if [ ! -e \"$PATCH_DIR\" ] ; then\n        mkdir -p $PATCH_DIR\n      fi\n\n      ## Obtain PR number and title\n      PULLREQUEST_ID=${GIT_PR_NUMBER}\n      PULLREQUEST_TITLE=\"${GIT_PR_TITLE}\"\n\n      ## Extract jira number from PR title\n      local prefix=${PULLREQUEST_TITLE%ZOOKEEPER\\-[0-9]*}\n      local noprefix=${PULLREQUEST_TITLE#$prefix}\n      local regex='\\(ZOOKEEPER-.[0-9]*\\)'\n      defect=$(expr \"$noprefix\" : ${regex})\n\n      echo \"Pull request id: ${PULLREQUEST_ID}\"\n      echo \"Pull request title: ${PULLREQUEST_TITLE}\"\n      echo \"Defect number: ${defect}\"\n\n      JIRA_COMMENT=\"GitHub Pull Request ${PULLREQUEST_NUMBER} Build\n      \"\n      ;;\n    DEVELOPER)\n      ### Set QABUILD to false to indicate that this script is being run by a developer\n      QABUILD=false\n      if [[ $# != 10 ]] ; then\n        echo \"ERROR: usage $0 DEVELOPER <GIT_PR_URL> <SCRATCH_DIR> <GIT_CMD> <GREP_CMD> <PATCH_CMD> <FINDBUGS_HOME> <FORREST_HOME> <WORKSPACE_BASEDIR> <JAVA5_HOME>\"\n        cleanupAndExit 0\n      fi\n      PATCH_DIR=$3\n      PATCH_FILE=${PATCH_DIR}/patch\n      curl -L $2.diff > ${PATCH_FILE}\n      ### PATCH_FILE contains the location of the patchfile\n      if [[ ! -e \"$PATCH_FILE\" ]] ; then\n        echo \"Unable to locate the patch file $PATCH_FILE\"\n        cleanupAndExit 0\n      fi\n      ### Check if $PATCH_DIR exists. If it does not exist, create a new directory\n      if [[ ! -e \"$PATCH_DIR\" ]] ; then\n\tmkdir \"$PATCH_DIR\"\n\tif [[ $? == 0 ]] ; then\n\t  echo \"$PATCH_DIR has been created\"\n\telse\n\t  echo \"Unable to create $PATCH_DIR\"\n\t  cleanupAndExit 0\n\tfi\n      fi\n      GIT=$4\n      GREP=$5\n      PATCH=$6\n      FINDBUGS_HOME=$7\n      FORREST_HOME=$8\n      BASEDIR=$9\n      JAVA5_HOME=${10}\n      ### Obtain the patch filename to append it to the version number\n      local subject=`grep \"Subject:\" ${PATCH_FILE}`\n      local length=`expr match ${subject} ZOOKEEPER-[0-9]*`\n      local position=`expr index ${subject} ZOOKEEPER-`\n      defect=${${subject:$position:$length}#ZOOKEEPER-}\n      ;;\n    *)\n      echo \"ERROR: usage $0 QABUILD [args] | DEVELOPER [args]\"\n      cleanupAndExit 0\n      ;;\n  esac\n}\n\n###############################################################################\ncheckout () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Testing patch for pull request ${PULLREQUEST_ID}.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  ### When run by a developer, if the workspace contains modifications, do not continue\n  # Ref http://stackoverflow.com/a/2659808 for details on checking dirty status\n  ${GIT} diff-index --quiet HEAD\n  if [[ $? -ne 0 ]] ; then\n    uncommitted=`${GIT} diff --name-only HEAD`\n    uncommitted=\"You have the following files with uncommitted changes:${NEWLINE}${uncommitted}\"\n  fi\n  untracked=\"$(${GIT} ls-files --exclude-standard --others)\" && test -z \"${untracked}\"\n  if [[ $? -ne 0 ]] ; then\n    untracked=\"You have untracked and unignored files:${NEWLINE}${untracked}\"\n  fi\n\n  if [[ $QABUILD == \"false\" ]] ; then\n    if [[ $uncommitted || $untracked ]] ; then\n      echo \"ERROR: can't run in a workspace that contains the following modifications\"\n      echo \"\"\n      echo \"${uncommitted}\"\n      echo \"\"\n      echo \"${untracked}\"\n      cleanupAndExit 1\n    fi\n  else\n    # I don't believe we need to do anything here - the jenkins job will\n    # cleanup the environment for us (\"cleanup before checkout\" action)\n    # on the precommit jenkins job\n    echo\n  fi\n  return $?\n}\n\n###############################################################################\nsetup () {\n  ### exit if warnings are NOT defined in the properties file\n  if [ -z \"$OK_FINDBUGS_WARNINGS\" ] || [[ -z \"$OK_JAVADOC_WARNINGS\" ]] || [[ -z $OK_RELEASEAUDIT_WARNINGS ]]; then\n    echo \"Please define the following properties in test-patch.properties file\"\n\t echo  \"OK_FINDBUGS_WARNINGS\"\n\t echo  \"OK_RELEASEAUDIT_WARNINGS\"\n\t echo  \"OK_JAVADOC_WARNINGS\"\n    cleanupAndExit 1\n  fi\n  ### get pull request diff\n  ${CURL} -L ${GIT_PR_URL}.diff > $PATCH_DIR/patch\n\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \" Pre-build trunk to verify trunk stability and javac warnings\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant  -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/trunkJavacWarnings.txt 2>&1\"\n $ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/trunkJavacWarnings.txt 2>&1\n  if [[ $? != 0 ]] ; then\n    echo \"Trunk compilation is broken?\"\n    cleanupAndExit 1\n  fi\n}\n\n###############################################################################\n### Check for @author tags in the patch\ncheckAuthor () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Checking there are no @author tags in the patch.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  authorTags=`$GREP -c -i '@author' $PATCH_DIR/patch`\n  echo \"There appear to be $authorTags @author tags in the patch.\"\n  if [[ $authorTags != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 @author.  The patch appears to contain $authorTags @author tags which the Zookeeper community has agreed to not allow in code contributions.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 @author.  The patch does not contain any @author tags.\"\n  return 0\n}\n\n###############################################################################\n### Check for tests in the patch\ncheckTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Checking there are new or changed tests in the patch.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  testReferences=`$GREP -c -i '/test' $PATCH_DIR/patch`\n  echo \"There appear to be $testReferences test files referenced in the patch.\"\n  if [[ $testReferences == 0 ]] ; then\n    if [[ $QABUILD == \"true\" ]] ; then\n      patchIsDoc=`$GREP -c -i 'title=\"documentation' $PATCH_DIR/jira`\n      if [[ $patchIsDoc != 0 ]] ; then\n        echo \"The patch appears to be a documentation patch that doesn't require tests.\"\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +0 tests included.  The patch appears to be a documentation patch that doesn't require tests.\"\n        return 0\n      fi\n    fi\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 tests included.  The patch doesn't appear to include any new or modified tests.\n                        Please justify why no new tests are needed for this patch.\n                        Also please list what manual steps were performed to verify this patch.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 tests included.  The patch appears to include $testReferences new or modified tests.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no javadoc warnings\ncheckJavadocWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched javadoc warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= clean javadoc | tee $PATCH_DIR/patchJavadocWarnings.txt\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= clean javadoc | tee $PATCH_DIR/patchJavadocWarnings.txt\n  javadocWarnings=`$GREP -o '\\[javadoc\\] [0-9]* warning' $PATCH_DIR/patchJavadocWarnings.txt | awk '{total += $2} END {print total}'`\n  echo \"\"\n  echo \"\"\n  echo \"There appear to be $javadocWarnings javadoc warnings generated by the patched build.\"\n\n  ### if current warnings greater than OK_JAVADOC_WARNINGS\n  if [[ $javadocWarnings > $OK_JAVADOC_WARNINGS ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javadoc.  The javadoc tool appears to have generated `expr $(($javadocWarnings-$OK_JAVADOC_WARNINGS))` warning messages.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 javadoc.  The javadoc tool did not generate any warning messages.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Javac warnings\ncheckJavacWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched javac warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/patchJavacWarnings.txt 2>&1\"\n  $ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/patchJavacWarnings.txt 2>&1\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javac.  The patch appears to cause tar ant target to fail.\"\n    return 1\n  fi\n  ### Compare trunk and patch javac warning numbers\n  if [[ -f $PATCH_DIR/patchJavacWarnings.txt ]] ; then\n    trunkJavacWarnings=`$GREP -o '\\[javac\\] [0-9]* warning' $PATCH_DIR/trunkJavacWarnings.txt | awk '{total += $2} END {print total}'`\n    patchJavacWarnings=`$GREP -o '\\[javac\\] [0-9]* warning' $PATCH_DIR/patchJavacWarnings.txt | awk '{total += $2} END {print total}'`\n    echo \"There appear to be $trunkJavacWarnings javac compiler warnings before the patch and $patchJavacWarnings javac compiler warnings after applying the patch.\"\n    if [[ $patchJavacWarnings != \"\" && $trunkJavacWarnings != \"\" ]] ; then\n      if [[ $patchJavacWarnings -gt $trunkJavacWarnings ]] ; then\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javac.  The applied patch generated $patchJavacWarnings javac compiler warnings (more than the trunk's current $trunkJavacWarnings warnings).\"\n        return 1\n      fi\n    fi\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 javac.  The applied patch does not increase the total number of javac compiler warnings.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of release audit (RAT) warnings\ncheckReleaseAuditWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched release audit warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= releaseaudit > $PATCH_DIR/patchReleaseAuditWarnings.txt 2>&1\"\n  $ANT_HOME/bin/ant -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= releaseaudit > $PATCH_DIR/patchReleaseAuditWarnings.txt 2>&1\n\n  ### Compare trunk and patch release audit warning numbers\n  if [[ -f $PATCH_DIR/patchReleaseAuditWarnings.txt ]] ; then\n    patchReleaseAuditWarnings=`$GREP -c '\\!?????' $PATCH_DIR/patchReleaseAuditWarnings.txt`\n    echo \"\"\n    echo \"\"\n    echo \"There appear to be $OK_RELEASEAUDIT_WARNINGS release audit warnings before the patch and $patchReleaseAuditWarnings release audit warnings after applying the patch.\"\n    if [[ $patchReleaseAuditWarnings != \"\" && $OK_RELEASEAUDIT_WARNINGS != \"\" ]] ; then\n      if [[ $patchReleaseAuditWarnings -gt $OK_RELEASEAUDIT_WARNINGS ]] ; then\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 release audit.  The applied patch generated $patchReleaseAuditWarnings release audit warnings (more than the trunk's current $OK_RELEASEAUDIT_WARNINGS warnings).\"\n        $GREP '\\!?????' $PATCH_DIR/patchReleaseAuditWarnings.txt > $PATCH_DIR/patchReleaseAuditProblems.txt\n        echo \"Lines that start with ????? in the release audit report indicate files that do not have an Apache license header.\" >> $PATCH_DIR/patchReleaseAuditProblems.txt\n        JIRA_COMMENT_FOOTER=\"Release audit warnings: $BUILD_URL/artifact/trunk/patchprocess/patchReleaseAuditProblems.txt\n$JIRA_COMMENT_FOOTER\"\n        return 1\n      fi\n    fi\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 release audit.  The applied patch does not increase the total number of release audit warnings.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Checkstyle warnings\ncheckStyle () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched checkstyle warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"THIS IS NOT IMPLEMENTED YET\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= checkstyle\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= checkstyle\n  JIRA_COMMENT_FOOTER=\"Checkstyle results: $BUILD_URL/artifact/trunk/build/test/checkstyle-errors.html\n$JIRA_COMMENT_FOOTER\"\n  ### TODO: calculate actual patchStyleErrors\n#  patchStyleErrors=0\n#  if [[ $patchStyleErrors != 0 ]] ; then\n#    JIRA_COMMENT=\"$JIRA_COMMENT\n#\n#    -1 checkstyle.  The patch generated $patchStyleErrors code style errors.\"\n#    return 1\n#  fi\n#  JIRA_COMMENT=\"$JIRA_COMMENT\n#\n#    +1 checkstyle.  The patch generated 0 code style errors.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Findbugs warnings\ncheckFindbugsWarnings () {\n  findbugs_version=`${FINDBUGS_HOME}/bin/findbugs -version`\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched Findbugs warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Dfindbugs.home=$FINDBUGS_HOME -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= findbugs\"\n  $ANT_HOME/bin/ant -Dfindbugs.home=$FINDBUGS_HOME -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= findbugs\n  if [ $? != 0 ] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 findbugs.  The patch appears to cause Findbugs (version ${findbugs_version}) to fail.\"\n    return 1\n  fi\nJIRA_COMMENT_FOOTER=\"Findbugs warnings: $BUILD_URL/artifact/trunk/build/test/findbugs/newPatchFindbugsWarnings.html\n$JIRA_COMMENT_FOOTER\"\n  cp $BASEDIR/build/test/findbugs/*.xml $PATCH_DIR/patchFindbugsWarnings.xml\n  $FINDBUGS_HOME/bin/setBugDatabaseInfo -timestamp \"01/01/2000\" \\\n    $PATCH_DIR/patchFindbugsWarnings.xml \\\n    $PATCH_DIR/patchFindbugsWarnings.xml\n  findbugsWarnings=`$FINDBUGS_HOME/bin/filterBugs -first \"01/01/2000\" $PATCH_DIR/patchFindbugsWarnings.xml \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml | /usr/bin/awk '{print $1}'`\n  $FINDBUGS_HOME/bin/convertXmlToText -html \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.html\n  cp $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.html $PATCH_DIR/newPatchFindbugsWarnings.html\n  cp $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml $PATCH_DIR/newPatchFindbugsWarnings.xml\n\n  ### if current warnings greater than OK_FINDBUGS_WARNINGS\n  if [[ $findbugsWarnings > $OK_FINDBUGS_WARNINGS ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 findbugs.  The patch appears to introduce `expr $(($findbugsWarnings-$OK_FINDBUGS_WARNINGS))` new Findbugs (version ${findbugs_version}) warnings.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 findbugs.  The patch does not introduce any new Findbugs (version ${findbugs_version}) warnings.\"\n  return 0\n}\n\n###############################################################################\n### Run the test-core target\nrunCoreTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Running core tests.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n\n  ### Kill any rogue build processes from the last attempt\n  $PS auxwww | $GREP ZookeeperPatchProcess | /usr/bin/nawk '{print $2}' | /usr/bin/xargs -t -I {} /bin/kill -9 {} > /dev/null\n\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes -Dtest.junit.threads=8 -Dcompile.c++=yes -Dforrest.home=$FORREST_HOME -Djava5.home=$JAVA5_HOME test-core\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes -Dtest.junit.threads=8 -Dcompile.c++=yes -Dforrest.home=$FORREST_HOME -Djava5.home=$JAVA5_HOME test-core\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 core tests.  The patch failed core unit tests.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 core tests.  The patch passed core unit tests.\"\n  return 0\n}\n\n###############################################################################\n### Run the test-contrib target\nrunContribTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Running contrib tests.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n\n  ### Kill any rogue build processes from the last attempt\n  $PS auxwww | $GREP ZookeeperPatchProcess | /usr/bin/nawk '{print $2}' | /usr/bin/xargs -t -I {} /bin/kill -9 {} > /dev/null\n\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes test-contrib\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes test-contrib\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 contrib tests.  The patch failed contrib unit tests.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 contrib tests.  The patch passed contrib unit tests.\"\n  return 0\n}\n\n###############################################################################\n### Submit a comment to the defect's Jira\nsubmitJiraComment () {\n  local result=$1\n  ### Do not output the value of JIRA_COMMENT_FOOTER when run by a developer\n  if [[  $QABUILD == \"false\" ]] ; then\n    JIRA_COMMENT_FOOTER=\"\"\n  fi\n  if [[ $result == 0 ]] ; then\n    comment=\"+1 overall.  $JIRA_COMMENT\n\n$JIRA_COMMENT_FOOTER\"\n  else\n    comment=\"-1 overall.  $JIRA_COMMENT\n\n$JIRA_COMMENT_FOOTER\"\n  fi\n  ### Output the test result to the console\n  echo \"\n\n\n\n$comment\"\n\n  if [[ $QABUILD == \"true\" ]] ; then\n    echo \"\"\n    echo \"\"\n    echo \"======================================================================\"\n    echo \"======================================================================\"\n    echo \"    Adding comment to Jira.\"\n    echo \"======================================================================\"\n    echo \"======================================================================\"\n    echo \"\"\n    echo \"\"\n    ### Update Jira with a comment\n    export USER=jenkins\n    $JIRACLI -s https://issues.apache.org/jira -a addcomment -u hadoopqa -p $JIRA_PASSWD --comment \"$comment\" --issue $defect\n    $JIRACLI -s https://issues.apache.org/jira -a logout -u hadoopqa -p $JIRA_PASSWD\n  fi\n}\n\n###############################################################################\n### Cleanup files\ncleanupAndExit () {\n  local result=$1\n  if [[ $QABUILD == \"true\" ]] ; then\n    if [ -e \"$PATCH_DIR\" ] ; then\n      mv $PATCH_DIR $BASEDIR\n    fi\n  fi\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Finished build.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  exit $result\n}\n\n###############################################################################\n###############################################################################\n###############################################################################\n\nJIRA_COMMENT=\"\"\nJIRA_COMMENT_FOOTER=\"Console output: $BUILD_URL/console\n\nThis message is automatically generated.\"\n\n### Check if arguments to the script have been specified properly or not\necho \"----- Going to parser args -----\"\nparseArgs $@\ncd $BASEDIR\n\necho \"----- Parsed args, going to checkout -----\"\ncheckout\nRESULT=$?\nif [[ $QABUILD == \"true\" ]] ; then\n  if [[ $RESULT != 0 ]] ; then\n    exit 100\n  fi\nfi\nsetup\ncheckAuthor\n(( RESULT = RESULT + $? ))\n\ncheckTests\ncheckTestsResult=$?\n(( RESULT = RESULT + $checkTestsResult ))\nif [[ $checkTestsResult != 0 ]] ; then\n  submitJiraComment 1\n  cleanupAndExit 1\nfi\ncheckJavadocWarnings\n(( RESULT = RESULT + $? ))\ncheckJavacWarnings\n(( RESULT = RESULT + $? ))\n### Checkstyle not implemented yet\n#checkStyle\n#(( RESULT = RESULT + $? ))\ncheckFindbugsWarnings\n(( RESULT = RESULT + $? ))\ncheckReleaseAuditWarnings\n(( RESULT = RESULT + $? ))\n### Do not call these when run by a developer\nif [[ $QABUILD == \"true\" ]] ; then\n  runCoreTests\n  (( RESULT = RESULT + $? ))\n  runContribTests\n  (( RESULT = RESULT + $? ))\nfi\nJIRA_COMMENT_FOOTER=\"Test results: $BUILD_URL/testReport/\n$JIRA_COMMENT_FOOTER\"\n\nsubmitJiraComment $RESULT\ncleanupAndExit $RESULT\n"
  },
  {
    "path": "src/java/test/bin/test-patch.properties",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nOK_RELEASEAUDIT_WARNINGS=24\nOK_FINDBUGS_WARNINGS=0\nOK_JAVADOC_WARNINGS=0\n"
  },
  {
    "path": "src/java/test/bin/test-patch.sh",
    "content": "#!/usr/bin/env bash\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n\n\n#set -x\nulimit -n 1024\n\n### Setup some variables.  \n### SVN_REVISION and BUILD_URL are set by Hudson if it is run by patch process\n### Read variables from properties file\n. `dirname $0`/test-patch.properties\n\n###############################################################################\nparseArgs() {\n  case \"$1\" in\n    HUDSON)\n      ### Set HUDSON to true to indicate that this script is being run by Hudson\n      HUDSON=true\n      if [[ $# != 15 ]] ; then\n        echo \"ERROR: usage $0 HUDSON <PATCH_DIR> <PS_CMD> <WGET_CMD> <JIRACLI> <SVN_CMD> <GREP_CMD> <PATCH_CMD> <FINDBUGS_HOME> <FORREST_HOME> <WORKSPACE_BASEDIR> <JIRA_PASSWD> <JAVA5_HOME> <CURL_CMD> <DEFECT> \"\n        cleanupAndExit 0\n      fi\n      PATCH_DIR=$2\n      PS=$3\n      WGET=$4\n      JIRACLI=$5\n      SVN=$6\n      GREP=$7\n      PATCH=$8\n      FINDBUGS_HOME=$9\n      FORREST_HOME=${10}\n      BASEDIR=${11}\n      JIRA_PASSWD=${12}\n      JAVA5_HOME=${13}\n      CURL=${14}\n      defect=${15}\n\t\t\n      ### Retrieve the defect number\n      if [ -z \"$defect\" ] ; then\n        echo \"Could not determine the patch to test.  Exiting.\"\n        cleanupAndExit 0\n      fi\n\n      if [ ! -e \"$PATCH_DIR\" ] ; then\n        mkdir -p $PATCH_DIR \n      fi\n\n      ;;\n    DEVELOPER)\n      ### Set HUDSON to false to indicate that this script is being run by a developer\n      HUDSON=false\n      if [[ $# != 10 ]] ; then\n        echo \"ERROR: usage $0 DEVELOPER <PATCH_FILE> <SCRATCH_DIR> <SVN_CMD> <GREP_CMD> <PATCH_CMD> <FINDBUGS_HOME> <FORREST_HOME> <WORKSPACE_BASEDIR> <JAVA5_HOME>\"\n        cleanupAndExit 0\n      fi\n      ### PATCH_FILE contains the location of the patchfile\n      PATCH_FILE=$2 \n      if [[ ! -e \"$PATCH_FILE\" ]] ; then\n        echo \"Unable to locate the patch file $PATCH_FILE\"\n        cleanupAndExit 0\n      fi\n      PATCH_DIR=$3\n      ### Check if $PATCH_DIR exists. If it does not exist, create a new directory\n      if [[ ! -e \"$PATCH_DIR\" ]] ; then\n\tmkdir \"$PATCH_DIR\"\n\tif [[ $? == 0 ]] ; then \n\t  echo \"$PATCH_DIR has been created\"\n\telse\n\t  echo \"Unable to create $PATCH_DIR\"\n\t  cleanupAndExit 0\n\tfi\n      fi\n      SVN=$4\n      GREP=$5\n      PATCH=$6\n      FINDBUGS_HOME=$7\n      FORREST_HOME=$8\n      BASEDIR=$9\n      JAVA5_HOME=${10}\n      ### Obtain the patch filename to append it to the version number\n      defect=`basename $PATCH_FILE` \n      ;;\n    *)\n      echo \"ERROR: usage $0 HUDSON [args] | DEVELOPER [args]\"\n      cleanupAndExit 0\n      ;;\n  esac\n}\n\n###############################################################################\ncheckout () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Testing patch for ${defect}.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  ### When run by a developer, if the workspace contains modifications, do not continue\n  status=`$SVN stat --ignore-externals | sed -e '/^X[ ]*/D'`\n  if [[ $HUDSON == \"false\" ]] ; then\n    if [[ \"$status\" != \"\" ]] ; then\n      echo \"ERROR: can't run in a workspace that contains the following modifications\"\n      echo \"$status\"\n      cleanupAndExit 1\n    fi\n  else   \n    cd $BASEDIR\n    $SVN revert -R .\n    rm -rf `$SVN status --no-ignore`\n    $SVN update\n  fi\n  return $?\n}\n\n###############################################################################\nsetup () {\n  ### Download latest patch file (ignoring .htm and .html) when run from patch process\n  if [[ $HUDSON == \"true\" ]] ; then\n    $WGET -q -O $PATCH_DIR/jira http://issues.apache.org/jira/browse/$defect\n    if [[ `$GREP -c 'Patch Available' $PATCH_DIR/jira` == 0 ]] ; then\n      echo \"$defect is not \\\"Patch Available\\\".  Exiting.\"\n      cleanupAndExit 0\n    fi\n    relativePatchURL=`$GREP -o '\"/jira/secure/attachment/[0-9]*/[^\"]*' $PATCH_DIR/jira | $GREP -v -e 'htm[l]*$' | sort | tail -1 | $GREP -o '/jira/secure/attachment/[0-9]*/[^\"]*'`\n    patchURL=\"http://issues.apache.org${relativePatchURL}\"\n    patchNum=`echo $patchURL | $GREP -o '[0-9]*/' | $GREP -o '[0-9]*'`\n    echo \"$defect patch is being downloaded at `date` from\"\n    echo \"$patchURL\"\n    $WGET -q -O $PATCH_DIR/patch $patchURL\n    JIRA_COMMENT=\"Here are the results of testing the latest attachment \n  $patchURL\n  against trunk revision ${SVN_REVISION}.\"\n\n  ### Copy the patch file to $PATCH_DIR\n  else\n    cp $PATCH_FILE $PATCH_DIR/patch\n    if [[ $? == 0 ]] ; then\n      echo \"Patch file $PATCH_FILE copied to $PATCH_DIR\"\n    else\n      echo \"Could not copy $PATCH_FILE to $PATCH_DIR\"\n      cleanupAndExit 0\n    fi\n  fi\n  ### exit if warnings are NOT defined in the properties file\n  if [ -z \"$OK_FINDBUGS_WARNINGS\" ] || [[ -z \"$OK_JAVADOC_WARNINGS\" ]] || [[ -z $OK_RELEASEAUDIT_WARNINGS ]]; then\n    echo \"Please define the following properties in test-patch.properties file\"\n\t echo  \"OK_FINDBUGS_WARNINGS\"\n\t echo  \"OK_RELEASEAUDIT_WARNINGS\"\n\t echo  \"OK_JAVADOC_WARNINGS\"\n    cleanupAndExit 1\n  fi\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \" Pre-build trunk to verify trunk stability and javac warnings\" \n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant  -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/trunkJavacWarnings.txt 2>&1\"\n $ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/trunkJavacWarnings.txt 2>&1\n  if [[ $? != 0 ]] ; then\n    echo \"Trunk compilation is broken?\"\n    cleanupAndExit 1\n  fi\n}\n\n###############################################################################\n### Check for @author tags in the patch\ncheckAuthor () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Checking there are no @author tags in the patch.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  authorTags=`$GREP -c -i '@author' $PATCH_DIR/patch`\n  echo \"There appear to be $authorTags @author tags in the patch.\"\n  if [[ $authorTags != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 @author.  The patch appears to contain $authorTags @author tags which the Zookeeper community has agreed to not allow in code contributions.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 @author.  The patch does not contain any @author tags.\"\n  return 0\n}\n\n###############################################################################\n### Check for tests in the patch\ncheckTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Checking there are new or changed tests in the patch.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  testReferences=`$GREP -c -i '/test' $PATCH_DIR/patch`\n  echo \"There appear to be $testReferences test files referenced in the patch.\"\n  if [[ $testReferences == 0 ]] ; then\n    if [[ $HUDSON == \"true\" ]] ; then\n      patchIsDoc=`$GREP -c -i 'title=\"documentation' $PATCH_DIR/jira`\n      if [[ $patchIsDoc != 0 ]] ; then\n        echo \"The patch appears to be a documentation patch that doesn't require tests.\"\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +0 tests included.  The patch appears to be a documentation patch that doesn't require tests.\"\n        return 0\n      fi\n    fi\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 tests included.  The patch doesn't appear to include any new or modified tests.\n                        Please justify why no new tests are needed for this patch.\n                        Also please list what manual steps were performed to verify this patch.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 tests included.  The patch appears to include $testReferences new or modified tests.\"\n  return 0\n}\n\n###############################################################################\n### Attempt to apply the patch\napplyPatch () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Applying patch.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  $PATCH -E -p0 < $PATCH_DIR/patch\n  if [[ $? != 0 ]] ; then\n    echo \"PATCH APPLICATION FAILED\"\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 patch.  The patch command could not apply the patch.\"\n    return 1\n  fi\n  return 0\n}\n\n###############################################################################\n### Check there are no javadoc warnings\ncheckJavadocWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched javadoc warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= clean javadoc | tee $PATCH_DIR/patchJavadocWarnings.txt\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= clean javadoc | tee $PATCH_DIR/patchJavadocWarnings.txt\n  javadocWarnings=`$GREP -o '\\[javadoc\\] [0-9]* warning' $PATCH_DIR/patchJavadocWarnings.txt | awk '{total += $2} END {print total}'`\n  echo \"\"\n  echo \"\"\n  echo \"There appear to be $javadocWarnings javadoc warnings generated by the patched build.\"\n\n  ### if current warnings greater than OK_JAVADOC_WARNINGS\n  if [[ $javadocWarnings > $OK_JAVADOC_WARNINGS ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javadoc.  The javadoc tool appears to have generated `expr $(($javadocWarnings-$OK_JAVADOC_WARNINGS))` warning messages.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 javadoc.  The javadoc tool did not generate any warning messages.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Javac warnings\ncheckJavacWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched javac warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/patchJavacWarnings.txt 2>&1\"\n  $ANT_HOME/bin/ant -Djavac.args=\"-Xlint -Xmaxwarns 1000\" -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= clean tar > $PATCH_DIR/patchJavacWarnings.txt 2>&1\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javac.  The patch appears to cause tar ant target to fail.\"\n    return 1\n  fi\n  ### Compare trunk and patch javac warning numbers\n  if [[ -f $PATCH_DIR/patchJavacWarnings.txt ]] ; then\n    trunkJavacWarnings=`$GREP -o '\\[javac\\] [0-9]* warning' $PATCH_DIR/trunkJavacWarnings.txt | awk '{total += $2} END {print total}'`\n    patchJavacWarnings=`$GREP -o '\\[javac\\] [0-9]* warning' $PATCH_DIR/patchJavacWarnings.txt | awk '{total += $2} END {print total}'`\n    echo \"There appear to be $trunkJavacWarnings javac compiler warnings before the patch and $patchJavacWarnings javac compiler warnings after applying the patch.\"\n    if [[ $patchJavacWarnings != \"\" && $trunkJavacWarnings != \"\" ]] ; then\n      if [[ $patchJavacWarnings -gt $trunkJavacWarnings ]] ; then\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 javac.  The applied patch generated $patchJavacWarnings javac compiler warnings (more than the trunk's current $trunkJavacWarnings warnings).\"\n        return 1\n      fi\n    fi\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 javac.  The applied patch does not increase the total number of javac compiler warnings.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of release audit (RAT) warnings\ncheckReleaseAuditWarnings () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched release audit warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= releaseaudit > $PATCH_DIR/patchReleaseAuditWarnings.txt 2>&1\"\n  $ANT_HOME/bin/ant -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= releaseaudit > $PATCH_DIR/patchReleaseAuditWarnings.txt 2>&1\n\n  ### Compare trunk and patch release audit warning numbers\n  if [[ -f $PATCH_DIR/patchReleaseAuditWarnings.txt ]] ; then\n    patchReleaseAuditWarnings=`$GREP -c '\\!?????' $PATCH_DIR/patchReleaseAuditWarnings.txt`\n    echo \"\"\n    echo \"\"\n    echo \"There appear to be $OK_RELEASEAUDIT_WARNINGS release audit warnings before the patch and $patchReleaseAuditWarnings release audit warnings after applying the patch.\"\n    if [[ $patchReleaseAuditWarnings != \"\" && $OK_RELEASEAUDIT_WARNINGS != \"\" ]] ; then\n      if [[ $patchReleaseAuditWarnings -gt $OK_RELEASEAUDIT_WARNINGS ]] ; then\n        JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 release audit.  The applied patch generated $patchReleaseAuditWarnings release audit warnings (more than the trunk's current $OK_RELEASEAUDIT_WARNINGS warnings).\"\n        $GREP '\\!?????' $PATCH_DIR/patchReleaseAuditWarnings.txt > $PATCH_DIR/patchReleaseAuditProblems.txt\n        echo \"Lines that start with ????? in the release audit report indicate files that do not have an Apache license header.\" >> $PATCH_DIR/patchReleaseAuditProblems.txt\n        JIRA_COMMENT_FOOTER=\"Release audit warnings: $BUILD_URL/artifact/trunk/patchprocess/patchReleaseAuditProblems.txt\n$JIRA_COMMENT_FOOTER\"\n        return 1\n      fi\n    fi\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 release audit.  The applied patch does not increase the total number of release audit warnings.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Checkstyle warnings\ncheckStyle () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched checkstyle warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"THIS IS NOT IMPLEMENTED YET\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= checkstyle\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= checkstyle\n  JIRA_COMMENT_FOOTER=\"Checkstyle results: $BUILD_URL/artifact/trunk/build/test/checkstyle-errors.html\n$JIRA_COMMENT_FOOTER\"\n  ### TODO: calculate actual patchStyleErrors\n#  patchStyleErrors=0\n#  if [[ $patchStyleErrors != 0 ]] ; then\n#    JIRA_COMMENT=\"$JIRA_COMMENT\n#\n#    -1 checkstyle.  The patch generated $patchStyleErrors code style errors.\"\n#    return 1\n#  fi\n#  JIRA_COMMENT=\"$JIRA_COMMENT\n#\n#    +1 checkstyle.  The patch generated 0 code style errors.\"\n  return 0\n}\n\n###############################################################################\n### Check there are no changes in the number of Findbugs warnings\ncheckFindbugsWarnings () {\n  findbugs_version=`${FINDBUGS_HOME}/bin/findbugs -version`\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Determining number of patched Findbugs warnings.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  echo \"$ANT_HOME/bin/ant -Dfindbugs.home=$FINDBUGS_HOME -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= findbugs\"\n  $ANT_HOME/bin/ant -Dfindbugs.home=$FINDBUGS_HOME -Djava5.home=${JAVA5_HOME} -Dforrest.home=${FORREST_HOME} -DZookeeperPatchProcess= findbugs\n  if [ $? != 0 ] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 findbugs.  The patch appears to cause Findbugs (version ${findbugs_version}) to fail.\"\n    return 1\n  fi\nJIRA_COMMENT_FOOTER=\"Findbugs warnings: $BUILD_URL/artifact/trunk/build/test/findbugs/newPatchFindbugsWarnings.html\n$JIRA_COMMENT_FOOTER\"\n  cp $BASEDIR/build/test/findbugs/*.xml $PATCH_DIR/patchFindbugsWarnings.xml\n  $FINDBUGS_HOME/bin/setBugDatabaseInfo -timestamp \"01/01/2000\" \\\n    $PATCH_DIR/patchFindbugsWarnings.xml \\\n    $PATCH_DIR/patchFindbugsWarnings.xml\n  findbugsWarnings=`$FINDBUGS_HOME/bin/filterBugs -first \"01/01/2000\" $PATCH_DIR/patchFindbugsWarnings.xml \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml | /usr/bin/awk '{print $1}'`\n  $FINDBUGS_HOME/bin/convertXmlToText -html \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml \\\n    $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.html\n  cp $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.html $PATCH_DIR/newPatchFindbugsWarnings.html\n  cp $BASEDIR/build/test/findbugs/newPatchFindbugsWarnings.xml $PATCH_DIR/newPatchFindbugsWarnings.xml\n\n  ### if current warnings greater than OK_FINDBUGS_WARNINGS\n  if [[ $findbugsWarnings > $OK_FINDBUGS_WARNINGS ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 findbugs.  The patch appears to introduce `expr $(($findbugsWarnings-$OK_FINDBUGS_WARNINGS))` new Findbugs (version ${findbugs_version}) warnings.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 findbugs.  The patch does not introduce any new Findbugs (version ${findbugs_version}) warnings.\"\n  return 0\n}\n\n###############################################################################\n### Run the test-core target\nrunCoreTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Running core tests.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  \n  ### Kill any rogue build processes from the last attempt\n  $PS auxwww | $GREP ZookeeperPatchProcess | /usr/bin/nawk '{print $2}' | /usr/bin/xargs -t -I {} /bin/kill -9 {} > /dev/null\n\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes -Dcompile.c++=yes -Dforrest.home=$FORREST_HOME -Djava5.home=$JAVA5_HOME test-core\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes -Dcompile.c++=yes -Dforrest.home=$FORREST_HOME -Djava5.home=$JAVA5_HOME test-core\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 core tests.  The patch failed core unit tests.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 core tests.  The patch passed core unit tests.\"\n  return 0\n}\n\n###############################################################################\n### Run the test-contrib target\nrunContribTests () {\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Running contrib tests.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n\n  ### Kill any rogue build processes from the last attempt\n  $PS auxwww | $GREP ZookeeperPatchProcess | /usr/bin/nawk '{print $2}' | /usr/bin/xargs -t -I {} /bin/kill -9 {} > /dev/null\n\n  echo \"$ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes test-contrib\"\n  $ANT_HOME/bin/ant -DZookeeperPatchProcess= -Dtest.junit.output.format=xml -Dtest.output=yes test-contrib\n  if [[ $? != 0 ]] ; then\n    JIRA_COMMENT=\"$JIRA_COMMENT\n\n    -1 contrib tests.  The patch failed contrib unit tests.\"\n    return 1\n  fi\n  JIRA_COMMENT=\"$JIRA_COMMENT\n\n    +1 contrib tests.  The patch passed contrib unit tests.\"\n  return 0\n}\n\n###############################################################################\n### Submit a comment to the defect's Jira\nsubmitJiraComment () {\n  local result=$1\n  ### Do not output the value of JIRA_COMMENT_FOOTER when run by a developer\n  if [[  $HUDSON == \"false\" ]] ; then\n    JIRA_COMMENT_FOOTER=\"\"\n  fi\n  if [[ $result == 0 ]] ; then\n    comment=\"+1 overall.  $JIRA_COMMENT\n\n$JIRA_COMMENT_FOOTER\"\n  else\n    comment=\"-1 overall.  $JIRA_COMMENT\n\n$JIRA_COMMENT_FOOTER\"\n  fi\n  ### Output the test result to the console\n  echo \"\n\n\n\n$comment\"  \n\n  if [[ $HUDSON == \"true\" ]] ; then\n    echo \"\"\n    echo \"\"\n    echo \"======================================================================\"\n    echo \"======================================================================\"\n    echo \"    Adding comment to Jira.\"\n    echo \"======================================================================\"\n    echo \"======================================================================\"\n    echo \"\"\n    echo \"\"\n    ### Update Jira with a comment\n    export USER=hudson\n    $JIRACLI -s https://issues.apache.org/jira -a addcomment -u hadoopqa -p $JIRA_PASSWD --comment \"$comment\" --issue $defect\n    $JIRACLI -s https://issues.apache.org/jira -a logout -u hadoopqa -p $JIRA_PASSWD\n  fi\n}\n\n###############################################################################\n### Cleanup files\ncleanupAndExit () {\n  local result=$1\n  if [[ $HUDSON == \"true\" ]] ; then\n    if [ -e \"$PATCH_DIR\" ] ; then\n      mv $PATCH_DIR $BASEDIR\n    fi\n  fi\n  echo \"\"\n  echo \"\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"    Finished build.\"\n  echo \"======================================================================\"\n  echo \"======================================================================\"\n  echo \"\"\n  echo \"\"\n  exit $result\n}\n\n###############################################################################\n###############################################################################\n###############################################################################\n\nJIRA_COMMENT=\"\"\nJIRA_COMMENT_FOOTER=\"Console output: $BUILD_URL/console\n\nThis message is automatically generated.\"\n\n### Check if arguments to the script have been specified properly or not\nparseArgs $@\ncd $BASEDIR\n\ncheckout\nRESULT=$?\nif [[ $HUDSON == \"true\" ]] ; then\n  if [[ $RESULT != 0 ]] ; then\n    exit 100\n  fi\nfi\nsetup\ncheckAuthor\nRESULT=$?\n\ncheckTests\n(( RESULT = RESULT + $? ))\napplyPatch\nif [[ $? != 0 ]] ; then\n  submitJiraComment 1\n  cleanupAndExit 1\nfi\ncheckJavadocWarnings\n(( RESULT = RESULT + $? ))\ncheckJavacWarnings\n(( RESULT = RESULT + $? ))\n### Checkstyle not implemented yet\n#checkStyle\n#(( RESULT = RESULT + $? ))\ncheckFindbugsWarnings\n(( RESULT = RESULT + $? ))\ncheckReleaseAuditWarnings\n(( RESULT = RESULT + $? ))\n### Do not call these when run by a developer \nif [[ $HUDSON == \"true\" ]] ; then\n  runCoreTests\n  (( RESULT = RESULT + $? ))\n  runContribTests\n  (( RESULT = RESULT + $? ))\nfi\nJIRA_COMMENT_FOOTER=\"Test results: $BUILD_URL/testReport/\n$JIRA_COMMENT_FOOTER\"\n\nsubmitJiraComment $RESULT\ncleanupAndExit $RESULT\n"
  },
  {
    "path": "src/java/test/checkstyle-noframes-sorted.xsl",
    "content": "<xsl:stylesheet\txmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n<xsl:output method=\"html\" indent=\"yes\"/>\n<xsl:decimal-format decimal-separator=\".\" grouping-separator=\",\" />\n\n<xsl:key name=\"files\" match=\"file\" use=\"@name\" />\n\n<!-- Checkstyle XML Style Sheet by Stephane Bailliez <sbailliez@apache.org>         -->\n<!-- Part of the Checkstyle distribution found at http://checkstyle.sourceforge.net -->\n<!-- Usage (generates checkstyle_report.html):                                      -->\n<!--    <checkstyle failonviolation=\"false\" config=\"${check.config}\">               -->\n<!--      <fileset dir=\"${src.dir}\" includes=\"**/*.java\"/>                          -->\n<!--      <formatter type=\"xml\" toFile=\"${doc.dir}/checkstyle_report.xml\"/>         -->\n<!--    </checkstyle>                                                               -->\n<!--    <style basedir=\"${doc.dir}\" destdir=\"${doc.dir}\"                            -->\n<!--            includes=\"checkstyle_report.xml\"                                    -->\n<!--            style=\"${doc.dir}/checkstyle-noframes-sorted.xsl\"/>                 -->\n\n<xsl:template match=\"checkstyle\">\n\t<html>\n\t\t<head>\n\t\t<style type=\"text/css\">\n    .bannercell {\n      border: 0px;\n      padding: 0px;\n    }\n    body {\n      margin-left: 10;\n      margin-right: 10;\n      font:normal 80% arial,helvetica,sanserif;\n      background-color:#FFFFFF;\n      color:#000000;\n    }\n    .a td {\n      background: #efefef;\n    }\n    .b td {\n      background: #fff;\n    }\n    th, td {\n      text-align: left;\n      vertical-align: top;\n    }\n    th {\n      font-weight:bold;\n      background: #ccc;\n      color: black;\n    }\n    table, th, td {\n      font-size:100%;\n      border: none\n    }\n    table.log tr td, tr th {\n\n    }\n    h2 {\n      font-weight:bold;\n      font-size:140%;\n      margin-bottom: 5;\n    }\n    h3 {\n      font-size:100%;\n      font-weight:bold;\n      background: #525D76;\n      color: white;\n      text-decoration: none;\n      padding: 5px;\n      margin-right: 2px;\n      margin-left: 2px;\n      margin-bottom: 0;\n    }\n\t\t</style>\n\t\t</head>\n\t\t<body>\n\t\t\t<a name=\"top\"></a>\n      <!-- jakarta logo -->\n      <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n      <tr>\n        <td class=\"bannercell\" rowspan=\"2\">\n          <!--a href=\"http://jakarta.apache.org/\">\n          <img src=\"http://jakarta.apache.org/images/jakarta-logo.gif\" alt=\"http://jakarta.apache.org\" align=\"left\" border=\"0\"/>\n          </a-->\n        </td>\n    \t\t<td class=\"text-align:right\"><h2>CheckStyle Audit</h2></td>\n    \t\t</tr>\n    \t\t<tr>\n    \t\t<td class=\"text-align:right\">Designed for use with <a href='http://checkstyle.sourceforge.net/'>CheckStyle</a> and <a href='http://jakarta.apache.org'>Ant</a>.</td>\n    \t\t</tr>\n      </table>\n    \t<hr size=\"1\"/>\n\n\t\t\t<!-- Summary part -->\n\t\t\t<xsl:apply-templates select=\".\" mode=\"summary\"/>\n\t\t\t<hr size=\"1\" width=\"100%\" align=\"left\"/>\n\n\t\t\t<!-- Package List part -->\n\t\t\t<xsl:apply-templates select=\".\" mode=\"filelist\"/>\n\t\t\t<hr size=\"1\" width=\"100%\" align=\"left\"/>\n\n\t\t\t<!-- For each package create its part -->\n            <xsl:apply-templates select=\"file[@name and generate-id(.) = generate-id(key('files', @name))]\" />\n\n\t\t\t<hr size=\"1\" width=\"100%\" align=\"left\"/>\n\n\n\t\t</body>\n\t</html>\n</xsl:template>\n\n\n\n\t<xsl:template match=\"checkstyle\" mode=\"filelist\">\n\t\t<h3>Files</h3>\n\t\t<table class=\"log\" border=\"0\" cellpadding=\"5\" cellspacing=\"2\" width=\"100%\">\n      <tr>\n        <th>Name</th>\n        <th>Errors</th>\n      </tr>\n          <xsl:for-each select=\"file[@name and generate-id(.) = generate-id(key('files', @name))]\">\n                <xsl:sort data-type=\"number\" order=\"descending\" select=\"count(key('files', @name)/error)\"/>\n\t\t\t\t<xsl:variable name=\"errorCount\" select=\"count(error)\"/>\n\t\t\t\t<tr>\n          <xsl:call-template name=\"alternated-row\"/>\n\t\t\t\t\t<td><a href=\"#f-{@name}\"><xsl:value-of select=\"@name\"/></a></td>\n\t\t\t\t\t<td><xsl:value-of select=\"$errorCount\"/></td>\n\t\t\t\t</tr>\n\t\t\t</xsl:for-each>\n\t\t</table>\n\t</xsl:template>\n\n\n\t<xsl:template match=\"file\">\n    <a name=\"f-{@name}\"></a>\n    <h3>File <xsl:value-of select=\"@name\"/></h3>\n\n    <table class=\"log\" border=\"0\" cellpadding=\"5\" cellspacing=\"2\" width=\"100%\">\n    \t<tr>\n    \t  <th>Error Description</th>\n    \t  <th>Line</th>\n      </tr>\n        <xsl:for-each select=\"key('files', @name)/error\">\n          <xsl:sort data-type=\"number\" order=\"ascending\" select=\"@line\"/>\n    \t<tr>\n        <xsl:call-template name=\"alternated-row\"/>\n    \t  <td><xsl:value-of select=\"@message\"/></td>\n    \t  <td><xsl:value-of select=\"@line\"/></td>\n    \t</tr>\n    \t</xsl:for-each>\n    </table>\n    <a href=\"#top\">Back to top</a>\n\t</xsl:template>\n\n\n\t<xsl:template match=\"checkstyle\" mode=\"summary\">\n\t\t<h3>Summary</h3>\n        <xsl:variable name=\"fileCount\" select=\"count(file[@name and generate-id(.) = generate-id(key('files', @name))])\"/>\n\t\t<xsl:variable name=\"errorCount\" select=\"count(file/error)\"/>\n\t\t<table class=\"log\" border=\"0\" cellpadding=\"5\" cellspacing=\"2\" width=\"100%\">\n\t\t<tr>\n\t\t\t<th>Files</th>\n\t\t\t<th>Errors</th>\n\t\t</tr>\n\t\t<tr>\n\t\t  <xsl:call-template name=\"alternated-row\"/>\n\t\t\t<td><xsl:value-of select=\"$fileCount\"/></td>\n\t\t\t<td><xsl:value-of select=\"$errorCount\"/></td>\n\t\t</tr>\n\t\t</table>\n\t</xsl:template>\n\n  <xsl:template name=\"alternated-row\">\n    <xsl:attribute name=\"class\">\n      <xsl:if test=\"position() mod 2 = 1\">a</xsl:if>\n      <xsl:if test=\"position() mod 2 = 0\">b</xsl:if>\n    </xsl:attribute>\n  </xsl:template>\n</xsl:stylesheet>\n\n\n"
  },
  {
    "path": "src/java/test/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n    \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\"\n    \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n<!--\n  [Forked from Hadoop@2d7363b27360e36fdd62546c0f9d0b1d78133f29]\n\n  Checkstyle configuration for Zookeeper that is based on the sun_checks.xml file\n  that is bundled with Checkstyle and includes checks for:\n\n    - the Java Language Specification at\n      http://java.sun.com/docs/books/jls/second_edition/html/index.html\n\n    - the Sun Code Conventions at http://java.sun.com/docs/codeconv/\n\n    - the Javadoc guidelines at\n      http://java.sun.com/j2se/javadoc/writingdoccomments/index.html\n\n    - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html\n\n    - some best practices\n\n  Checkstyle is very configurable. Be sure to read the documentation at\n  http://checkstyle.sf.net (or in your downloaded distribution).\n\n  Most Checks are configurable, be sure to consult the documentation.\n\n  To completely disable a check, just comment it out or delete it from the file.\n\n  Finally, it is worth reading the documentation.\n\n-->\n\n<module name=\"Checker\">\n\n    <!-- Checks that a package.html file exists for each package.     -->\n    <!-- See http://checkstyle.sf.net/config_javadoc.html#PackageHtml -->\n    <module name=\"JavadocPackage\"/>\n\n    <!-- Checks whether files end with a new line.                        -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->\n    <!-- module name=\"NewlineAtEndOfFile\"/-->\n\n    <!-- Checks that property files contain the same keys.         -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->\n    <module name=\"Translation\"/>\n\n    <module name=\"FileLength\"/>\n    <module name=\"FileTabCharacter\"/>\n\n    <module name=\"TreeWalker\">\n\n        <!-- Checks for Javadoc comments.                     -->\n        <!-- See http://checkstyle.sf.net/config_javadoc.html -->\n        <module name=\"JavadocType\">\n          <property name=\"scope\" value=\"public\"/>\n          <property name=\"allowMissingParamTags\" value=\"true\"/>\n        </module>\n        <module name=\"JavadocStyle\"/>\n\n        <!-- Checks for Naming Conventions.                  -->\n        <!-- See http://checkstyle.sf.net/config_naming.html -->\n        <module name=\"ConstantName\"/>\n        <module name=\"LocalFinalVariableName\"/>\n        <module name=\"LocalVariableName\"/>\n        <module name=\"MemberName\"/>\n        <module name=\"MethodName\"/>\n        <module name=\"PackageName\"/>\n        <module name=\"ParameterName\"/>\n        <module name=\"StaticVariableName\"/>\n        <module name=\"TypeName\"/>\n\n\n        <!-- Checks for Headers                                -->\n        <!-- See http://checkstyle.sf.net/config_header.html   -->\n        <!-- <module name=\"Header\">                            -->\n            <!-- The follow property value demonstrates the ability     -->\n            <!-- to have access to ANT properties. In this case it uses -->\n            <!-- the ${basedir} property to allow Checkstyle to be run  -->\n            <!-- from any directory within a project. See property      -->\n            <!-- expansion,                                             -->\n            <!-- http://checkstyle.sf.net/config.html#properties        -->\n            <!-- <property                                              -->\n            <!--     name=\"headerFile\"                                  -->\n            <!--     value=\"${basedir}/java.header\"/>                   -->\n        <!-- </module> -->\n\n        <!-- Following interprets the header file as regular expressions. -->\n        <!-- <module name=\"RegexpHeader\"/>                                -->\n\n\n        <!-- Checks for imports                              -->\n        <!-- See http://checkstyle.sf.net/config_import.html -->\n        <module name=\"IllegalImport\"/> <!-- defaults to sun.* packages -->\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\"/>\n\n\n        <!-- Checks for Size Violations.                    -->\n        <!-- See http://checkstyle.sf.net/config_sizes.html -->\n        <module name=\"LineLength\">\n          <property name=\"ignorePattern\" value=\"^import\"/>\n        </module>\n        <module name=\"MethodLength\"/>\n        <module name=\"ParameterNumber\"/>\n\n\n        <!-- Checks for whitespace                               -->\n        <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n        <module name=\"EmptyForIteratorPad\"/>\n        <module name=\"MethodParamPad\"/>\n        <module name=\"NoWhitespaceAfter\"/>\n        <module name=\"NoWhitespaceBefore\"/>\n        <module name=\"ParenPad\"/>\n        <module name=\"TypecastParenPad\"/>\n        <module name=\"WhitespaceAfter\">\n\t    \t<property name=\"tokens\" value=\"COMMA, SEMI\"/>\n\t\t</module>\n\n\n        <!-- Modifier Checks                                    -->\n        <!-- See http://checkstyle.sf.net/config_modifiers.html -->\n        <module name=\"ModifierOrder\"/>\n        <module name=\"RedundantModifier\"/>\n\n\n        <!-- Checks for blocks. You know, those {}'s         -->\n        <!-- See http://checkstyle.sf.net/config_blocks.html -->\n        <module name=\"AvoidNestedBlocks\"/>\n        <module name=\"EmptyBlock\"/>\n        <module name=\"LeftCurly\"/>\n        <module name=\"NeedBraces\"/>\n        <module name=\"RightCurly\"/>\n\n\n        <!-- Checks for common coding problems               -->\n        <!-- See http://checkstyle.sf.net/config_coding.html -->\n        <!-- module name=\"AvoidInlineConditionals\"/-->\n        <module name=\"EmptyStatement\"/>\n        <module name=\"EqualsHashCode\"/>\n        <module name=\"HiddenField\">\n          <property name=\"ignoreConstructorParameter\" value=\"true\"/>\n        </module>\n        <module name=\"IllegalInstantiation\"/>\n        <module name=\"InnerAssignment\"/>\n        <module name=\"MissingSwitchDefault\"/>\n        <module name=\"SimplifyBooleanExpression\"/>\n        <module name=\"SimplifyBooleanReturn\"/>\n\n        <!-- Checks for class design                         -->\n        <!-- See http://checkstyle.sf.net/config_design.html -->\n        <module name=\"FinalClass\"/>\n        <module name=\"HideUtilityClassConstructor\"/>\n        <module name=\"InterfaceIsType\"/>\n        <module name=\"VisibilityModifier\"/>\n\n\n        <!-- Miscellaneous other checks.                   -->\n        <!-- See http://checkstyle.sf.net/config_misc.html -->\n        <module name=\"ArrayTypeStyle\"/>\n        <module name=\"Indentation\">\n            <property name=\"basicOffset\" value=\"4\" />\n            <property name=\"caseIndent\" value=\"0\" />\n        </module> \n        <module name=\"TodoComment\"/>\n        <module name=\"UpperEll\"/>\n\n    </module>\n\n</module>\n"
  },
  {
    "path": "src/java/test/config/findbugsExcludeFile.xml",
    "content": "<FindBugsFilter>\n  <!-- Allow command line utilities, which follow pattern *Main.java, to call\n       system exit -->\n  <Match>\n    <Class name=\"~org\\.apache\\.zookeeper\\..*Main\" />\n    <Bug pattern=\"DM_EXIT\" />\n  </Match>\n\n  <!-- This is too complicated to resolve/ingrained into the architecture\n       In particular we want to make sure we exit if this occurs\n       Also notice logged as fatal error -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.ZooKeeperCriticalThread\" />\n    <Method name=\"handleException\" />\n    <Bug pattern=\"DM_EXIT\" />\n  </Match>\n\n  <!-- In particular we want to make sure we exit if this occurs, unrecoverable.\n       Also notice logged as fatal error -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.ZooKeeperServer\" />\n    <Method name=\"takeSnapshot\" />\n    <Bug pattern=\"DM_EXIT\" />\n  </Match>\n\n\n  <!-- We want to catch all exceptions and cleanup, regardless of source\n       (incl runtime) -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.ClientCnxn$SendThread\" />\n    <Method name=\"run\" />\n    <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n  </Match>\n\n   <!-- If we cannot open a socket to elect a leader, then we should\n            simply exit -->\n   <Match>\n     <Class name=\"org.apache.zookeeper.server.quorum.LeaderElection\" />\n       <Method name=\"lookForLeader\" />\n       <Bug pattern=\"DM_EXIT\" />\n   </Match>\n\n   <!-- Committing out of order is an unrecoverable error, so we should\n              really exit  -->\n   <Match>\n     <Class name=\"org.apache.zookeeper.server.quorum.FollowerZooKeeperServer\" />\n       <Method name=\"commit\" />\n       <Bug pattern=\"DM_EXIT\" />\n     </Match>\n\n   <!-- Two unrecoverable errors while following the leader  -->\n   <Match>\n     <Class name=\"org.apache.zookeeper.server.quorum.Learner\" />\n       <Method name=\"syncWithLeader\" />\n       <Bug pattern=\"DM_EXIT\" />\n   </Match>\n\n  <Match>\n    <Package name=\"org.apache.jute.compiler.generated\" />\n  </Match>\n\n  <Match>\n    <Package name=\"~org\\.apache\\.zookeeper\\.(proto|data|txn)\" />\n    <Bug code=\"EI, EI2\" />\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.DataNode\" />\n      <Bug code=\"EI2\"/>\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.QuorumPacket\" />\n       <Bug code=\"EI2, EI\" />\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.QuorumAuthPacket\" />\n      <Bug code=\"EI2, EI\" />\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.ClientCnxn\"/>\n      <Bug code=\"EI, EI2\" />\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.DataNode\"/>\n      <Field name=\"children\"/> \n      <Bug code=\"IS\"/>\n  </Match>\n <Match>\n   <Class name=\"org.apache.zookeeper.server.quorum.Leader\"/>\n     <Field name=\"lastProposed\"/>\n     <Bug code=\"IS\"/>\n  </Match>\n  <Match>\n     <Class name=\"org.apache.zookeeper.server.quorum.LearnerSessionTracker\"/>\n       <Bug code=\"UrF\"/>\n  </Match>\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.AuthFastLeaderElection$Messenger$WorkerSender\"/>\n    <Method name=\"process\"/>\n    <Bug code=\"RV,SF\"/>\n  </Match>\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.AuthFastLeaderElection$Messenger$WorkerReceiver\"/>\n    <Method name=\"run\"/>\n    <Bug code=\"SF\"/>\n  </Match>\n\n  <!-- these are old classes just for upgrading and should go away -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.AuthFastLeaderElection\"/>\n  </Match>\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.upgrade.DataNodeV1\"/>\n  </Match> \n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.upgrade.DataTreeV1\"/>\n  </Match>\n\n  <!-- References code in a generated file that may or maynot be null -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.Version\" />\n    <Method name=\"getVersion\" />\n    <Bug pattern=\"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE\" />\n  </Match>\n\n  <!-- sync'd object is also being used to protect the isrunning flag, this is ok -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.ClientCnxn$EventThread\"/>\n    <Bug code=\"JLM\"/>\n    <Or>\n      <Method name=\"queuePacket\" />\n      <Method name=\"run\" />\n    </Or>\n  </Match>\n\n  <Match>\n    <Class name=\"org.apache.zookeeper.server.quorum.QuorumPeer\"/>\n    <Bug pattern=\"OS_OPEN_STREAM\" />\n    <Method name=\"writeLongToFile\" />\n  </Match>\n\n  <!-- Disable 'Malicious code vulnerability warnings' due to mutable collection types in interface.\n       Undo this when ZOOKEEPER-1362 is done. -->\n  <Match>\n    <Class name=\"org.apache.zookeeper.ZooDefs$Ids\"/>\n      <Bug pattern=\"MS_MUTABLE_COLLECTION\" />\n  </Match>\n\n  <!-- Disable 'Found reliance on default encoding in' warnings. Ideally this should be fixed\n       by fixing the underlying cause - reliance on 'default' encoding in IO operations.\n       Please see ZOOKEEPER-1976 for detailed discussion. -->\n  <Match>\n    <Bug pattern=\"DM_DEFAULT_ENCODING\" />\n  </Match>\n\n</FindBugsFilter>\n"
  },
  {
    "path": "src/java/test/data/kerberos/minikdc-krb5.conf",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# This resource is originally from HDFS, see the similarly named files there\n# in case of bug fixing, history, etc.\n# Branch : trunk\n# Github Revision: 1d1ab587e4e92ce3aea4cb144811f69145cb3b33\n#\n[libdefaults]\n    default_realm = {0}\n    udp_preference_limit = 1\n\n[realms]\n    {0} = '{'\n        kdc = {1}:{2}\n    '}'"
  },
  {
    "path": "src/java/test/data/kerberos/minikdc.ldiff",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# This resource is originally from HDFS, see the similarly named files there\n# in case of bug fixing, history, etc.\n# Branch : trunk\n# Github Revision: 1d1ab587e4e92ce3aea4cb144811f69145cb3b33\n#\ndn: ou=users,dc=${0},dc=${1}\nobjectClass: organizationalUnit\nobjectClass: top\nou: users\n\ndn: uid=krbtgt,ou=users,dc=${0},dc=${1}\nobjectClass: top\nobjectClass: person\nobjectClass: inetOrgPerson\nobjectClass: krb5principal\nobjectClass: krb5kdcentry\ncn: KDC Service\nsn: Service\nuid: krbtgt\nuserPassword: secret\nkrb5PrincipalName: krbtgt/${2}.${3}@${2}.${3}\nkrb5KeyVersionNumber: 0\n\ndn: uid=ldap,ou=users,dc=${0},dc=${1}\nobjectClass: top\nobjectClass: person\nobjectClass: inetOrgPerson\nobjectClass: krb5principal\nobjectClass: krb5kdcentry\ncn: LDAP\nsn: Service\nuid: ldap\nuserPassword: secret\nkrb5PrincipalName: ldap/${4}@${2}.${3}\nkrb5KeyVersionNumber: 0"
  },
  {
    "path": "src/java/test/org/apache/jute/BinaryInputArchiveTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.jute;\n\nimport junit.framework.Assert;\nimport org.junit.Test;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\n\npublic class BinaryInputArchiveTest {\n\n    @Test\n    public void testReadStringCheckLength() {\n        byte[] buf = new byte[]{\n                Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE};\n        ByteArrayInputStream is = new ByteArrayInputStream(buf);\n        BinaryInputArchive ia = BinaryInputArchive.getArchive(is);\n        try {\n            ia.readString(\"\");\n            Assert.fail(\"Should have thrown an IOException\");\n        } catch (IOException e) {\n            Assert.assertTrue(\"Not 'Unreasonable length' exception: \" + e,\n                    e.getMessage().startsWith(BinaryInputArchive.UNREASONBLE_LENGTH));\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/ClientReconnectTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\n\nimport static org.mockito.Matchers.anyLong;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport junit.framework.Assert;\nimport junit.framework.TestCase;\n\nimport org.apache.zookeeper.client.HostProvider;\nimport org.junit.Test;\n\npublic class ClientReconnectTest extends TestCase {\n    private SocketChannel sc;\n    private CountDownLatch countDownLatch = new CountDownLatch(3);\n    \n    class MockCnxn extends ClientCnxnSocketNIO {\n        MockCnxn() throws IOException {\n            super();\n        }\n\n        @Override\n        void registerAndConnect(SocketChannel sock, InetSocketAddress addr) throws\n        IOException {\n            countDownLatch.countDown();\n            throw new IOException(\"failed to register\");\n        }\n\n        @Override\n        SocketChannel createSock() {\n            return sc;\n        }\n    }\n\n    @Test\n    public void testClientReconnect() throws IOException, InterruptedException {\n        HostProvider hostProvider = mock(HostProvider.class);\n        when(hostProvider.size()).thenReturn(1);\n        InetSocketAddress inaddr = new InetSocketAddress(1111);\n        when(hostProvider.next(anyLong())).thenReturn(inaddr);\n        ZooKeeper zk = mock(ZooKeeper.class);\n        sc =  SocketChannel.open();\n\n        ClientCnxnSocketNIO nioCnxn = new MockCnxn();\n        ClientWatchManager watcher = mock(ClientWatchManager.class);\n        ClientCnxn clientCnxn = new ClientCnxn(\n                \"tmp\", hostProvider, 5000,\n                zk, watcher, nioCnxn, false);\n        clientCnxn.start();\n        countDownLatch.await(5000, TimeUnit.MILLISECONDS);\n        Assert.assertTrue(countDownLatch.getCount() == 0);\n        clientCnxn.close();\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/JUnit4ZKTestRunner.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.junit.Test;\nimport org.junit.internal.runners.statements.InvokeMethod;\nimport org.junit.runners.BlockJUnit4ClassRunner;\nimport org.junit.runners.model.FrameworkMethod;\nimport org.junit.runners.model.InitializationError;\nimport org.junit.runners.model.Statement;\n\n/**\n * The sole responsibility of this class is to print to the log when a test\n * starts and when it finishes.\n */\npublic class JUnit4ZKTestRunner extends BlockJUnit4ClassRunner {\n    private static final Logger LOG = LoggerFactory.getLogger(JUnit4ZKTestRunner.class);\n\n    public JUnit4ZKTestRunner(Class<?> klass) throws InitializationError {\n        super(klass);\n    }\n\n    public class LoggedInvokeMethod extends InvokeMethod {\n        private final FrameworkMethod method;\n        private final String name;\n\n        public LoggedInvokeMethod(FrameworkMethod method, Object target) {\n            super(method, target);\n            this.method = method;\n            name = method.getName();\n        }\n\n        @Override\n        public void evaluate() throws Throwable {\n            LOG.info(\"RUNNING TEST METHOD {}\", name);\n            try {\n                super.evaluate();\n                Runtime rt = Runtime.getRuntime();\n                long usedKB = (rt.totalMemory() - rt.freeMemory()) / 1024;\n                LOG.info(\"Memory used {}\", usedKB);\n                ThreadGroup tg = Thread.currentThread().getThreadGroup();\n                while (tg.getParent() != null) {\n                    tg = tg.getParent();\n                }\n                LOG.info(\"Number of threads {}\", tg.activeCount());\n            } catch (Throwable t) {\n                // The test method threw an exception, but it might be an\n                // expected exception as defined in the @Test annotation.\n                // Check the annotation and log an appropriate message.\n                Test annotation = this.method.getAnnotation(Test.class);\n                if (annotation != null && annotation.expected() != null &&\n                        annotation.expected().isAssignableFrom(t.getClass())) {\n                    LOG.info(\"TEST METHOD {} THREW EXPECTED EXCEPTION {}\", name,\n                        annotation.expected());\n                } else {\n                    LOG.info(\"TEST METHOD FAILED {}\", name, t);\n                }\n                throw t;\n            }\n            LOG.info(\"FINISHED TEST METHOD {}\", name);\n        }\n    }\n\n    @Override\n    protected Statement methodInvoker(FrameworkMethod method, Object test) {\n        return new LoggedInvokeMethod(method, test);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/JaasConfiguration.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;\n\n/**\n * This helper class allows to programmatically create a JAAS configuration.\n * Each section must have a name and a login module, and a set of key/values\n * to describe login options.\n *\n * Example:\n *   jaas = new JaasConfiguration();\n *   jaas.addSection(\"Server\", \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n *                   \"username\", \"passowrd\");\n */\npublic class JaasConfiguration extends javax.security.auth.login.Configuration {\n    private final Map<String, AppConfigurationEntry[]> sections =\n      new HashMap<String, AppConfigurationEntry[]>();\n\n    public JaasConfiguration() {\n    }\n\n    /**\n     * Add a section to the jaas.conf\n     * @param name Section name\n     * @param loginModuleName Login module name\n     * @param args login key/value args\n     */\n    public void addSection(String name, String loginModuleName, String... args) {\n        Map<String, String> conf = new HashMap<String, String>();\n        // loop through the args (must be key/value sequence)\n        for (int i = 0; i < args.length - 1; i += 2) {\n            conf.put(args[i], args[i + 1]);\n        }\n        addSection(name, loginModuleName, conf);\n    }\n\n    /**\n     * Add a section to the jaas.conf\n     * @param name Section name\n     * @param loginModuleName Login module name\n     * @param conf login key/value args\n     */\n    public void addSection(String name, String loginModuleName, final Map<String,String> conf) {\n        AppConfigurationEntry[] entries = new AppConfigurationEntry[1];\n        entries[0] = new AppConfigurationEntry(loginModuleName, LoginModuleControlFlag.REQUIRED, conf);\n        this.sections.put(name, entries);\n    }\n\n    @Override\n    public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {\n        return sections.get(appName);\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/MockPacket.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.ZooKeeper.WatchRegistration;\nimport java.nio.ByteBuffer;\n\npublic class MockPacket extends ClientCnxn.Packet {\n\n    public MockPacket(RequestHeader requestHeader, ReplyHeader replyHeader,\n               Record request, Record response,\n               WatchRegistration watchRegistration) {\n        super(requestHeader, replyHeader, request, response, watchRegistration);\n    }\n\n    public MockPacket(RequestHeader requestHeader, ReplyHeader replyHeader,\n               Record request, Record response,\n               WatchRegistration watchRegistration, boolean readOnly) {\n        super(requestHeader, replyHeader, request, response, watchRegistration, readOnly);\n    }\n\n    public ByteBuffer createAndReturnBB() {\n        createBB();\n        return this.bb;\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/MultiResponseTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport junit.framework.TestCase;\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.junit.Test;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\npublic class MultiResponseTest extends TestCase {\n    public void testRoundTrip() throws IOException {\n        MultiResponse response = new MultiResponse();\n\n        response.add(new OpResult.CheckResult());\n        response.add(new OpResult.CreateResult(\"foo-bar\"));\n        response.add(new OpResult.DeleteResult());\n\n        Stat s = new Stat();\n        s.setCzxid(546);\n        response.add(new OpResult.SetDataResult(s));\n\n        MultiResponse decodedResponse = codeDecode(response);\n\n        assertEquals(response, decodedResponse);\n        assertEquals(response.hashCode(), decodedResponse.hashCode());\n    }\n\n    @Test\n    public void testEmptyRoundTrip() throws IOException {\n        MultiResponse result = new MultiResponse();\n        MultiResponse decodedResult = codeDecode(result);\n\n        assertEquals(result, decodedResult);\n        assertEquals(result.hashCode(), decodedResult.hashCode());\n    }\n\n    private MultiResponse codeDecode(MultiResponse request) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n        request.serialize(boa, \"result\");\n        baos.close();\n        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n        bb.rewind();\n\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(new ByteBufferInputStream(bb));\n        MultiResponse decodedRequest = new MultiResponse();\n        decodedRequest.deserialize(bia, \"result\");\n        return decodedRequest;\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/MultiTransactionRecordTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport junit.framework.TestCase;\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.junit.Test;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\npublic class MultiTransactionRecordTest extends TestCase {\n    @Test\n    public void testRoundTrip() throws IOException {\n        MultiTransactionRecord request = new MultiTransactionRecord();\n        request.add(Op.check(\"check\", 1));\n        request.add(Op.create(\"create\", \"create data\".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, ZooDefs.Perms.ALL));\n        request.add(Op.delete(\"delete\", 17));\n        request.add(Op.setData(\"setData\", \"set data\".getBytes(), 19));\n\n        MultiTransactionRecord decodedRequest = codeDecode(request);\n\n        assertEquals(request, decodedRequest);\n        assertEquals(request.hashCode(), decodedRequest.hashCode());\n    }\n\n    @Test\n    public void testEmptyRoundTrip() throws IOException {\n        MultiTransactionRecord request = new MultiTransactionRecord();\n        MultiTransactionRecord decodedRequest = codeDecode(request);\n\n        assertEquals(request, decodedRequest);\n        assertEquals(request.hashCode(), decodedRequest.hashCode());\n    }\n\n    private MultiTransactionRecord codeDecode(MultiTransactionRecord request) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n        request.serialize(boa, \"request\");\n        baos.close();\n        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n        bb.rewind();\n\n        BinaryInputArchive bia = BinaryInputArchive.getArchive(new ByteBufferInputStream(bb));\n        MultiTransactionRecord decodedRequest = new MultiTransactionRecord();\n        decodedRequest.deserialize(bia, \"request\");\n        return decodedRequest;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/PortAssignment.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/** Assign ports to tests */\npublic class PortAssignment {\n    private static final Logger LOG = LoggerFactory.getLogger(PortAssignment.class);\n\n    private static int nextPort = 11221;\n\n    /** Assign a new, unique port to the test */\n    public synchronized static int unique() {\n        LOG.info(\"assigning port \" + nextPort);\n        return nextPort++;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/SaslAuthTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.ClientCnxn.SendThread;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class SaslAuthTest extends ClientBase {\n    @BeforeClass\n    public static void init() {\n        System.setProperty(\"zookeeper.authProvider.1\",\n                \"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            String jaasContent = getJaasFileContent();\n            FileWriter fwriter = new FileWriter(saslConfFile);\n            fwriter.write(jaasContent);\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\", saslConfFile.getAbsolutePath());\n        } catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file : test will\n            // fail now.\n        }\n    }\n\n    private static String getJaasFileContent() {\n        StringBuilder jaasContent=new StringBuilder();\n        String newLine = System.getProperty(\"line.separator\");\n        jaasContent.append(\"Server {\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"org.apache.zookeeper.server.auth.DigestLoginModule required\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"user_super=\\\"test\\\";\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"};\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"Client {\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"org.apache.zookeeper.server.auth.DigestLoginModule required\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"username=\\\"super\\\"\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"password=\\\"test\\\";\");\n        jaasContent.append(newLine);\n        jaasContent.append(\"};\");\n        jaasContent.append(newLine);\n        return jaasContent.toString();\n    }\n\n    @AfterClass\n    public static void clean() {\n        System.clearProperty(\"zookeeper.authProvider.1\");\n        System.clearProperty(\"java.security.auth.login.config\");\n    }\n\n    private AtomicInteger authFailed = new AtomicInteger(0);\n    \n    @Override\n    protected TestableZooKeeper createClient(String hp)\n    throws IOException, InterruptedException\n    {\n        MyWatcher watcher = new MyWatcher();\n        return createClient(watcher, hp);\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                authFailed.incrementAndGet();\n            }\n            else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testAuth() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            Thread.sleep(1000);\n        } finally {\n            zk.close();\n        }\n    }\n\n    @Test\n    public void testValidSaslIds() throws Exception {\n        ZooKeeper zk = createClient();\n\n        List<String> validIds = new ArrayList<String>();\n        validIds.add(\"user\");\n        validIds.add(\"service/host.name.com\");\n        validIds.add(\"user@KERB.REALM\");\n        validIds.add(\"service/host.name.com@KERB.REALM\");\n\n        int i = 0;\n        for(String validId: validIds) {\n            List<ACL> aclList = new ArrayList<ACL>();\n            ACL acl = new ACL(0,new Id(\"sasl\",validId));\n            aclList.add(acl);\n            zk.create(\"/valid\"+i,null,aclList,CreateMode.PERSISTENT);\n            i++;\n        }\n    }\n\n    @Test\n    public void testInvalidSaslIds() throws Exception {\n        ZooKeeper zk = createClient();\n\n        List<String> invalidIds = new ArrayList<String>();\n        invalidIds.add(\"user@KERB.REALM/server.com\");\n        invalidIds.add(\"user@KERB.REALM1@KERB.REALM2\");\n\n        int i = 0;\n        for(String invalidId: invalidIds) {\n            List<ACL> aclList = new ArrayList<ACL>();\n            try {\n                ACL acl = new ACL(0,new Id(\"sasl\",invalidId));\n                aclList.add(acl);\n                zk.create(\"/invalid\"+i,null,aclList,CreateMode.PERSISTENT);\n                Assert.fail(\"SASLAuthenticationProvider.isValid() failed to catch invalid Id.\");\n            }\n            catch (KeeperException.InvalidACLException e) {\n                // ok.\n            }\n            finally {\n                i++;\n            }\n        }\n    }\n    \n    @Test\n    public void testZKOperationsAfterClientSaslAuthFailure() throws Exception {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        try {\n            setSaslFailureFlag(zk);\n\n            // try node creation for around 15 second,\n            int totalTry = 10;\n            int tryCount = 0;\n\n            boolean success = false;\n            while (!success && tryCount++ <= totalTry) {\n                try {\n                    zk.create(\"/saslAuthFail\", \"data\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                            CreateMode.PERSISTENT_SEQUENTIAL);\n                    success = true;\n                } catch (KeeperException.ConnectionLossException e) {\n                    Thread.sleep(1000);\n                    // do nothing\n                }\n            }\n            assertTrue(\"ZNode creation is failing continuously after Sasl auth failure.\", success);\n\n        } finally {\n            zk.close();\n        }\n    }\n\n    // set saslLoginFailed to true to simulate the LoginException\n    private void setSaslFailureFlag(ZooKeeper zk) throws Exception {\n        Field cnxnField = zk.getClass().getDeclaredField(\"cnxn\");\n        cnxnField.setAccessible(true);\n        ClientCnxn clientCnxn = (ClientCnxn) cnxnField.get(zk);\n        Field sendThreadField = clientCnxn.getClass().getDeclaredField(\"sendThread\");\n        sendThreadField.setAccessible(true);\n        SendThread sendThread = (SendThread) sendThreadField.get(clientCnxn);\n        Field saslLoginFailedField = sendThread.getClass().getDeclaredField(\"saslLoginFailed\");\n        saslLoginFailedField.setAccessible(true);\n        saslLoginFailedField.setBoolean(sendThread, true);\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/ServerConfigTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.apache.zookeeper.server.ServerConfig;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\n\npublic class ServerConfigTest {\n\n    private ServerConfig serverConfig;\n\n    @Before\n    public void setUp() {\n        serverConfig = new ServerConfig();\n    }\n\n    @Test(expected=IllegalArgumentException.class)\n    public void testFewArguments() {\n        String[] args = {\"2181\"};\n        serverConfig.parse(args);\n    }\n\n    @Test\n    public void testValidArguments() {\n        String[] args = {\"2181\", \"/data/dir\", \"60000\", \"10000\"};\n        serverConfig.parse(args);\n\n        assertEquals(2181, serverConfig.getClientPortAddress().getPort());\n        assertTrue(checkEquality(\"/data/dir\", serverConfig.getDataDir()));\n        assertEquals(60000, serverConfig.getTickTime());\n        assertEquals(10000, serverConfig.getMaxClientCnxns());\n    }\n\n    @Test(expected=IllegalArgumentException.class)\n    public void testTooManyArguments() {\n        String[] args = {\"2181\", \"/data/dir\", \"60000\", \"10000\", \"9999\"};\n        serverConfig.parse(args);\n    }\n\n    boolean checkEquality(String a, String b) {\n        assertNotNull(a);\n        assertNotNull(b);\n        return a.equals(b);\n    }\n\n    boolean checkEquality(String a, File b) {\n        assertNotNull(a);\n        assertNotNull(b);\n        return new File(a).equals(b);\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/TestableZooKeeper.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.IOException;\nimport java.net.SocketAddress;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\n\npublic class TestableZooKeeper extends ZooKeeper {\n\n    public TestableZooKeeper(String host, int sessionTimeout,\n            Watcher watcher) throws IOException {\n        super(host, sessionTimeout, watcher);\n    }\n    \n    @Override\n    public List<String> getChildWatches() {\n        return super.getChildWatches();\n    }\n\n\n    @Override\n    public List<String> getDataWatches() {\n        return super.getDataWatches();\n    }\n\n\n    @Override\n    public List<String> getExistWatches() {\n        return super.getExistWatches();\n    }\n\n    /**\n     * Cause this ZooKeeper object to disconnect from the server. It will then\n     * later attempt to reconnect.\n     */\n    public void testableConnloss() throws IOException {\n        synchronized(cnxn) {\n            cnxn.sendThread.testableCloseSocket();\n        }\n    }\n\n    /**\n     * Cause this ZooKeeper object to stop receiving from the ZooKeeperServer\n     * for the given number of milliseconds.\n     * @param ms the number of milliseconds to pause.\n     * @return true if the connection is paused, otherwise false\n     */\n    public boolean pauseCnxn(final long ms) {\n        final CountDownLatch initiatedPause = new CountDownLatch(1);\n        new Thread() {\n            public void run() {\n                synchronized(cnxn) {\n                    try {\n                        try {\n                            cnxn.sendThread.testableCloseSocket();\n                        } catch (IOException e) {\n                            e.printStackTrace();\n                        } finally {\n                            initiatedPause.countDown();\n                        }\n                        Thread.sleep(ms);\n                    } catch (InterruptedException e) {\n                    }\n                }\n            }\n        }.start();\n\n        try {\n            return initiatedPause.await(ms, TimeUnit.MILLISECONDS);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n    \n    public boolean testableWaitForShutdown(int wait)\n        throws InterruptedException\n    {\n        return super.testableWaitForShutdown(wait);\n    }\n\n    public SocketAddress testableLocalSocketAddress() {\n        return super.testableLocalSocketAddress();\n    }\n\n    public SocketAddress testableRemoteSocketAddress() {\n        return super.testableRemoteSocketAddress();\n    }\n\n    /**\n     * @return the last zxid as seen by the client session\n     */\n    public long testableLastZxid() {\n        return cnxn.getLastZxid();\n    }\n\n    public ReplyHeader submitRequest(RequestHeader h, Record request,\n            Record response, WatchRegistration watchRegistration) throws InterruptedException {\n        return cnxn.submitRequest(h, request, response, watchRegistration);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/VerGenTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.version.util.VerGen;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n\n/**\n * Test VerGen, used during the build.\n *\n */\n@RunWith(Parameterized.class)\npublic class VerGenTest extends ZKTestCase {\n    @Parameters\n    public static Collection<Object[]> data() {\n            return Arrays.asList(new Object[][] {\n                            {\"1.2.3\", new Object[] {1, 2, 3, null}},\n                            {\"1.2.3-dev\", new Object[] {1, 2, 3, \"dev\"}},\n                            {\"1.2.3-SNAPSHOT\", new Object[] {1, 2, 3, \"SNAPSHOT\"}},\n                            {\"1.2.3-SNAPSHOT\", new Object[] {1, 2, 3, \"SNAPSHOT\"}},\n                            {\"1.2.3-foo-bar+123\", new Object[] {1, 2, 3, \"foo-bar+123\"}},\n                            {\"1.2.3.4.5-SNAPSHOT\", new Object[] {1, 2, 3, \"SNAPSHOT\"}},\n                            {\"1.2.3.4.5-foo-bar+123\", new Object[] {1, 2, 3, \"foo-bar+123\"}}\n            });\n    }\n\n    private String input;\n\n    private Object[] expected;\n\n    public VerGenTest(String input, Object[] expected) {\n        this.input = input;\n        this.expected = expected;\n    }\n\n    @Test\n    public void testParser() {\n        VerGen.Version v = VerGen.parseVersionString(input);\n        Assert.assertEquals(expected[0], v.maj);\n        Assert.assertEquals(expected[1], v.min);\n        Assert.assertEquals(expected[2], v.micro);\n        Assert.assertEquals(expected[3], v.qualifier);\n    }\n\n    @Test\n    public void testGenFile() throws Exception {\n        VerGen.Version v = VerGen.parseVersionString(input);\n        File outputDir = ClientBase.createTmpDir();\n        VerGen.generateFile(outputDir, v, \"1\", \"Nov1\");\n        ClientBase.recursiveDelete(outputDir);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/ZKTestCase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper;\n\nimport org.junit.Assume;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.junit.Rule;\nimport org.junit.rules.MethodRule;\nimport org.junit.rules.TestWatchman;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.model.FrameworkMethod;\n\nimport java.io.IOException;\nimport java.net.Inet6Address;\nimport java.net.InetAddress;\n\n/**\n * Base class for a non-parameterized ZK test.\n *\n * Basic utilities shared by all tests. Also logging of various events during\n * the test execution (start/stop/success/failure/etc...)\n */\n@RunWith(JUnit4ZKTestRunner.class)\npublic class ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(ZKTestCase.class);\n\n    private String testName;\n\n    protected String getTestName() {\n        return testName;\n    }\n\n    @Rule\n    public MethodRule watchman = new TestWatchman() {\n        @Override\n        public void starting(FrameworkMethod method) {\n            testName = method.getName();\n            // ZOOKEEPER-2693 disables all 4lw by default.\n            // Here we enable the 4lw which ZooKeeper tests depends.\n            System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"*\");\n\n            LOG.info(\"STARTING \" + testName);\n        }\n\n        @Override\n        public void finished(FrameworkMethod method) {\n            LOG.info(\"FINISHED \" + testName);\n        }\n\n        @Override\n        public void succeeded(FrameworkMethod method) {\n            LOG.info(\"SUCCEEDED \" + testName);\n        }\n\n        @Override\n        public void failed(Throwable e, FrameworkMethod method) {\n            LOG.info(\"FAILED \" + testName, e);\n        }\n\n    };\n\n    protected void assumeIPv6Available() {\n        try {\n            InetAddress address = Inet6Address.getByName(\"0:0:0:0:0:0:0:1\");\n            Assume.assumeTrue(address.isReachable(1000));\n        } catch (IOException exception) {\n            Assume.assumeTrue(false);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/ZooKeeperTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper;\n\nimport static org.junit.Assert.*;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * \n * Testing Zookeeper public methods\n *\n */\npublic class ZooKeeperTest extends ClientBase {\n\n    @Test\n    public void testDeleteRecursive() throws IOException, InterruptedException,\n            KeeperException {\n        final ZooKeeper zk = createClient();\n        // making sure setdata works on /\n        zk.setData(\"/\", \"some\".getBytes(), -1);\n        zk.create(\"/a\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v/1\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/c\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/c/v\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        List<String> children = zk.getChildren(\"/a\", false);\n\n        Assert.assertEquals(\"2 children - b & c should be present \", children\n                .size(), 2);\n        Assert.assertTrue(children.contains(\"b\"));\n        Assert.assertTrue(children.contains(\"c\"));\n\n        ZKUtil.deleteRecursive(zk, \"/a\");\n        Assert.assertNull(zk.exists(\"/a\", null));\n    }\n\n    @Test\n    public void testDeleteRecursiveAsync() throws IOException,\n            InterruptedException, KeeperException {\n        final ZooKeeper zk = createClient();\n        // making sure setdata works on /\n        zk.setData(\"/\", \"some\".getBytes(), -1);\n        zk.create(\"/a\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v/1\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/c\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/c/v\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        for (int i = 0; i < 50; ++i) {\n            zk.create(\"/a/c/\" + i, \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n        List<String> children = zk.getChildren(\"/a\", false);\n\n        Assert.assertEquals(\"2 children - b & c should be present \", children\n                .size(), 2);\n        Assert.assertTrue(children.contains(\"b\"));\n        Assert.assertTrue(children.contains(\"c\"));\n\n        VoidCallback cb = new VoidCallback() {\n\n            @Override\n            public void processResult(int rc, String path, Object ctx) {\n                synchronized (ctx) {\n                    ((AtomicInteger) ctx).set(4);\n                    ctx.notify();\n                }\n            }\n\n        };\n        final AtomicInteger ctx = new AtomicInteger(3);\n        ZKUtil.deleteRecursive(zk, \"/a\", cb, ctx);\n        synchronized (ctx) {\n            ctx.wait();\n        }\n        Assert.assertEquals(4, ((AtomicInteger) ctx).get());\n    }\n    \n    @Test\n    public void testStatWhenPathDoesNotExist() throws IOException,\n    \t\tInterruptedException {\n    \tfinal ZooKeeper zk = createClient();\n    \tZooKeeperMain main = new ZooKeeperMain(zk);\n    \tString cmdstring = \"stat /invalidPath\";\n    \tmain.cl.parseCommand(cmdstring);\n    \ttry {\n    \t\tmain.processZKCmd(main.cl);\n    \t\tAssert.fail(\"As Node does not exist, command should fail by throwing No Node Exception.\");\n    \t} catch (KeeperException e) {\n    \t\tAssert.assertEquals(\"KeeperErrorCode = NoNode for /invalidPath\", e.getMessage());\n    \t}\n    }\n\n    @Test\n    public void testParseWithExtraSpaces() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        String cmdstring = \"      ls       /  \";\n        zkMain.cl.parseCommand(cmdstring);\n        Assert.assertEquals(\"Spaces also considered as characters\", zkMain.cl.getNumArguments(), 2);\n        Assert.assertEquals(\"ls is not taken as first argument\", zkMain.cl.getCmdArgument(0), \"ls\");\n        Assert.assertEquals(\"/ is not taken as second argument\", zkMain.cl.getCmdArgument(1), \"/\");\n    }\n\n    @Test\n    public void testCheckInvalidAcls() throws Exception {\n         final ZooKeeper zk = createClient();\n            ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n            String cmdstring = \"create -s -e /node data ip:scheme:gggsd\"; //invalid acl's\n            try{\n                 zkMain.executeLine(cmdstring);\n            }catch(KeeperException.InvalidACLException e){\n                fail(\"For Invalid ACls should not throw exception\");\n            }\n    }\n\n    @Test\n    public void testDeleteWithInvalidVersionNo() throws Exception {\n         final ZooKeeper zk = createClient();\n            ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n            String cmdstring = \"create -s -e /node1 data \"; \n            String cmdstring1 = \"delete /node1 2\";//invalid dataversion no\n                 zkMain.executeLine(cmdstring);\n           try{\n               zkMain.executeLine(cmdstring1);\n                     \n            }catch(KeeperException.BadVersionException e){\n                fail(\"For Invalid dataversion number should not throw exception\");\n            }\n    }\n\n    @Test\n    public void testCliCommandsNotEchoingUsage() throws Exception {\n            // setup redirect out/err streams to get System.in/err, use this judiciously!\n           final PrintStream systemErr = System.err; // get current err\n           final ByteArrayOutputStream errContent = new ByteArrayOutputStream();\n           System.setErr(new PrintStream(errContent));\n           final ZooKeeper zk = createClient();\n           ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n           String cmd1 = \"printwatches\";\n           zkMain.executeLine(cmd1);\n           String cmd2 = \"history\";\n           zkMain.executeLine(cmd2);\n           String cmd3 = \"redo\";\n           zkMain.executeLine(cmd3);\n           // revert redirect of out/err streams - important step!\n           System.setErr(systemErr);\n           if (errContent.toString().contains(\"ZooKeeper -server host:port cmd args\")) {\n                fail(\"CLI commands (history, redo, connect, printwatches) display usage info!\");\n            }\n    }\n\n     @Test\n    public void testParseWithQuotes() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        for (String quoteChar : new String[] {\"'\", \"\\\"\"}) {\n            String cmdstring = String.format(\"create /node %1$squoted data%1$s\", quoteChar);\n            zkMain.cl.parseCommand(cmdstring);\n            Assert.assertEquals(\"quotes combine arguments\", zkMain.cl.getNumArguments(), 3);\n            Assert.assertEquals(\"create is not taken as first argument\", zkMain.cl.getCmdArgument(0), \"create\");\n            Assert.assertEquals(\"/node is not taken as second argument\", zkMain.cl.getCmdArgument(1), \"/node\");\n            Assert.assertEquals(\"quoted data is not taken as third argument\", zkMain.cl.getCmdArgument(2), \"quoted data\");\n        }\n    }\n\n    @Test\n    public void testParseWithMixedQuotes() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        for (String[] quoteChars : new String[][] {{\"'\", \"\\\"\"}, {\"\\\"\", \"'\"}}) {\n            String outerQuotes = quoteChars[0];\n            String innerQuotes = quoteChars[1];\n            String cmdstring = String.format(\"create /node %1$s%2$squoted data%2$s%1$s\", outerQuotes, innerQuotes);\n            zkMain.cl.parseCommand(cmdstring);\n            Assert.assertEquals(\"quotes combine arguments\", zkMain.cl.getNumArguments(), 3);\n            Assert.assertEquals(\"create is not taken as first argument\", zkMain.cl.getCmdArgument(0), \"create\");\n            Assert.assertEquals(\"/node is not taken as second argument\", zkMain.cl.getCmdArgument(1), \"/node\");\n            Assert.assertEquals(\"quoted data is not taken as third argument\", zkMain.cl.getCmdArgument(2), innerQuotes + \"quoted data\" + innerQuotes);\n        }\n    }\n\n    @Test\n    public void testParseWithEmptyQuotes() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        String cmdstring = \"create /node ''\";\n        zkMain.cl.parseCommand(cmdstring);\n        Assert.assertEquals(\"empty quotes should produce arguments\", zkMain.cl.getNumArguments(), 3);\n        Assert.assertEquals(\"create is not taken as first argument\", zkMain.cl.getCmdArgument(0), \"create\");\n        Assert.assertEquals(\"/node is not taken as second argument\", zkMain.cl.getCmdArgument(1), \"/node\");\n        Assert.assertEquals(\"empty string is not taken as third argument\", zkMain.cl.getCmdArgument(2), \"\");\n    }\n\n    @Test\n    public void testParseWithMultipleQuotes() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        String cmdstring = \"create /node '' ''\";\n        zkMain.cl.parseCommand(cmdstring);\n        Assert.assertEquals(\"expected 5 arguments\", zkMain.cl.getNumArguments(), 4);\n        Assert.assertEquals(\"create is not taken as first argument\", zkMain.cl.getCmdArgument(0), \"create\");\n        Assert.assertEquals(\"/node is not taken as second argument\", zkMain.cl.getCmdArgument(1), \"/node\");\n        Assert.assertEquals(\"empty string is not taken as third argument\", zkMain.cl.getCmdArgument(2), \"\");\n        Assert.assertEquals(\"empty string is not taken as fourth argument\", zkMain.cl.getCmdArgument(3), \"\");\n    }\n\n    // ZOOKEEPER-2467 : Testing negative number for redo command\n    @Test\n    public void testRedoWithNegativeCmdNumber() throws Exception {\n        final ZooKeeper zk = createClient();\n        ZooKeeperMain zkMain = new ZooKeeperMain(zk);\n        String cmd1 = \"redo -1\";\n\n        // setup redirect out/err streams to get System.in/err, use this\n        // judiciously!\n        final PrintStream systemOut = System.out; // get current out\n        final ByteArrayOutputStream outContent = new ByteArrayOutputStream();\n        System.setOut(new PrintStream(outContent));\n        try {\n            zkMain.executeLine(cmd1);\n            Assert.assertEquals(\"Command index out of range\", outContent\n                    .toString().trim());\n        } finally {\n            // revert redirect of out/err streams - important step!\n            System.setOut(systemOut);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/common/TimeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.common;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Command line program for demonstrating robustness to clock\n * changes.\n * <p/>\n * How to run:\n * ant clean compile-test\n * echo build/test/lib/*.jar build/lib/*.jar build/classes build/test/classes | sed -e 's/ /:/g' > cp\n * java -cp $(cat cp) org.apache.zookeeper.common.TimeTest | tee log-without-patch\n * <p/>\n * After test program starts, in another window, do commands:\n * date -s '+1hour'\n * date -s '-1hour'\n * <p/>\n * As long as there isn't any expired event, the experiment is successful.\n */\npublic class TimeTest extends ClientBase {\n    private static final long mt0 = System.currentTimeMillis();\n    private static final long nt0 = Time.currentElapsedTime();\n\n    private static AtomicInteger watchCount = new AtomicInteger(0);\n\n\n    public static void main(String[] args) throws Exception {\n        System.out.printf(\"Starting\\n\");\n        final TimeTest test = new TimeTest();\n        System.out.printf(\"After construct\\n\");\n        test.setUp();\n        ZooKeeper zk = test.createClient();\n        zk.create(\"/ephemeral\", new byte[]{1, 2, 3},\n                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n        while (Time.currentElapsedTime() - nt0 < 100000) {\n            System.out.printf(\"%d\\t%s\\n\", discrepancy(),\n                    zk.exists(\"/ephemeral\",\n                            watchCount.get() == 0 ? createWatcher() : null) != null);\n            waitByYielding(500);\n        }\n    }\n\n    private static Watcher createWatcher() {\n        watchCount.incrementAndGet();\n        return new Watcher() {\n            @Override\n            public void process(WatchedEvent event) {\n                watchCount.decrementAndGet();\n                System.out.printf(\"%d event = %s\\n\", discrepancy(), event);\n            }\n        };\n\n    }\n\n    private static void waitByYielding(long delay) {\n        long t0 = Time.currentElapsedTime();\n        while (Time.currentElapsedTime() < t0 + delay) {\n            Thread.yield();\n        }\n    }\n\n    private static long discrepancy() {\n        return (System.currentTimeMillis() - mt0) - (Time.currentElapsedTime() - nt0);\n    }\n\n    @Test\n    public void testElapsedTimeToDate() throws Exception {\n        long walltime = Time.currentWallTime();\n        long elapsedTime = Time.currentElapsedTime();\n        Thread.sleep(200);\n\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(Time.elapsedTimeToDate(elapsedTime));\n        int calculatedDate = cal.get(Calendar.HOUR_OF_DAY);\n        cal.setTime(new Date(walltime));\n        int realDate = cal.get(Calendar.HOUR_OF_DAY);\n\n        Assert.assertEquals(calculatedDate, realDate);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/CRCTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.zip.Adler32;\nimport java.util.zip.CheckedInputStream;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.InputArchive;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.persistence.FileSnap;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.TxnLog.TxnIterator;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class CRCTest extends ZKTestCase implements Watcher {\n    private static final Logger LOG = LoggerFactory.getLogger(CRCTest.class);\n\n    private static final String HOSTPORT =\n        \"127.0.0.1:\" + PortAssignment.unique();\n    private volatile CountDownLatch startSignal;\n\n    /**\n     * corrupt a file by writing m at 500 b\n     * offset\n     * @param file the file to be corrupted\n     * @throws IOException\n     */\n    private void corruptFile(File file) throws IOException {\n        // corrupt the logfile\n        RandomAccessFile raf  = new RandomAccessFile(file, \"rw\");\n        byte[] b = \"mahadev\".getBytes();\n        long writeLen = 500L;\n        raf.seek(writeLen);\n        //corrupting the data\n        raf.write(b);\n        raf.close();\n    }\n\n    /** return if checksum matches for a snapshot **/\n    private boolean getCheckSum(FileSnap snap, File snapFile) throws IOException {\n        DataTree dt = new DataTree();\n        Map<Long, Integer> sessions = new ConcurrentHashMap<Long, Integer>();\n        InputStream snapIS = new BufferedInputStream(new FileInputStream(\n                snapFile));\n        CheckedInputStream crcIn = new CheckedInputStream(snapIS, new Adler32());\n        InputArchive ia = BinaryInputArchive.getArchive(crcIn);\n        try {\n            snap.deserialize(dt, sessions, ia);\n        } catch (IOException ie) {\n            // we failed on the most recent snapshot\n            // must be incomplete\n            // try reading the next one\n            // after corrupting\n            snapIS.close();\n            crcIn.close();\n            throw ie;\n        }\n\n        long checksum = crcIn.getChecksum().getValue();\n        long val = ia.readLong(\"val\");\n        snapIS.close();\n        crcIn.close();\n        return (val != checksum);\n    }\n\n    /** test checksums for the logs and snapshots.\n     * the reader should fail on reading\n     * a corrupt snapshot and a corrupt log\n     * file\n     * @throws Exception\n     */\n    @Test\n    public void testChecksums() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(150);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        LOG.info(\"starting up the zookeeper server .. waiting\");\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        try {\n            for (int i =0; i < 2000; i++) {\n                zk.create(\"/crctest- \" + i , (\"/crctest- \" + i).getBytes(),\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n        f.shutdown();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(HOSTPORT,\n                           ClientBase.CONNECTION_TIMEOUT));\n\n        File versionDir = new File(tmpDir, \"version-2\");\n        File[] list = versionDir.listFiles();\n        //there should be only two files\n        // one the snapshot and the other logFile\n        File snapFile = null;\n        File logFile = null;\n        for (File file: list) {\n            LOG.info(\"file is \" + file);\n            if (file.getName().startsWith(\"log\")) {\n                logFile = file;\n                corruptFile(logFile);\n            }\n        }\n        FileTxnLog flog = new FileTxnLog(versionDir);\n        TxnIterator itr = flog.read(1);\n        //we will get a checksum failure\n        try {\n            while (itr.next()) {\n            }\n            Assert.assertTrue(false);\n        } catch(IOException ie) {\n            LOG.info(\"crc corruption\", ie);\n        }\n        itr.close();\n        // find the last snapshot\n        FileSnap snap = new FileSnap(versionDir);\n        List<File> snapFiles = snap.findNRecentSnapshots(2);\n        snapFile = snapFiles.get(0);\n        corruptFile(snapFile);\n        boolean cfile = false;\n        try {\n            cfile = getCheckSum(snap, snapFile);\n        } catch(IOException ie) {\n            //the last snapshot seems incompelte\n            // corrupt the last but one\n            // and use that\n            snapFile = snapFiles.get(1);\n            corruptFile(snapFile);\n            cfile = getCheckSum(snap, snapFile);\n        }\n        Assert.assertTrue(cfile);\n   }\n\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \" + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected\n                && startSignal != null && startSignal.getCount() > 0)\n        {\n            startSignal.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/DataNodeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport static org.junit.Assert.*;\n\nimport java.util.Set;\n\nimport org.junit.Test;\n\npublic class DataNodeTest {\n\n    @Test\n    public void testGetChildrenShouldReturnEmptySetWhenThereAreNoChidren() {\n        // create DataNode and call getChildren\n        DataNode dataNode = new DataNode();\n        Set<String> children = dataNode.getChildren();\n        assertNotNull(children);\n        assertEquals(0, children.size());\n\n        // add child,remove child and then call getChildren\n        String child = \"child\";\n        dataNode.addChild(child);\n        dataNode.removeChild(child);\n        children = dataNode.getChildren();\n        assertNotNull(children);\n        assertEquals(0, children.size());\n\n        // Returned empty set must not be modifiable\n        children = dataNode.getChildren();\n        try {\n            children.add(\"new child\");\n            fail(\"UnsupportedOperationException is expected\");\n        } catch (UnsupportedOperationException e) {\n            // do nothing\n        }\n    }\n\n    @Test\n    public void testGetChildrenReturnsImmutableEmptySet() {\n        DataNode dataNode = new DataNode();\n        Set<String> children = dataNode.getChildren();\n        try {\n            children.add(\"new child\");\n            fail(\"UnsupportedOperationException is expected\");\n        } catch (UnsupportedOperationException e) {\n            // do nothing\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/DataTreeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.KeeperException.NodeExistsException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.DataTree;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.apache.zookeeper.server.DataNode;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport org.apache.zookeeper.Quotas;\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.common.PathTrie;\nimport java.lang.reflect.*;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class DataTreeTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(DataTreeTest.class);\n\n    private DataTree dt;\n\n    @Before\n    public void setUp() throws Exception {\n        dt=new DataTree();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        dt=null;\n    }\n\n    /**\n     * For ZOOKEEPER-1755 - Test race condition when taking dumpEphemerals and\n     * removing the session related ephemerals from DataTree structure\n     */\n    @Test(timeout = 60000)\n    public void testDumpEphemerals() throws Exception {\n        int count = 1000;\n        long session = 1000;\n        long zxid = 2000;\n        final DataTree dataTree = new DataTree();\n        LOG.info(\"Create {} zkclient sessions and its ephemeral nodes\", count);\n        createEphemeralNode(session, dataTree, count);\n        final AtomicBoolean exceptionDuringDumpEphemerals = new AtomicBoolean(\n                false);\n        final AtomicBoolean running = new AtomicBoolean(true);\n        Thread thread = new Thread() {\n            public void run() {\n                PrintWriter pwriter = new PrintWriter(new StringWriter());\n                try {\n                    while (running.get()) {\n                        dataTree.dumpEphemerals(pwriter);\n                    }\n                } catch (Exception e) {\n                    LOG.error(\"Received exception while dumpEphemerals!\", e);\n                    exceptionDuringDumpEphemerals.set(true);\n                }\n            };\n        };\n        thread.start();\n        LOG.debug(\"Killing {} zkclient sessions and its ephemeral nodes\", count);\n        killZkClientSession(session, zxid, dataTree, count);\n        running.set(false);\n        thread.join();\n        Assert.assertFalse(\"Should have got exception while dumpEphemerals!\",\n                exceptionDuringDumpEphemerals.get());\n    }\n\n    private void killZkClientSession(long session, long zxid,\n            final DataTree dataTree, int count) {\n        for (int i = 0; i < count; i++) {\n            dataTree.killSession(session + i, zxid);\n        }\n    }\n\n    private void createEphemeralNode(long session, final DataTree dataTree,\n            int count) throws NoNodeException, NodeExistsException {\n        for (int i = 0; i < count; i++) {\n            dataTree.createNode(\"/test\" + i, new byte[0], null, session + i,\n                    dataTree.getNode(\"/\").stat.getCversion() + 1, 1, 1);\n        }\n    }\n    \n    @Test(timeout = 60000)\n    public void testRootWatchTriggered() throws Exception {\n        class MyWatcher implements Watcher{\n            boolean fired=false;\n            public void process(WatchedEvent event) {\n                if(event.getPath().equals(\"/\"))\n                    fired=true;\n            }\n        }\n        MyWatcher watcher=new MyWatcher();\n        // set a watch on the root node\n        dt.getChildren(\"/\", new Stat(), watcher);\n        // add a new node, should trigger a watch\n        dt.createNode(\"/xyz\", new byte[0], null, 0, dt.getNode(\"/\").stat.getCversion()+1, 1, 1);\n        Assert.assertFalse(\"Root node watch not triggered\",!watcher.fired);\n    }\n\n    /**\n     * For ZOOKEEPER-1046 test if cversion is getting incremented correctly.\n     */\n    @Test(timeout = 60000)\n    public void testIncrementCversion() throws Exception {\n        dt.createNode(\"/test\", new byte[0], null, 0, dt.getNode(\"/\").stat.getCversion()+1, 1, 1);\n        DataNode zk = dt.getNode(\"/test\");\n        int prevCversion = zk.stat.getCversion();\n        long prevPzxid = zk.stat.getPzxid();\n        dt.setCversionPzxid(\"/test/\",  prevCversion + 1, prevPzxid + 1);\n        int newCversion = zk.stat.getCversion();\n        long newPzxid = zk.stat.getPzxid();\n        Assert.assertTrue(\"<cversion, pzxid> verification failed. Expected: <\" +\n                (prevCversion + 1) + \", \" + (prevPzxid + 1) + \">, found: <\" +\n                newCversion + \", \" + newPzxid + \">\",\n                (newCversion == prevCversion + 1 && newPzxid == prevPzxid + 1));\n    }\n   \n    @Test(timeout = 60000)\n    public void testPathTrieClearOnDeserialize() throws Exception {\n\n        //Create a DataTree with quota nodes so PathTrie get updated\n        DataTree dserTree = new DataTree();\n        \n        dserTree.createNode(\"/bug\", new byte[20], null, -1, 1, 1, 1);\n        dserTree.createNode(Quotas.quotaZookeeper+\"/bug\", null, null, -1, 1, 1, 1);\n        dserTree.createNode(Quotas.quotaPath(\"/bug\"), new byte[20], null, -1, 1, 1, 1);\n        dserTree.createNode(Quotas.statPath(\"/bug\"), new byte[20], null, -1, 1, 1, 1);\n        \n        //deserialize a DataTree; this should clear the old /bug nodes and pathTrie\n        DataTree tree = new DataTree();\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive oa = BinaryOutputArchive.getArchive(baos);\n        tree.serialize(oa, \"test\");\n        baos.flush();\n\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        BinaryInputArchive ia = BinaryInputArchive.getArchive(bais);\n        dserTree.deserialize(ia, \"test\");\n\n        Field pfield = DataTree.class.getDeclaredField(\"pTrie\");\n        pfield.setAccessible(true);\n        PathTrie pTrie = (PathTrie)pfield.get(dserTree);\n\n        //Check that the node path is removed from pTrie\n        Assert.assertEquals(\"/bug is still in pTrie\", \"\", pTrie.findMaxPrefix(\"/bug\"));       \n    }\n\n    /*\n     * ZOOKEEPER-2201 - OutputArchive.writeRecord can block for long periods of\n     * time, we must call it outside of the node lock.\n     * We call tree.serialize, which calls our modified writeRecord method that\n     * blocks until it can verify that a separate thread can lock the DataNode\n     * currently being written, i.e. that DataTree.serializeNode does not hold\n     * the DataNode lock while calling OutputArchive.writeRecord.\n     */\n    @Test(timeout = 60000)\n    public void testSerializeDoesntLockDataNodeWhileWriting() throws Exception {\n        DataTree tree = new DataTree();\n        tree.createNode(\"/marker\", new byte[] {42}, null, -1, 1, 1, 1);\n        final DataNode markerNode = tree.getNode(\"/marker\");\n        final AtomicBoolean ranTestCase = new AtomicBoolean();\n        DataOutputStream out = new DataOutputStream(new ByteArrayOutputStream());\n        BinaryOutputArchive oa = new BinaryOutputArchive(out) {\n            @Override\n            public void writeRecord(Record r, String tag) throws IOException {\n                DataNode node = (DataNode) r;\n                if (node.data.length == 1 && node.data[0] == 42) {\n                    final Semaphore semaphore = new Semaphore(0);\n                    new Thread(new Runnable() {\n                        @Override\n                        public void run() {\n                            synchronized (markerNode) {\n                                //When we lock markerNode, allow writeRecord to continue\n                                semaphore.release();\n                            }\n                        }\n                    }).start();\n\n                    try {\n                        boolean acquired = semaphore.tryAcquire(30, TimeUnit.SECONDS);\n                        //This is the real assertion - could another thread lock\n                        //the DataNode we're currently writing\n                        Assert.assertTrue(\"Couldn't acquire a lock on the DataNode while we were calling tree.serialize\", acquired);\n                    } catch (InterruptedException e1) {\n                        throw new RuntimeException(e1);\n                    }\n                    ranTestCase.set(true);\n                }\n                super.writeRecord(r, tag);\n            }\n        };\n\n        tree.serialize(oa, \"test\");\n\n        //Let's make sure that we hit the code that ran the real assertion above\n        Assert.assertTrue(\"Didn't find the expected node\", ranTestCase.get());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/DataTreeUnitTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class DataTreeUnitTest extends ZKTestCase {\n    DataTree dt;\n\n    @Before\n    public void setUp() throws Exception {\n        dt=new DataTree();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        dt=null;\n    }\n\n    @Test\n    public void testRootWatchTriggered() throws Exception {\n        class MyWatcher implements Watcher{\n            boolean fired=false;\n            public void process(WatchedEvent event) {\n                if(event.getPath().equals(\"/\"))\n                    fired=true;\n            }\n        }\n        MyWatcher watcher=new MyWatcher();\n        // set a watch on the root node\n        dt.getChildren(\"/\", new Stat(), watcher);\n        // add a new node, should trigger a watch\n        dt.createNode(\"/xyz\", new byte[0], null, 0, dt.getNode(\"/\").stat.getCversion()+1, 1, 1);\n        Assert.assertFalse(\"Root node watch not triggered\",!watcher.fired);\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/DatadirCleanupManagerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.apache.zookeeper.server.DatadirCleanupManager.PurgeTaskStatus.COMPLETED;\nimport static org.apache.zookeeper.server.DatadirCleanupManager.PurgeTaskStatus.NOT_STARTED;\nimport static org.apache.zookeeper.server.DatadirCleanupManager.PurgeTaskStatus.STARTED;\n\nimport java.io.File;\n\nimport junit.framework.Assert;\n\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class DatadirCleanupManagerTest {\n\n    private DatadirCleanupManager purgeMgr;\n    private String snapDir;\n    private String dataLogDir;\n\n    @Before\n    public void setUp() throws Exception {\n        File dataDir = ClientBase.createTmpDir();\n        snapDir = dataDir.getAbsolutePath();\n        dataLogDir = dataDir.getAbsolutePath();\n    }\n\n    @Test\n    public void testPurgeTask() throws Exception {\n        purgeMgr = new DatadirCleanupManager(snapDir, dataLogDir, 3, 1);\n        purgeMgr.start();\n        Assert.assertEquals(\"Data log directory is not set as configured\",\n                dataLogDir, purgeMgr.getDataLogDir());\n        Assert.assertEquals(\"Snapshot directory is not set as configured\",\n                snapDir, purgeMgr.getSnapDir());\n        Assert.assertEquals(\"Snapshot retain count is not set as configured\",\n                3, purgeMgr.getSnapRetainCount());\n        Assert.assertEquals(\"Purge task is not started\", STARTED, purgeMgr.getPurgeTaskStatus());\n        purgeMgr.shutdown();\n        Assert.assertEquals(\"Purge task is still running after shutdown\", COMPLETED,\n                purgeMgr.getPurgeTaskStatus());\n    }\n\n    @Test\n    public void testWithZeroPurgeInterval() throws Exception {\n        purgeMgr = new DatadirCleanupManager(snapDir, dataLogDir, 3, 0);\n        purgeMgr.start();\n        Assert.assertEquals(\"Purge task is scheduled with zero purge interval\", NOT_STARTED,\n                purgeMgr.getPurgeTaskStatus());\n        purgeMgr.shutdown();\n        Assert.assertEquals(\"Purge task is scheduled with zero purge interval\", NOT_STARTED,\n                purgeMgr.getPurgeTaskStatus());\n    }\n\n    @Test\n    public void testWithNegativePurgeInterval() throws Exception {\n        purgeMgr = new DatadirCleanupManager(snapDir, dataLogDir, 3, -1);\n        purgeMgr.start();\n        Assert.assertEquals(\"Purge task is scheduled with negative purge interval\",\n                NOT_STARTED, purgeMgr.getPurgeTaskStatus());\n        purgeMgr.shutdown();\n        Assert.assertEquals(\"Purge task is scheduled with negative purge interval\", NOT_STARTED,\n                purgeMgr.getPurgeTaskStatus());\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if (purgeMgr != null) {\n            purgeMgr.shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/DeserializationPerfTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class DeserializationPerfTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(DeserializationPerfTest.class);\n\n    private static void deserializeTree(int depth, int width, int len)\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        BinaryInputArchive ia;\n        int count;\n        {\n            DataTree tree = new DataTree();\n            SerializationPerfTest.createNodes(tree, \"/\", depth, tree.getNode(\"/\").stat.getCversion(), width, new byte[len]);\n            count = tree.getNodeCount();\n\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryOutputArchive oa = BinaryOutputArchive.getArchive(baos);\n            tree.serialize(oa, \"test\");\n            baos.flush();\n\n            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n            ia = BinaryInputArchive.getArchive(bais);\n        }\n\n        DataTree dserTree = new DataTree();\n\n        System.gc();\n        long start = System.nanoTime();\n        dserTree.deserialize(ia, \"test\");\n        long end = System.nanoTime();\n        long durationms = (end - start) / 1000000L;\n        long pernodeus = ((end - start) / 1000L) / count;\n\n        Assert.assertEquals(count, dserTree.getNodeCount());\n\n        LOG.info(\"Deserialized \" + count + \" nodes in \" + durationms\n                + \" ms (\" + pernodeus + \"us/node), depth=\" + depth + \" width=\"\n                + width + \" datalen=\" + len);\n    }\n\n    @Test\n    public void testSingleDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(1, 0, 20);\n    }\n\n    @Test\n    public void testWideDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(2, 10000, 20);\n    }\n\n    @Test\n    public void testDeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(400, 1, 20);\n    }\n\n    @Test\n    public void test10Wide5DeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(5, 10, 20);\n    }\n\n    @Test\n    public void test15Wide5DeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(5, 15, 20);\n    }\n\n    @Test\n    public void test25Wide4DeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(4, 25, 20);\n    }\n\n    @Test\n    public void test40Wide4DeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(4, 40, 20);\n    }\n\n    @Test\n    public void test300Wide3DeepDeserialize() throws\n            InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        deserializeTree(3, 300, 20);\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/InvalidSnapCountTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Test stand-alone server.\n *\n */\npublic class InvalidSnapCountTest extends ZKTestCase implements Watcher {\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(InvalidSnapCountTest.class);\n\n    public static class MainThread extends Thread {\n        final File confFile;\n        final TestMain main;\n\n        public MainThread(int clientPort) throws IOException {\n            super(\"Standalone server with clientPort:\" + clientPort);\n            File tmpDir = ClientBase.createTmpDir();\n            confFile = new File(tmpDir, \"zoo.cfg\");\n\n            FileWriter fwriter = new FileWriter(confFile);\n            fwriter.write(\"tickTime=2000\\n\");\n            fwriter.write(\"initLimit=10\\n\");\n            fwriter.write(\"syncLimit=5\\n\");\n            fwriter.write(\"snapCount=1\\n\");\n\n            File dataDir = new File(tmpDir, \"data\");\n            if (!dataDir.mkdir()) {\n                throw new IOException(\"unable to mkdir \" + dataDir);\n            }\n            \n            // Convert windows path to UNIX to avoid problems with \"\\\"\n            String dir = dataDir.toString();\n            String osname = java.lang.System.getProperty(\"os.name\");\n            if (osname.toLowerCase().contains(\"windows\")) {\n                dir = dir.replace('\\\\', '/');\n            }\n            fwriter.write(\"dataDir=\" + dir + \"\\n\");\n            \n            fwriter.write(\"clientPort=\" + clientPort + \"\\n\");\n            fwriter.flush();\n            fwriter.close();\n\n            main = new TestMain();\n        }\n\n        public void run() {\n            String args[] = new String[1];\n            args[0] = confFile.toString();\n            try {\n                main.initializeAndRun(args);\n            } catch (Exception e) {\n                // test will still fail even though we just log/ignore\n                LOG.error(\"unexpected exception in run\", e);\n            }\n        }\n\n        public void shutdown() {\n            main.shutdown();\n        }\n    }\n\n    public static  class TestMain extends ZooKeeperServerMain {\n        public void shutdown() {\n            super.shutdown();\n        }\n    }\n\n    /**\n     * Verify the ability to start a standalone server instance.\n     */\n    @Test\n    public void testInvalidSnapCount() throws Exception {\n\n        final int CLIENT_PORT = 3181;\n\n        MainThread main = new MainThread(CLIENT_PORT);\n        main.start();\n\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT));\n\n        Assert.assertEquals(SyncRequestProcessor.getSnapCount(), 2);\n\n        main.shutdown();\n\n    }\n\n    public void process(WatchedEvent event) {\n        // ignore for this test\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/InvalidSnapshotTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This test checks that the server works even if the last snapshot is\n * invalidated by corruption or if the server crashes while generating the\n * snapshot.\n */\npublic class InvalidSnapshotTest extends ClientBase {\n    private static final Logger LOG =\n            LoggerFactory.getLogger(InvalidSnapshotTest.class);\n\n    public InvalidSnapshotTest() {\n        SyncRequestProcessor.setSnapCount(100);\n    }\n\n    /**\n     * Validate that the server can come up on an invalid snapshot - by\n     * reverting to a prior snapshot + associated logs.\n     */\n    @Test\n    public void testInvalidSnapshot() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            for (int i = 0; i < 2000; i++) {\n                zk.create(\"/invalidsnap-\" + i, new byte[0],\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n        NIOServerCnxnFactory factory = (NIOServerCnxnFactory)serverFactory;\n        stopServer();\n\n        // now corrupt the snapshot\n        File snapFile = factory.zkServer.getTxnLogFactory().findMostRecentSnapshot();\n        LOG.info(\"Corrupting \" + snapFile);\n        RandomAccessFile raf = new RandomAccessFile(snapFile, \"rws\");\n        raf.setLength(3);\n        raf.close();\n\n        // now restart the server\n        startServer();\n\n        // verify that the expected data exists and wasn't lost\n        zk = createClient();\n        try {\n            assertTrue(\"the node should exist\",\n                    (zk.exists(\"/invalidsnap-1999\", false) != null));\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/MockNIOServerCnxn.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.SocketChannel;\nimport java.io.IOException;\n\npublic class MockNIOServerCnxn extends NIOServerCnxn {\n\n    public MockNIOServerCnxn(ZooKeeperServer zk, SocketChannel sock,\n                         SelectionKey sk, NIOServerCnxnFactory factory)\n                         throws IOException {\n        super(zk, sock, sk, factory);\n    }\n\n    /**\n     * Handles read/write IO on connection.\n     */\n    public void doIO(SelectionKey k) throws InterruptedException {\n        super.doIO(k);\n    }\n\n     @Override\n     protected boolean isSocketOpen() {\n         return true;\n     }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/NIOServerCnxnTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.CancelledKeyException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class NIOServerCnxnTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(NIOServerCnxnTest.class);\n    /**\n     * Test operations on ServerCnxn after socket closure.\n     */\n    @Test(timeout = 60000)\n    public void testOperationsAfterCnxnClose() throws IOException,\n            InterruptedException, KeeperException {\n        final ZooKeeper zk = createClient();\n\n        final String path = \"/a\";\n        try {\n            // make sure zkclient works\n            zk.create(path, \"test\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            Assert.assertNotNull(\"Didn't create znode:\" + path,\n                    zk.exists(path, false));\n            // Defaults ServerCnxnFactory would be instantiated with\n            // NIOServerCnxnFactory\n            Assert.assertTrue(\n                    \"Didn't instantiate ServerCnxnFactory with NIOServerCnxnFactory!\",\n                    serverFactory instanceof NIOServerCnxnFactory);\n            Iterable<ServerCnxn> connections = serverFactory.getConnections();\n            for (ServerCnxn serverCnxn : connections) {\n                serverCnxn.close();\n                try {\n                    serverCnxn.toString();\n                } catch (Exception e) {\n                    LOG.error(\"Exception while getting connection details!\", e);\n                    Assert.fail(\"Shouldn't throw exception while \"\n                            + \"getting connection details!\");\n                }\n            }\n        } finally {\n            zk.close();\n        }\n    }\n\n    /**\n     * Mock extension of NIOServerCnxn to test for\n     * CancelledKeyException (ZOOKEEPER-2044).\n     */\n    private static class MockNIOServerCnxn extends NIOServerCnxn {\n        public MockNIOServerCnxn(NIOServerCnxn cnxn)\n                throws IOException {\n            super(cnxn.zkServer, cnxn.sock, cnxn.sk, cnxn.factory);\n        }\n\n        public void mockSendBuffer(ByteBuffer bb) throws Exception {\n            super.internalSendBuffer(bb);\n        }\n    }\n\n    @Test(timeout = 30000)\n    public void testValidSelectionKey() throws Exception {\n        final ZooKeeper zk = createZKClient(hostPort, 3000);\n        try {\n            Iterable<ServerCnxn> connections = serverFactory.getConnections();\n            for (ServerCnxn serverCnxn : connections) {\n                MockNIOServerCnxn mock = new MockNIOServerCnxn((NIOServerCnxn) serverCnxn);\n                // Cancel key\n                ((NIOServerCnxn) serverCnxn).sock.keyFor(((NIOServerCnxnFactory) serverFactory).selector).cancel();;\n                mock.mockSendBuffer(ByteBuffer.allocate(8));\n            }\n        } catch (CancelledKeyException e) {\n            LOG.error(\"Exception while sending bytes!\", e);\n            Assert.fail(e.toString());\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/NettyServerCnxnTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport junit.framework.Assert;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.NettyServerCnxnFactory.CnxnChannelHandler;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.ChannelStateEvent;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Test verifies the behavior of NettyServerCnxn which represents a connection\n * from a client to the server.\n */\npublic class NettyServerCnxnTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(NettyServerCnxnTest.class);\n\n    @Override\n    public void setUp() throws Exception {\n        System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                \"org.apache.zookeeper.server.NettyServerCnxnFactory\");\n        super.setUp();\n    }\n\n    /**\n     * Test verifies the channel closure - while closing the channel\n     * servercnxnfactory should remove all channel references to avoid\n     * duplicate channel closure. Duplicate closure may result in \n     * indefinite hanging due to netty open issue.\n     * \n     * @see <a href=\"https://issues.jboss.org/browse/NETTY-412\">NETTY-412</a>\n     */\n    @Test(timeout = 30000)\n    public void testSendCloseSession() throws Exception {\n        Assert.assertTrue(\n                \"Didn't instantiate ServerCnxnFactory with NettyServerCnxnFactory!\",\n                serverFactory instanceof NettyServerCnxnFactory);\n\n        NettyServerCnxnFactory nettyServerFactory = (NettyServerCnxnFactory) serverFactory;\n        final CountDownLatch channelLatch = new CountDownLatch(1);\n        CnxnChannelHandler channelHandler = nettyServerFactory.new CnxnChannelHandler() {\n            @Override\n            public void channelDisconnected(ChannelHandlerContext ctx,\n                    ChannelStateEvent e) throws Exception {\n                LOG.info(\"Recieves channel disconnected event\");\n                channelLatch.countDown();\n            }\n        };\n        LOG.info(\"Adding custom channel handler for simulation\");\n        nettyServerFactory.bootstrap.getPipeline().remove(\"servercnxnfactory\");\n        nettyServerFactory.bootstrap.getPipeline().addLast(\"servercnxnfactory\",\n                channelHandler);\n\n        final ZooKeeper zk = createClient();\n        final String path = \"/a\";\n        try {\n            // make sure zkclient works\n            zk.create(path, \"test\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            Assert.assertNotNull(\"Didn't create znode:\" + path,\n                    zk.exists(path, false));\n            Iterable<ServerCnxn> connections = serverFactory.getConnections();\n            Assert.assertEquals(\"Mismatch in number of live connections!\", 1,\n                    serverFactory.getNumAliveConnections());\n            for (ServerCnxn serverCnxn : connections) {\n                serverCnxn.sendCloseSession();\n            }\n            LOG.info(\"Waiting for the channel disconnected event\");\n            channelLatch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);\n            Assert.assertEquals(\"Mismatch in number of live connections!\", 0,\n                    serverFactory.getNumAliveConnections());\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/PrepRequestProcessorTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.SessionExpiredException;\nimport org.apache.zookeeper.KeeperException.SessionMovedException;\nimport org.apache.zookeeper.MultiTransactionRecord;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.proto.SetDataRequest;\nimport org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.ByteBuffer;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class PrepRequestProcessorTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory.getLogger(PrepRequestProcessorTest.class);\n    private static final int CONNECTION_TIMEOUT = 3000;\n    private static String HOSTPORT = \"127.0.0.1:\" + PortAssignment.unique();\n    private CountDownLatch pLatch;\n\n    private ZooKeeperServer zks;\n    private ServerCnxnFactory servcnxnf;\n    private PrepRequestProcessor processor;\n    private Request outcome;\n\n    @Before\n    public void setup() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(100);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n\n        servcnxnf = ServerCnxnFactory.createFactory(PORT, -1);\n        servcnxnf.startup(zks);\n        Assert.assertTrue(\"waiting for server being up \",\n                ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n        zks.sessionTracker = new MySessionTracker();\n    }\n\n    @After\n    public void teardown() throws Exception {\n        if (servcnxnf != null) {\n            servcnxnf.shutdown();\n        }\n        if (zks != null) {\n            zks.shutdown();\n        }\n    }\n\n    @Test\n    public void testPRequest() throws Exception {\n        pLatch = new CountDownLatch(1);\n        processor = new PrepRequestProcessor(zks, new MyRequestProcessor());\n        Request foo = new Request(null, 1l, 1, OpCode.create, ByteBuffer.allocate(3), null);\n        processor.pRequest(foo);\n\n        Assert.assertEquals(\"Request should have marshalling error\", new ErrorTxn(KeeperException.Code.MARSHALLINGERROR.intValue()),\n                outcome.txn);\n        Assert.assertTrue(\"request hasn't been processed in chain\", pLatch.await(5, TimeUnit.SECONDS));\n    }\n\n    private Request createRequest(Record record, int opCode) throws IOException {\n        // encoding\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n        record.serialize(boa, \"request\");\n        baos.close();\n\n        // Id\n        List<Id> ids = Arrays.asList(Ids.ANYONE_ID_UNSAFE);\n\n        return new Request(null, 1l, 0, opCode, ByteBuffer.wrap(baos.toByteArray()), ids);\n    }\n\n    private void process(List<Op> ops) throws Exception {\n        pLatch = new CountDownLatch(1);\n        processor = new PrepRequestProcessor(zks, new MyRequestProcessor());\n\n        Record record = new MultiTransactionRecord(ops);\n        Request req = createRequest(record, OpCode.multi);\n\n        processor.pRequest(req);\n        Assert.assertTrue(\"request hasn't been processed in chain\", pLatch.await(5, TimeUnit.SECONDS));\n    }\n\n    /**\n     * This test checks that a successful multi will change outstanding record\n     * and failed multi shouldn't change outstanding record.\n     */\n    @Test\n    public void testMultiOutstandingChange() throws Exception {\n        zks.getZKDatabase().dataTree.createNode(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE, 0, 0, 0, 0);\n\n        Assert.assertNull(zks.outstandingChangesForPath.get(\"/foo\"));\n\n        process(Arrays.asList(\n                Op.setData(\"/foo\", new byte[0], -1)));\n\n        ChangeRecord cr = zks.outstandingChangesForPath.get(\"/foo\");\n        Assert.assertNotNull(\"Change record wasn't set\", cr);\n        Assert.assertEquals(\"Record zxid wasn't set correctly\",\n                1, cr.zxid);\n\n        process(Arrays.asList(\n                Op.delete(\"/foo\", -1)));\n        cr = zks.outstandingChangesForPath.get(\"/foo\");\n        Assert.assertEquals(\"Record zxid wasn't set correctly\",\n                2, cr.zxid);\n\n\n        // It should fail and shouldn't change outstanding record.\n        process(Arrays.asList(\n                Op.delete(\"/foo\", -1)));\n        cr = zks.outstandingChangesForPath.get(\"/foo\");\n        // zxid should still be previous result because record's not changed.\n        Assert.assertEquals(\"Record zxid wasn't set correctly\",\n                2, cr.zxid);\n    }\n\n    /**\n     * ZOOKEEPER-2052:\n     * This test checks that if a multi operation aborted, and during the multi there is side effect\n     * that changed outstandingChangesForPath, after aborted the side effect should be removed and\n     * everything should be restored correctly.\n     */\n    @Test\n    public void testMultiRollbackNoLastChange() throws Exception {\n        zks.getZKDatabase().dataTree.createNode(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE, 0, 0, 0, 0);\n        zks.getZKDatabase().dataTree.createNode(\"/foo/bar\", new byte[0], Ids.OPEN_ACL_UNSAFE, 0, 0, 0, 0);\n\n        Assert.assertNull(zks.outstandingChangesForPath.get(\"/foo\"));\n\n        // multi record:\n        //   set \"/foo\" => succeed, leave a outstanding change\n        //   delete \"/foo\" => fail, roll back change\n        process(Arrays.asList(\n                Op.setData(\"/foo\", new byte[0], -1),\n                Op.delete(\"/foo\", -1)));\n\n        // aborting multi shouldn't leave any record.\n        Assert.assertNull(zks.outstandingChangesForPath.get(\"/foo\"));\n    }\n\n    /**\n     * It tests that PrepRequestProcessor will return BadArgument KeeperException\n     * if the request path (if it exists) is not valid, e.g. empty string.\n     */\n    @Test\n    public void testInvalidPath() throws Exception {\n        pLatch = new CountDownLatch(1);\n        processor = new PrepRequestProcessor(zks, new MyRequestProcessor());\n\n        SetDataRequest record = new SetDataRequest(\"\", new byte[0], -1);\n        Request req = createRequest(record, OpCode.setData);\n        processor.pRequest(req);\n        pLatch.await();\n        Assert.assertEquals(outcome.hdr.getType(), OpCode.error);\n        Assert.assertEquals(outcome.getException().code(), KeeperException.Code.BADARGUMENTS);\n    }\n\n    private class MyRequestProcessor implements RequestProcessor {\n        @Override\n        public void processRequest(Request request) {\n            // getting called by PrepRequestProcessor\n            outcome = request;\n            pLatch.countDown();\n        }\n\n        @Override\n        public void shutdown() {\n            // TODO Auto-generated method stub\n        }\n    }\n\n    private class MySessionTracker implements SessionTracker {\n        @Override\n        public void addSession(long id, int to) {\n            // TODO Auto-generated method stub\n            \n        }\n        @Override\n        public void checkSession(long sessionId, Object owner)\n                throws SessionExpiredException, SessionMovedException {\n            // TODO Auto-generated method stub\n            \n        }\n        @Override\n        public long createSession(int sessionTimeout) {\n            // TODO Auto-generated method stub\n            return 0;\n        }\n        @Override\n        public void dumpSessions(PrintWriter pwriter) {\n            // TODO Auto-generated method stub\n            \n        }\n         @Override\n        public void removeSession(long sessionId) {\n            // TODO Auto-generated method stub\n            \n        }\n        @Override\n        public void setOwner(long id, Object owner)\n                throws SessionExpiredException {\n            // TODO Auto-generated method stub\n            \n        }\n        @Override\n        public void shutdown() {\n            // TODO Auto-generated method stub\n            \n        }\n        @Override\n        public boolean touchSession(long sessionId, int sessionTimeout) {\n            // TODO Auto-generated method stub\n            return false;\n        }\n        @Override\n        public void setSessionClosing(long sessionId) {\n          // TODO Auto-generated method stub\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/PurgeTxnTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport org.apache.zookeeper.data.Stat;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.PurgeTxnLog;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class PurgeTxnTest extends ZKTestCase implements  Watcher {\n    private static final Logger LOG = LoggerFactory.getLogger(PurgeTxnTest.class);\n    private static String HOSTPORT = \"127.0.0.1:\" + PortAssignment.unique();\n    private static final int CONNECTION_TIMEOUT = 3000;\n    private static final long OP_TIMEOUT_IN_MILLIS = 90000;\n    private File tmpDir;\n\n    @After\n    public void teardown() {\n        if (null != tmpDir) {\n            ClientBase.recursiveDelete(tmpDir);\n        }\n    }\n\n    /**\n     * test the purge\n     * @throws Exception an exception might be thrown here\n     */\n    @Test\n    public void testPurge() throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(100);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        Assert.assertTrue(\"waiting for server being up \",\n                ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        try {\n            for (int i = 0; i< 2000; i++) {\n                zk.create(\"/invalidsnap-\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n        f.shutdown();\n        zks.getTxnLogFactory().close();\n        Assert.assertTrue(\"waiting for server to shutdown\",\n                ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));\n        // now corrupt the snapshot\n        PurgeTxnLog.purge(tmpDir, tmpDir, 3);\n        FileTxnSnapLog snaplog = new FileTxnSnapLog(tmpDir, tmpDir);\n        List<File> listLogs = snaplog.findNRecentSnapshots(4);\n        int numSnaps = 0;\n        for (File ff: listLogs) {\n            if (ff.getName().startsWith(\"snapshot\")) {\n                numSnaps++;\n            }\n        }\n        Assert.assertTrue(\"exactly 3 snapshots \", (numSnaps == 3));\n        snaplog.close();\n        zks.shutdown();\n    }\n\n    /**\n     * Tests purge when logs are rolling or a new snapshot is created, then\n     * these newer files should alse be excluded in the current cycle.\n     *\n     * For frequent snapshotting, configured SnapCount to 30. There are three\n     * threads which will create 1000 znodes each and simultaneously do purge\n     * call\n     */\n    @Test\n    public void testPurgeWhenLogRollingInProgress() throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(30);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        Assert.assertTrue(\"waiting for server being up \",\n                ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n        final ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        final CountDownLatch doPurge = new CountDownLatch(1);\n        final CountDownLatch purgeFinished = new CountDownLatch(1);\n        final AtomicBoolean opFailed = new AtomicBoolean(false);\n        new Thread() {\n            public void run() {\n                try {\n                    doPurge.await(OP_TIMEOUT_IN_MILLIS / 2,\n                            TimeUnit.MILLISECONDS);\n                    PurgeTxnLog.purge(tmpDir, tmpDir, 3);\n                } catch (IOException ioe) {\n                    LOG.error(\"Exception when purge\", ioe);\n                    opFailed.set(true);\n                } catch (InterruptedException ie) {\n                    LOG.error(\"Exception when purge\", ie);\n                    opFailed.set(true);\n                } finally {\n                    purgeFinished.countDown();\n                }\n            };\n        }.start();\n        final int thCount = 3;\n        List<String> znodes = manyClientOps(zk, doPurge, thCount,\n                \"/invalidsnap\");\n        Assert.assertTrue(\"Purging is not finished!\", purgeFinished.await(\n                OP_TIMEOUT_IN_MILLIS, TimeUnit.MILLISECONDS));\n        Assert.assertFalse(\"Purging failed!\", opFailed.get());\n        for (String znode : znodes) {\n            try {\n                zk.getData(znode, false, null);\n            } catch (Exception ke) {\n                LOG.error(\"Unexpected exception when visiting znode!\", ke);\n                Assert.fail(\"Unexpected exception when visiting znode!\");\n            }\n        }\n        zk.close();\n        f.shutdown();\n        zks.shutdown();\n        zks.getTxnLogFactory().close();\n    }\n\n    /**\n     * Tests finding n recent snapshots from set of snapshots and data logs\n     */\n    @Test\n    public void testFindNRecentSnapshots() throws Exception {\n        int nRecentSnap = 4; // n recent snap shots\n        int nRecentCount = 30;\n        int offset = 0;\n\n        tmpDir = ClientBase.createTmpDir();\n        File version2 = new File(tmpDir.toString(), \"version-2\");\n        Assert.assertTrue(\"Failed to create version_2 dir:\" + version2.toString(),\n                version2.mkdir());\n\n        // Test that with no snaps, findNRecentSnapshots returns empty list\n        FileTxnSnapLog txnLog = new FileTxnSnapLog(tmpDir, tmpDir);\n        List<File> foundSnaps = txnLog.findNRecentSnapshots(1);\n        assertEquals(0, foundSnaps.size());\n\n        List<File> expectedNRecentSnapFiles = new ArrayList<File>();\n        int counter = offset + (2 * nRecentCount);\n        for (int i = 0; i < nRecentCount; i++) {\n            // simulate log file\n            File logFile = new File(version2 + \"/log.\" + Long.toHexString(--counter));\n            Assert.assertTrue(\"Failed to create log File:\" + logFile.toString(),\n                    logFile.createNewFile());\n            // simulate snapshot file\n            File snapFile = new File(version2 + \"/snapshot.\"\n                    + Long.toHexString(--counter));\n            Assert.assertTrue(\"Failed to create snap File:\" + snapFile.toString(),\n                    snapFile.createNewFile());\n            // add the n recent snap files for assertion\n            if(i < nRecentSnap){\n                expectedNRecentSnapFiles.add(snapFile);\n            }\n        }\n\n        // Test that when we ask for recent snaps we get the number we asked for and\n        // the files we expected\n        List<File> nRecentSnapFiles = txnLog.findNRecentSnapshots(nRecentSnap);\n        Assert.assertEquals(\"exactly 4 snapshots \", 4,\n                nRecentSnapFiles.size());\n        expectedNRecentSnapFiles.removeAll(nRecentSnapFiles);\n        Assert.assertEquals(\"Didn't get the recent snap files\", 0,\n                expectedNRecentSnapFiles.size());\n\n        // Test that when asking for more snaps than we created, we still only get snaps\n        // not logs or anything else (per ZOOKEEPER-2420)\n        nRecentSnapFiles = txnLog.findNRecentSnapshots(nRecentCount + 5);\n        assertEquals(nRecentCount, nRecentSnapFiles.size());\n        for (File f: nRecentSnapFiles) {\n            Assert.assertTrue(\"findNRecentSnapshots() returned a non-snapshot: \" + f.getPath(),\n                   (Util.getZxidFromName(f.getName(), \"snapshot\") != -1));\n        }\n\n        txnLog.close();\n    }\n\n    /**\n     * Tests purge where the data directory contains old snapshots and data\n     * logs, newest snapshots and data logs, (newest + n) snapshots and data\n     * logs\n     */\n    @Test\n    public void testSnapFilesGreaterThanToRetain() throws Exception {\n        int nRecentCount = 4;\n        int fileAboveRecentCount = 4;\n        int fileToPurgeCount = 2;\n        AtomicInteger offset = new AtomicInteger(0);\n        tmpDir = ClientBase.createTmpDir();\n        File version2 = new File(tmpDir.toString(), \"version-2\");\n        Assert.assertTrue(\"Failed to create version_2 dir:\" + version2.toString(),\n                version2.mkdir());\n        List<File> snapsToPurge = new ArrayList<File>();\n        List<File> logsToPurge = new ArrayList<File>();\n        List<File> snaps = new ArrayList<File>();\n        List<File> logs = new ArrayList<File>();\n        List<File> snapsAboveRecentFiles = new ArrayList<File>();\n        List<File> logsAboveRecentFiles = new ArrayList<File>();\n        createDataDirFiles(offset, fileToPurgeCount, false, version2, snapsToPurge,\n                logsToPurge);\n        createDataDirFiles(offset, nRecentCount, false, version2, snaps, logs);\n        logs.add(logsToPurge.remove(0)); // log that precedes first retained snapshot is also retained\n        createDataDirFiles(offset, fileAboveRecentCount, false, version2,\n                snapsAboveRecentFiles, logsAboveRecentFiles);\n\n        /**\n         * The newest log file preceding the oldest retained snapshot is not removed as it may\n         * contain transactions newer than the oldest snapshot.\n         */\n        logsToPurge.remove(0);\n\n        FileTxnSnapLog txnLog = new FileTxnSnapLog(tmpDir, tmpDir);\n        PurgeTxnLog.purgeOlderSnapshots(txnLog, snaps.get(snaps.size() - 1));\n        txnLog.close();\n        verifyFilesAfterPurge(snapsToPurge, false);\n        verifyFilesAfterPurge(logsToPurge, false);\n        verifyFilesAfterPurge(snaps, true);\n        verifyFilesAfterPurge(logs, true);\n        verifyFilesAfterPurge(snapsAboveRecentFiles, true);\n        verifyFilesAfterPurge(logsAboveRecentFiles, true);\n    }\n\n    /**\n     * Tests purge where the data directory contains snap files and log files equals to the\n     * number of files to be retained\n     */\n    @Test\n    public void testSnapFilesEqualsToRetain() throws Exception {\n        internalTestSnapFilesEqualsToRetain(false);\n    }\n\n    /**\n     * Tests purge where the data directory contains snap files equals to the\n     * number of files to be retained, and a log file that precedes the earliest snapshot\n     */\n    @Test\n    public void testSnapFilesEqualsToRetainWithPrecedingLog() throws Exception {\n        internalTestSnapFilesEqualsToRetain(true);\n    }\n\n    public void internalTestSnapFilesEqualsToRetain(boolean testWithPrecedingLogFile) throws Exception {\n        int nRecentCount = 3;\n        AtomicInteger offset = new AtomicInteger(0);\n        tmpDir = ClientBase.createTmpDir();\n        File version2 = new File(tmpDir.toString(), \"version-2\");\n        Assert.assertTrue(\"Failed to create version_2 dir:\" + version2.toString(),\n                version2.mkdir());\n        List<File> snaps = new ArrayList<File>();\n        List<File> logs = new ArrayList<File>();\n        createDataDirFiles(offset, nRecentCount, testWithPrecedingLogFile, version2, snaps, logs);\n\n        FileTxnSnapLog txnLog = new FileTxnSnapLog(tmpDir, tmpDir);\n        PurgeTxnLog.purgeOlderSnapshots(txnLog, snaps.get(snaps.size() - 1));\n        txnLog.close();\n        verifyFilesAfterPurge(snaps, true);\n        verifyFilesAfterPurge(logs, true);\n    }\n\n    /**\n     * Tests purge where the data directory contains old snapshots and data\n     * logs, newest snapshots and data logs\n     */\n    @Test\n    public void testSnapFilesLessThanToRetain() throws Exception {\n        int nRecentCount = 4;\n        int fileToPurgeCount = 2;\n        AtomicInteger offset = new AtomicInteger(0);\n        tmpDir = ClientBase.createTmpDir();\n        File version2 = new File(tmpDir.toString(), \"version-2\");\n        Assert.assertTrue(\"Failed to create version_2 dir:\" + version2.toString(),\n                version2.mkdir());\n        List<File> snapsToPurge = new ArrayList<File>();\n        List<File> logsToPurge = new ArrayList<File>();\n        List<File> snaps = new ArrayList<File>();\n        List<File> logs = new ArrayList<File>();\n        createDataDirFiles(offset, fileToPurgeCount, false, version2, snapsToPurge,\n                logsToPurge);\n        createDataDirFiles(offset, nRecentCount, false, version2, snaps, logs);\n        logs.add(logsToPurge.remove(0)); // log that precedes first retained snapshot is also retained\n\n        /**\n         * The newest log file preceding the oldest retained snapshot is not removed as it may\n         * contain transactions newer than the oldest snapshot.\n         */\n        logsToPurge.remove(0);\n\n        FileTxnSnapLog txnLog = new FileTxnSnapLog(tmpDir, tmpDir);\n        PurgeTxnLog.purgeOlderSnapshots(txnLog, snaps.get(snaps.size() - 1));\n        txnLog.close();\n        verifyFilesAfterPurge(snapsToPurge, false);\n        verifyFilesAfterPurge(logsToPurge, false);\n        verifyFilesAfterPurge(snaps, true);\n        verifyFilesAfterPurge(logs, true);\n    }\n\n    /**\n     * PurgeTxnLog is called with dataLogDir snapDir -n count This test case\n     * verify these values are parsed properly and functionality works fine\n     */\n    @Test\n    public void testPurgeTxnLogWithDataDir()\n            throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        File dataDir = new File(tmpDir, \"dataDir\");\n        File dataLogDir = new File(tmpDir, \"dataLogDir\");\n\n        File dataDirVersion2 = new File(dataDir, \"version-2\");\n        dataDirVersion2.mkdirs();\n        File dataLogDirVersion2 = new File(dataLogDir, \"version-2\");\n        dataLogDirVersion2.mkdirs();\n\n        // create dummy log and transaction file\n        int totalFiles = 20;\n\n        // create transaction and snapshot files in different-different\n        // directories\n        for (int i = 0; i < totalFiles; i++) {\n            // simulate log file\n            File logFile = new File(dataLogDirVersion2, \"log.\"\n                    + Long.toHexString(i));\n            logFile.createNewFile();\n            // simulate snapshot file\n            File snapFile = new File(dataDirVersion2, \"snapshot.\"\n                    + Long.toHexString(i));\n            snapFile.createNewFile();\n        }\n\n        int numberOfSnapFilesToKeep = 10;\n        // scenario where four parameter are passed\n        String[] args = new String[] { dataLogDir.getAbsolutePath(),\n                dataDir.getAbsolutePath(), \"-n\",\n                Integer.toString(numberOfSnapFilesToKeep) };\n        PurgeTxnLog.main(args);\n\n        assertEquals(numberOfSnapFilesToKeep, dataDirVersion2.listFiles().length);\n        // Since for each snapshot we have a log file with same zxid, expect same # logs as snaps to be kept\n        assertEquals(numberOfSnapFilesToKeep, dataLogDirVersion2.listFiles().length);\n        ClientBase.recursiveDelete(tmpDir);\n\n    }\n\n    /**\n     * PurgeTxnLog is called with dataLogDir -n count This test case verify\n     * these values are parsed properly and functionality works fine\n     */\n    @Test\n    public void testPurgeTxnLogWithoutDataDir()\n            throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        File dataDir = new File(tmpDir, \"dataDir\");\n        File dataLogDir = new File(tmpDir, \"dataLogDir\");\n\n        File dataDirVersion2 = new File(dataDir, \"version-2\");\n        dataDirVersion2.mkdirs();\n        File dataLogDirVersion2 = new File(dataLogDir, \"version-2\");\n        dataLogDirVersion2.mkdirs();\n\n        // create dummy log and transaction file\n        int totalFiles = 20;\n\n        // create transaction and snapshot files in data directory\n        for (int i = 0; i < totalFiles; i++) {\n            // simulate log file\n            File logFile = new File(dataLogDirVersion2, \"log.\"\n                    + Long.toHexString(i));\n            logFile.createNewFile();\n            // simulate snapshot file\n            File snapFile = new File(dataLogDirVersion2, \"snapshot.\"\n                    + Long.toHexString(i));\n            snapFile.createNewFile();\n        }\n\n        int numberOfSnapFilesToKeep = 10;\n        // scenario where only three parameter are passed\n        String[] args = new String[] { dataLogDir.getAbsolutePath(), \"-n\",\n                Integer.toString(numberOfSnapFilesToKeep) };\n        PurgeTxnLog.main(args);\n        assertEquals(numberOfSnapFilesToKeep * 2, // Since for each snapshot we have a log file with same zxid, expect same # logs as snaps to be kept\n                dataLogDirVersion2.listFiles().length);\n        ClientBase.recursiveDelete(tmpDir);\n\n    }\n\n    /**\n     * Verifies that purge does not delete any log files which started before the oldest retained\n     * snapshot but which might extend beyond it.\n     * @throws Exception an exception might be thrown here\n     */\n    @Test\n    public void testPurgeDoesNotDeleteOverlappingLogFile() throws Exception {\n        // Setting used for snapRetainCount in this test.\n        final int SNAP_RETAIN_COUNT = 3;\n        // Number of znodes this test creates in each snapshot.\n        final int NUM_ZNODES_PER_SNAPSHOT = 100;\n        /**\n         * Set a sufficiently high snapCount to ensure that we don't rollover the log.  Normally,\n         * the default value (100K at time of this writing) would ensure this, but we make that\n         * dependence explicit here to make the test future-proof.  Not rolling over the log is\n         * important for this test since we are testing retention of the one and only log file which\n         * predates each retained snapshot.\n         */\n        SyncRequestProcessor.setSnapCount(SNAP_RETAIN_COUNT * NUM_ZNODES_PER_SNAPSHOT * 10);\n\n        // Create Zookeeper and connect to it.\n        tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        Assert.assertTrue(\"waiting for server being up \",\n                ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));\n        ZooKeeper zk = ClientBase.createZKClient(HOSTPORT);\n\n        // Unique identifier for each znode that we create.\n        int unique = 0;\n        try {\n            /**\n             * Create some znodes and take a snapshot.  Repeat this until we have SNAP_RETAIN_COUNT\n             * snapshots.  Do not rollover the log.\n             */\n            for (int snapshotCount = 0; snapshotCount < SNAP_RETAIN_COUNT; snapshotCount++) {\n                for (int i = 0; i< 100; i++, unique++) {\n                    zk.create(\"/snap-\" + unique, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                            CreateMode.PERSISTENT);\n                }\n                zks.takeSnapshot();\n            }\n            // Create some additional znodes without taking a snapshot afterwards.\n            for (int i = 0; i< 100; i++, unique++) {\n                zk.create(\"/snap-\" + unique, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n\n        // Shutdown Zookeeper.\n        f.shutdown();\n        zks.getTxnLogFactory().close();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server to shutdown\",\n                ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));\n\n        // Purge snapshot and log files.\n        PurgeTxnLog.purge(tmpDir, tmpDir, SNAP_RETAIN_COUNT);\n\n        // Initialize Zookeeper again from the same dataDir.\n        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        zk = ClientBase.createZKClient(HOSTPORT);\n\n        /**\n         * Verify that the last znode that was created above exists.  This znode's creation was\n         * captured by the transaction log which was created before any of the above\n         * SNAP_RETAIN_COUNT snapshots were created, but it's not captured in any of these\n         * snapshots.  So for it it exist, the (only) existing log file should not have been purged.\n         */\n        final String lastZnode = \"/snap-\" + (unique - 1);\n        final Stat stat = zk.exists(lastZnode, false);\n        Assert.assertNotNull(\"Last znode does not exist: \" + lastZnode, stat);\n\n        // Shutdown for the last time.\n        f.shutdown();\n        zks.getTxnLogFactory().close();\n        zks.shutdown();\n    }\n\n    private File createDataDirLogFile(File version_2, int Zxid) throws IOException {\n        File logFile = new File(version_2 + \"/log.\" + Long.toHexString(Zxid));\n        Assert.assertTrue(\"Failed to create log File:\" + logFile.toString(),\n                logFile.createNewFile());\n        return logFile;\n    }\n\n    private void createDataDirFiles(AtomicInteger offset, int limit, boolean createPrecedingLogFile,\n            File version_2, List<File> snaps, List<File> logs)\n            throws IOException {\n        int counter = offset.get() + (2 * limit);\n        if (createPrecedingLogFile) {\n            counter++;\n        }\n        offset.set(counter);\n        for (int i = 0; i < limit; i++) {\n            // simulate log file\n            logs.add(createDataDirLogFile(version_2, --counter));\n            // simulate snapshot file\n            File snapFile = new File(version_2 + \"/snapshot.\"\n                    + Long.toHexString(--counter));\n            Assert.assertTrue(\"Failed to create snap File:\" + snapFile.toString(),\n                    snapFile.createNewFile());\n            snaps.add(snapFile);\n        }\n        if (createPrecedingLogFile) {\n            logs.add(createDataDirLogFile(version_2, --counter));\n        }\n    }\n\n    private void verifyFilesAfterPurge(List<File> logs, boolean exists) {\n        for (File file : logs) {\n            Assert.assertEquals(\"After purging, file \" + file, exists,\n                    file.exists());\n        }\n    }\n\n    private List<String> manyClientOps(final ZooKeeper zk,\n            final CountDownLatch doPurge, int thCount, final String prefix) {\n        Thread[] ths = new Thread[thCount];\n        final List<String> znodes = Collections\n                .synchronizedList(new ArrayList<String>());\n        final CountDownLatch finished = new CountDownLatch(thCount);\n        for (int indx = 0; indx < thCount; indx++) {\n            final String myprefix = prefix + \"-\" + indx;\n            Thread th = new Thread() {\n                public void run() {\n                    for (int i = 0; i < 1000; i++) {\n                        try {\n                            String mynode = myprefix + \"-\" + i;\n                            znodes.add(mynode);\n                            zk.create(mynode, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                    CreateMode.PERSISTENT);\n                        } catch (Exception e) {\n                            LOG.error(\"Unexpected exception occurred!\", e);\n                        }\n                        if (i == 200) {\n                            doPurge.countDown();\n                        }\n                    }\n                    finished.countDown();\n                };\n            };\n            ths[indx] = th;\n        }\n\n        for (Thread thread : ths) {\n            thread.start();\n        }\n        try {\n            Assert.assertTrue(\"ZkClient ops is not finished!\",\n                    finished.await(OP_TIMEOUT_IN_MILLIS, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ie) {\n            LOG.error(\"Unexpected exception occurred!\", ie);\n            Assert.fail(\"Unexpected exception occurred!\");\n        }\n        return znodes;\n    }\n\n    public void process(WatchedEvent event) {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ReferenceCountedACLCacheTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.junit.Test;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.*;\n\npublic class ReferenceCountedACLCacheTest {\n    @Test\n    public void testSameACLGivesSameID() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n\n        List<ACL> testACL2 = createACL(\"myid\");\n\n        assertEquals(aclId, cache.convertAcls(testACL2));\n    }\n\n    @Test\n    public void testWhetherOrderingMatters() {\n        List<ACL> testACL = new ArrayList<ACL>();\n        testACL.add(new ACL(ZooDefs.Perms.READ, new Id(\"scheme\", \"ro\")));\n        testACL.add(new ACL(ZooDefs.Perms.WRITE, new Id(\"scheme\", \"rw\")));\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n\n        List<ACL> testACL2 = new ArrayList<ACL>();\n        testACL2.add(new ACL(ZooDefs.Perms.WRITE, new Id(\"scheme\", \"rw\")));\n        testACL2.add(new ACL(ZooDefs.Perms.READ, new Id(\"scheme\", \"ro\")));\n\n        assertFalse(aclId.equals(cache.convertAcls(testACL2)));\n    }\n\n    @Test\n    public void testBidirectionality() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n\n        assertEquals(testACL, cache.convertLong(aclId));\n    }\n\n    @Test\n    public void testCacheSize() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n        assertEquals(1, cache.size());\n\n        List<ACL> testACL2 = createACL(\"myid\");\n\n        assertEquals(aclId, cache.convertAcls(testACL2));\n        assertEquals(1, cache.size());\n\n        List<ACL> testACL3 = createACL(\"differentId\");\n\n        Long aclId3 = cache.convertAcls(testACL3);\n        assertFalse(aclId3.equals(aclId));\n        assertEquals(2, cache.size());\n    }\n\n    @Test\n    public void testAddThenRemove() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n        assertEquals(1, cache.size());\n\n        cache.removeUsage(aclId);\n        assertEquals(0, cache.size());\n    }\n\n    @Test\n    public void testMultipleAddsAndRemove() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n        assertEquals(1, cache.size());\n\n        cache.convertAcls(testACL);\n        assertEquals(1, cache.size());\n\n        List<ACL> testACL2 = createACL(\"anotherId\");\n        cache.convertAcls(testACL2);\n\n        cache.removeUsage(aclId);\n        assertEquals(2, cache.size());\n        cache.removeUsage(aclId);\n        assertEquals(1, cache.size());\n\n        Long newId = cache.convertAcls(testACL);\n        assertFalse(aclId.equals(newId));\n    }\n\n    @Test\n    public void testAddUsage() {\n        List<ACL> testACL = createACL(\"myid\");\n\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        Long aclId = cache.convertAcls(testACL);\n        assertEquals(1, cache.size());\n\n        cache.addUsage(aclId);\n        assertEquals(1, cache.size());\n\n        cache.removeUsage(aclId);\n        assertEquals(1, cache.size());\n        cache.removeUsage(aclId);\n        assertEquals(0, cache.size());\n    }\n\n    @Test\n    public void testAddNonExistentUsage() {\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n        cache.addUsage(1L);\n\n        assertEquals(0, cache.size());\n        /*\n        On startup, it's possible that we'll try calling addUsage of an ID not in the cache.  This is safe to ignore\n        as it'll be added later when we traverse the tranlog.  See discussion here:\n        http://mail-archives.apache.org/mod_mbox/zookeeper-user/201507.mbox/%3CCAB5oV2_ujhvBA1sEkCG2WRakPjCy%2BNR10620WK2G1GGgmEO44g%40mail.gmail.com%3E\n\n        This test makes sure that we don't add the ID to the cache in this case as that would result in dupes later\n        and consequently incorrect counts and entries that will never be cleaned out.\n         */\n    }\n\n    @Test\n    public void testSerializeDeserialize() throws IOException {\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n\n        List<ACL> acl1 = createACL(\"one\");\n        List<ACL> acl2 = createACL(\"two\");\n        List<ACL> acl3 = createACL(\"three\");\n        List<ACL> acl4 = createACL(\"four\");\n        List<ACL> acl5 = createACL(\"five\");\n\n        Long aclId1 = convertACLsNTimes(cache, acl1, 1);\n        Long aclId2 = convertACLsNTimes(cache, acl2, 2);\n        Long aclId3 = convertACLsNTimes(cache, acl3, 3);\n        Long aclId4 = convertACLsNTimes(cache, acl4, 4);\n        Long aclId5 = convertACLsNTimes(cache, acl5, 5);\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive archive = BinaryOutputArchive.getArchive(baos);\n        cache.serialize(archive);\n\n        BinaryInputArchive inArchive = BinaryInputArchive.getArchive(new ByteArrayInputStream(baos.toByteArray()));\n        ReferenceCountedACLCache deserializedCache = new ReferenceCountedACLCache();\n        deserializedCache.deserialize(inArchive);\n        callAddUsageNTimes(deserializedCache, aclId1, 1);\n        callAddUsageNTimes(deserializedCache, aclId2, 2);\n        callAddUsageNTimes(deserializedCache, aclId3, 3);\n        callAddUsageNTimes(deserializedCache, aclId4, 4);\n        callAddUsageNTimes(deserializedCache, aclId5, 5);\n\n        assertCachesEqual(cache, deserializedCache);\n    }\n\n    private void assertCachesEqual(ReferenceCountedACLCache expected, ReferenceCountedACLCache actual){\n        assertEquals(expected.aclIndex, actual.aclIndex);\n        assertEquals(expected.aclKeyMap, actual.aclKeyMap);\n        assertEquals(expected.longKeyMap, actual.longKeyMap);\n        assertEquals(expected.referenceCounter, actual.referenceCounter);\n    }\n\n    @Test\n    public void testPurgeUnused() throws IOException {\n        ReferenceCountedACLCache cache = new ReferenceCountedACLCache();\n\n        List<ACL> acl1 = createACL(\"one\");\n        List<ACL> acl2 = createACL(\"two\");\n        List<ACL> acl3 = createACL(\"three\");\n        List<ACL> acl4 = createACL(\"four\");\n        List<ACL> acl5 = createACL(\"five\");\n\n        Long aclId1 = convertACLsNTimes(cache, acl1, 1);\n        Long aclId2 = convertACLsNTimes(cache, acl2, 2);\n        Long aclId3 = convertACLsNTimes(cache, acl3, 3);\n        Long aclId4 = convertACLsNTimes(cache, acl4, 4);\n        Long aclId5 = convertACLsNTimes(cache, acl5, 5);\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        BinaryOutputArchive archive = BinaryOutputArchive.getArchive(baos);\n        cache.serialize(archive);\n\n        BinaryInputArchive inArchive = BinaryInputArchive.getArchive(new ByteArrayInputStream(baos.toByteArray()));\n        ReferenceCountedACLCache deserializedCache = new ReferenceCountedACLCache();\n        deserializedCache.deserialize(inArchive);\n        callAddUsageNTimes(deserializedCache, aclId1, 1);\n        callAddUsageNTimes(deserializedCache, aclId2, 2);\n        deserializedCache.purgeUnused();\n\n        assertEquals(2, deserializedCache.size());\n        assertEquals(aclId1, deserializedCache.convertAcls(acl1));\n        assertEquals(aclId2, deserializedCache.convertAcls(acl2));\n        assertFalse(acl3.equals(deserializedCache.convertAcls(acl3)));\n        assertFalse(acl4.equals(deserializedCache.convertAcls(acl4)));\n        assertFalse(acl5.equals(deserializedCache.convertAcls(acl5)));\n    }\n\n    private void callAddUsageNTimes(ReferenceCountedACLCache deserializedCache, Long aclId, int num) {\n        for (int i = 0; i < num; i++) {\n            deserializedCache.addUsage(aclId);\n        }\n    }\n\n    private Long convertACLsNTimes(ReferenceCountedACLCache cache, List<ACL> acl, int num) {\n        if (num <= 0) {\n            return -1L;\n        }\n\n        for (int i = 0; i < num -1; i++) {\n            cache.convertAcls(acl);\n        }\n\n        return cache.convertAcls(acl);\n    }\n\n    private List<ACL> createACL(String id) {\n        List<ACL> acl1 = new ArrayList<ACL>();\n        acl1.add(new ACL(ZooDefs.Perms.ADMIN, new Id(\"scheme\", id)));\n        return acl1;\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/SerializationPerfTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.junit.Test;\n\npublic class SerializationPerfTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(SerializationPerfTest.class);\n\n    private static class NullOutputStream extends OutputStream {\n        public void write(int b) {\n            // do nothing - exclude persistence from perf\n        }\n    }\n\n    static int createNodes(DataTree tree, String path, int depth,\n            int childcount, int parentCVersion, byte[] data) throws KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        path += \"node\" + depth;\n        tree.createNode(path, data, null, -1, ++parentCVersion, 1, 1);\n\n        if (--depth == 0) {\n            return 1;\n        }\n\n        path += \"/\";\n\n        int count = 1;\n        for (int i = 0; i < childcount; i++) {\n            count += createNodes(tree, path + i, depth, childcount, 1, data);\n        }\n\n        return count;\n    }\n\n    private static void serializeTree(int depth, int width, int len)\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        DataTree tree = new DataTree();\n        createNodes(tree, \"/\", depth, width, tree.getNode(\"/\").stat.getCversion(), new byte[len]);\n        int count = tree.getNodeCount();\n\n        BinaryOutputArchive oa =\n            BinaryOutputArchive.getArchive(new NullOutputStream());\n        System.gc();\n        long start = System.nanoTime();\n        tree.serialize(oa, \"test\");\n        long end = System.nanoTime();\n        long durationms = (end - start)/1000000L;\n        long pernodeus = ((end - start)/1000L)/count;\n        LOG.info(\"Serialized \" + count + \" nodes in \"\n                + durationms + \" ms (\" + pernodeus + \"us/node), depth=\"\n                + depth + \" width=\" + width + \" datalen=\" + len);\n    }\n\n    @Test\n    public void testSingleSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(1, 0, 20);\n    }\n\n    @Test\n    public void testWideSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(2, 10000, 20);\n    }\n\n    @Test\n    public void testDeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(400, 1, 20);\n    }\n\n    @Test\n    public void test10Wide5DeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(5, 10, 20);\n    }\n\n    @Test\n    public void test15Wide5DeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(5, 15, 20);\n    }\n\n    @Test\n    public void test25Wide4DeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(4, 25, 20);\n    }\n\n    @Test\n    public void test40Wide4DeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(4, 40, 20);\n    }\n\n    @Test\n    public void test300Wide3DeepSerialize()\n            throws InterruptedException, IOException, KeeperException.NodeExistsException, KeeperException.NoNodeException {\n        serializeTree(3, 300, 20);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ServerCnxnFactoryAccessor.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\npublic class ServerCnxnFactoryAccessor {\n    public static ZooKeeperServer getZkServer(ServerCnxnFactory fac) {\n\treturn fac.zkServer;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/SessionTrackerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport junit.framework.Assert;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.server.SessionTrackerImpl.SessionImpl;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Test;\n\n/**\n * Testing zk client session logic in sessiontracker\n */\npublic class SessionTrackerTest extends ZKTestCase {\n\n    private final long sessionId = 339900;\n    private final int sessionTimeout = 3000;\n    private FirstProcessor firstProcessor;\n    private CountDownLatch latch;\n\n    /**\n     * Verify the create session call in the Leader.FinalRequestProcessor after\n     * the session expiration.\n     */\n    @Test(timeout = 20000)\n    public void testAddSessionAfterSessionExpiry() throws Exception {\n        ZooKeeperServer zks = setupSessionTracker();\n\n        latch = new CountDownLatch(1);\n        zks.sessionTracker.addSession(sessionId, sessionTimeout);\n        SessionTrackerImpl sessionTrackerImpl = (SessionTrackerImpl) zks.sessionTracker;\n        SessionImpl sessionImpl = sessionTrackerImpl.sessionsById\n                .get(sessionId);\n        Assert.assertNotNull(\"Sessionid:\" + sessionId\n                + \" doesn't exists in sessiontracker\", sessionImpl);\n\n        // verify the session existence\n        Object sessionOwner = new Object();\n        sessionTrackerImpl.checkSession(sessionId, sessionOwner);\n\n        // waiting for the session expiry\n        latch.await(sessionTimeout * 2, TimeUnit.MILLISECONDS);\n\n        // Simulating FinalRequestProcessor logic: create session request has\n        // delayed and now reaches FinalRequestProcessor. Here the leader zk\n        // will do sessionTracker.addSession(id, timeout)\n        sessionTrackerImpl.addSession(sessionId, sessionTimeout);\n        try {\n            sessionTrackerImpl.checkSession(sessionId, sessionOwner);\n            Assert.fail(\"Should throw session expiry exception \"\n                    + \"as the session has expired and closed\");\n        } catch (KeeperException.SessionExpiredException e) {\n            // expected behaviour\n        }\n        Assert.assertTrue(\"Session didn't expired\", sessionImpl.isClosing());\n        Assert.assertFalse(\"Session didn't expired\", sessionTrackerImpl\n                .touchSession(sessionId, sessionTimeout));\n        Assert.assertEquals(\n                \"Duplicate session expiry request has been generated\", 1,\n                firstProcessor.getCountOfCloseSessionReq());\n    }\n\n    /**\n     * Verify the session closure request has reached PrepRequestProcessor soon\n     * after session expiration by the session tracker\n     */\n    @Test(timeout = 20000)\n    public void testCloseSessionRequestAfterSessionExpiry() throws Exception {\n        ZooKeeperServer zks = setupSessionTracker();\n\n        latch = new CountDownLatch(1);\n        zks.sessionTracker.addSession(sessionId, sessionTimeout);\n        SessionTrackerImpl sessionTrackerImpl = (SessionTrackerImpl) zks.sessionTracker;\n        SessionImpl sessionImpl = sessionTrackerImpl.sessionsById\n                .get(sessionId);\n        Assert.assertNotNull(\"Sessionid:\" + sessionId\n                + \" doesn't exists in sessiontracker\", sessionImpl);\n\n        // verify the session existence\n        Object sessionOwner = new Object();\n        sessionTrackerImpl.checkSession(sessionId, sessionOwner);\n\n        // waiting for the session expiry\n        latch.await(sessionTimeout * 2, TimeUnit.MILLISECONDS);\n\n        // Simulating close session request: removeSession() will be executed\n        // while OpCode.closeSession\n        sessionTrackerImpl.removeSession(sessionId);\n        SessionImpl actualSession = sessionTrackerImpl.sessionsById\n                .get(sessionId);\n        Assert.assertNull(\"Session:\" + sessionId\n                + \" still exists after removal\", actualSession);\n    }\n\n    private ZooKeeperServer setupSessionTracker() throws IOException {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        zks.setupRequestProcessors();\n        firstProcessor = new FirstProcessor(zks, null);\n        zks.firstProcessor = firstProcessor;\n\n        // setup session tracker\n        zks.createSessionTracker();\n        zks.startSessionTracker();\n        return zks;\n    }\n\n    // Mock processor used in zookeeper server\n    private class FirstProcessor extends PrepRequestProcessor {\n        private volatile int countOfCloseSessionReq = 0;\n\n        public FirstProcessor(ZooKeeperServer zks,\n                RequestProcessor nextProcessor) {\n            super(zks, nextProcessor);\n        }\n\n        @Override\n        public void processRequest(Request request) {\n            // check session close request\n            if (request.type == OpCode.closeSession) {\n                countOfCloseSessionReq++;\n                latch.countDown();\n            }\n        }\n\n        // return number of session expiry calls\n        int getCountOfCloseSessionReq() {\n            return countOfCloseSessionReq;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ToStringTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.proto.SetDataRequest;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * A misc place to verify toString methods - mainly to make sure they don't\n * fail.\n */\npublic class ToStringTest extends ZKTestCase {\n    /** Verify jute - which we've had particular problems with in the past \n     * wrt null fields */\n    @Test\n    public void testJuteToString() {\n        SetDataRequest req = new SetDataRequest(null, null, 0);\n        Assert.assertNotSame(\"ERROR\", req.toString());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ZooKeeperServerMainTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\nimport static org.junit.Assert.fail;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.jboss.netty.channel.Channel;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Test stand-alone server.\n *\n */\npublic class ZooKeeperServerMainTest extends ZKTestCase implements Watcher {\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(ZooKeeperServerMainTest.class);\n\n    public static class MainThread extends Thread {\n        final File confFile;\n        final TestZKSMain main;\n        final File tmpDir;\n        final File dataDir;\n        final File logDir;\n\n        public MainThread(int clientPort, boolean preCreateDirs) throws IOException {\n            this(clientPort, preCreateDirs, ClientBase.createTmpDir());\n        }\n\n        public MainThread(int clientPort, boolean preCreateDirs, File tmpDir) throws IOException {\n            super(\"Standalone server with clientPort:\" + clientPort);\n            this.tmpDir = tmpDir;\n            confFile = new File(this.tmpDir, \"zoo.cfg\");\n\n            FileWriter fwriter = new FileWriter(confFile);\n            fwriter.write(\"tickTime=2000\\n\");\n            fwriter.write(\"initLimit=10\\n\");\n            fwriter.write(\"syncLimit=5\\n\");\n\n            dataDir = new File(this.tmpDir, \"data\");\n            logDir = new File(dataDir.toString() + \"_txnlog\");\n            if (preCreateDirs) {\n                if (!dataDir.mkdir()) {\n                    throw new IOException(\"unable to mkdir \" + dataDir);\n                }\n                if (!logDir.mkdir()) {\n                    throw new IOException(\"unable to mkdir \" + logDir);\n                }\n            }\n\n            String dataDirPath = dataDir.toString();\n            String logDirPath = logDir.toString();\n\n            // Convert windows path to UNIX to avoid problems with \"\\\"\n            String osname = java.lang.System.getProperty(\"os.name\");\n            if (osname.toLowerCase().contains(\"windows\")) {\n                dataDirPath = dataDirPath.replace('\\\\', '/');\n                logDirPath = logDirPath.replace('\\\\', '/');\n            }\n            fwriter.write(\"dataDir=\" + dataDirPath + \"\\n\");\n            fwriter.write(\"dataLogDir=\" + logDirPath + \"\\n\");\n            fwriter.write(\"clientPort=\" + clientPort + \"\\n\");\n            fwriter.flush();\n            fwriter.close();\n\n            main = new TestZKSMain();\n        }\n\n        public void run() {\n            String args[] = new String[1];\n            args[0] = confFile.toString();\n            try {\n                main.initializeAndRun(args);\n            } catch (Exception e) {\n                // test will still fail even though we just log/ignore\n                LOG.error(\"unexpected exception in run\", e);\n            }\n        }\n\n        public void shutdown() throws IOException {\n            main.shutdown();\n        }\n\n        void deleteDirs() throws IOException{\n            delete(tmpDir);\n        }\n\n        void delete(File f) throws IOException {\n            if (f.isDirectory()) {\n                for (File c : f.listFiles())\n                    delete(c);\n            }\n            if (!f.delete())\n                // double check for the file existence\n                if (f.exists()) {\n                    throw new IOException(\"Failed to delete file: \" + f);\n                }\n        }\n\n        ServerCnxnFactory getCnxnFactory() {\n            return main.getCnxnFactory();\n        }\n    }\n\n    public static  class TestZKSMain extends ZooKeeperServerMain {\n        public void shutdown() {\n            super.shutdown();\n        }\n    }\n\n    /**\n     * Test case for https://issues.apache.org/jira/browse/ZOOKEEPER-2247.\n     * Test to verify that even after non recoverable error (error while\n     * writing transaction log) on ZooKeeper service will be available\n     */\n    @Test(timeout = 30000)\n    public void testNonRecoverableError() throws Exception {\n        ClientBase.setupTestEnv();\n\n        final int CLIENT_PORT = PortAssignment.unique();\n\n        MainThread main = new MainThread(CLIENT_PORT, true);\n        main.start();\n\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT));\n\n\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT,\n                ClientBase.CONNECTION_TIMEOUT, this);\n\n        zk.create(\"/foo1\", \"foobar\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        Assert.assertEquals(new String(zk.getData(\"/foo1\", null, null)), \"foobar\");\n\n        // inject problem in server\n        ZooKeeperServer zooKeeperServer = main.getCnxnFactory()\n                .getZooKeeperServer();\n        FileTxnSnapLog snapLog = zooKeeperServer.getTxnLogFactory();\n        FileTxnSnapLog fileTxnSnapLogWithError = new FileTxnSnapLog(\n                snapLog.getDataDir(), snapLog.getSnapDir()) {\n            @Override\n            public void commit() throws IOException {\n                throw new IOException(\"Input/output error\");\n            }\n        };\n        ZKDatabase newDB = new ZKDatabase(fileTxnSnapLogWithError);\n        zooKeeperServer.setZKDatabase(newDB);\n\n        try {\n            // do create operation, so that injected IOException is thrown\n            zk.create(\"/foo2\", \"foobar\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            fail(\"IOException is expected as error is injected in transaction log commit funtionality\");\n        } catch (Exception e) {\n            // do nothing\n        }\n        zk.close();\n        Assert.assertTrue(\"waiting for server down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT,\n                        ClientBase.CONNECTION_TIMEOUT));\n        fileTxnSnapLogWithError.close();\n        main.shutdown();\n        main.deleteDirs();\n    }\n\n    /**\n     * Tests that the ZooKeeper server will fail to start if the\n     * snapshot directory is read only.\n     *\n     * This test will fail if it is executed as root user.\n     */\n    @Test(timeout = 30000)\n    public void testReadOnlySnapshotDir() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT = PortAssignment.unique();\n\n        // Start up the ZK server to automatically create the necessary directories\n        // and capture the directory where data is stored\n        MainThread main = new MainThread(CLIENT_PORT, true);\n        File tmpDir = main.tmpDir;\n        main.start();\n        Assert.assertTrue(\"waiting for server being up\", ClientBase\n                .waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT / 2));\n        main.shutdown();\n\n        // Make the snapshot directory read only\n        File snapDir = new File(main.dataDir, FileTxnSnapLog.version + FileTxnSnapLog.VERSION);\n        snapDir.setWritable(false);\n\n        // Restart ZK and observe a failure\n        main = new MainThread(CLIENT_PORT, false, tmpDir);\n        main.start();\n\n        Assert.assertFalse(\"waiting for server being up\", ClientBase\n                .waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT / 2));\n\n        main.shutdown();\n\n        snapDir.setWritable(true);\n\n        main.deleteDirs();\n    }\n\n    /**\n     * Tests that the ZooKeeper server will fail to start if the\n     * transaction log directory is read only.\n     *\n     * This test will fail if it is executed as root user.\n     */\n    @Test(timeout = 30000)\n    public void testReadOnlyTxnLogDir() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT = PortAssignment.unique();\n\n        // Start up the ZK server to automatically create the necessary directories\n        // and capture the directory where data is stored\n        MainThread main = new MainThread(CLIENT_PORT, true);\n        File tmpDir = main.tmpDir;\n        main.start();\n        Assert.assertTrue(\"waiting for server being up\", ClientBase\n                .waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT / 2));\n        main.shutdown();\n\n        // Make the transaction log directory read only\n        File logDir = new File(main.logDir, FileTxnSnapLog.version + FileTxnSnapLog.VERSION);\n        logDir.setWritable(false);\n\n        // Restart ZK and observe a failure\n        main = new MainThread(CLIENT_PORT, false, tmpDir);\n        main.start();\n\n        Assert.assertFalse(\"waiting for server being up\", ClientBase\n                .waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT / 2));\n\n        main.shutdown();\n\n        logDir.setWritable(true);\n\n        main.deleteDirs();\n    }\n\n    /**\n     * Verify the ability to start a standalone server instance.\n     */\n    @Test\n    public void testStandalone() throws Exception {\n        ClientBase.setupTestEnv();\n\n        final int CLIENT_PORT = PortAssignment.unique();\n\n        MainThread main = new MainThread(CLIENT_PORT, true);\n        main.start();\n\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT));\n\n\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT,\n                ClientBase.CONNECTION_TIMEOUT, this);\n\n        zk.create(\"/foo\", \"foobar\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        Assert.assertEquals(new String(zk.getData(\"/foo\", null, null)), \"foobar\");\n        zk.close();\n\n        main.shutdown();\n        main.join();\n        main.deleteDirs();\n\n        Assert.assertTrue(\"waiting for server down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT,\n                        ClientBase.CONNECTION_TIMEOUT));\n    }\n\n    /**\n     * Test verifies the auto creation of data dir and data log dir.\n     */\n    @Test(timeout = 30000)\n    public void testAutoCreateDataLogDir() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT = PortAssignment.unique();\n\n        MainThread main = new MainThread(CLIENT_PORT, false);\n        String args[] = new String[1];\n        args[0] = main.confFile.toString();\n        main.start();\n\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT));\n\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT,\n                ClientBase.CONNECTION_TIMEOUT, this);\n\n        zk.create(\"/foo\", \"foobar\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        Assert.assertEquals(new String(zk.getData(\"/foo\", null, null)),\n                \"foobar\");\n        zk.close();\n\n        main.shutdown();\n        main.join();\n        main.deleteDirs();\n\n        Assert.assertTrue(\"waiting for server down\", ClientBase\n                .waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT,\n                        ClientBase.CONNECTION_TIMEOUT));\n    }\n\n    @Test\n    public void testJMXRegistrationWithNIO() throws Exception {\n        ClientBase.setupTestEnv();\n        File tmpDir_1 = ClientBase.createTmpDir();\n        ServerCnxnFactory server_1 = startServer(tmpDir_1);\n        File tmpDir_2 = ClientBase.createTmpDir();\n        ServerCnxnFactory server_2 = startServer(tmpDir_2);\n\n        server_1.shutdown();\n        server_2.shutdown();\n\n        deleteFile(tmpDir_1);\n        deleteFile(tmpDir_2);\n    }\n\n    @Test\n    public void testJMXRegistrationWithNetty() throws Exception {\n        String originalServerCnxnFactory = System\n                .getProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n        System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                NettyServerCnxnFactory.class.getName());\n        try {\n            ClientBase.setupTestEnv();\n            File tmpDir_1 = ClientBase.createTmpDir();\n            ServerCnxnFactory server_1 = startServer(tmpDir_1);\n            File tmpDir_2 = ClientBase.createTmpDir();\n            ServerCnxnFactory server_2 = startServer(tmpDir_2);\n\n            server_1.shutdown();\n            server_2.shutdown();\n\n            deleteFile(tmpDir_1);\n            deleteFile(tmpDir_2);\n        } finally {\n            // setting back\n            if (originalServerCnxnFactory == null\n                    || originalServerCnxnFactory.isEmpty()) {\n                System.clearProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n            } else {\n                System.setProperty(\n                        ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                        originalServerCnxnFactory);\n            }\n        }\n    }\n\n    /**\n     * Test case to verify that ZooKeeper server is able to shutdown properly\n     * when there are pending request(s) in the RequestProcessor chain.\n     *\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2347}\n     */\n    @Test(timeout = 30000)\n    public void testRaceBetweenSyncFlushAndZKShutdown() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        File testDir = File.createTempFile(\"test\", \".dir\", tmpDir);\n        testDir.delete();\n\n        // Following are the sequence of steps to simulate the deadlock\n        // situation - SyncRequestProcessor#shutdown holds a lock and waits on\n        // FinalRequestProcessor to complete a pending operation, which in turn\n        // also needs the ZooKeeperServer lock\n\n        // 1. start zk server\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(testDir, testDir);\n        final SimpleZooKeeperServer zkServer = new SimpleZooKeeperServer(ftsl);\n        zkServer.startup();\n        // 2. Wait for setting up request processor chain. At the end of setup,\n        // it will add a mock request into the chain\n        // 3. Also, waiting for FinalRequestProcessor to start processing request\n        zkServer.waitForFinalProcessRequest();\n        // 4. Above step ensures that there is a request in the processor chain.\n        // Now invoke shutdown, which will acquire zks lock\n        Thread shutdownThread = new Thread() {\n            public void run() {\n                zkServer.shutdown();\n            };\n        };\n        shutdownThread.start();\n        // 5. Wait for SyncRequestProcessor to trigger shutdown function.\n        // This is to ensure that zks lock is acquired\n        zkServer.waitForSyncReqProcessorShutdown();\n        // 6. Now resume FinalRequestProcessor which in turn call\n        // zks#decInProcess() function and tries to acquire zks lock.\n        // This results in deadlock\n        zkServer.resumeFinalProcessRequest();\n        // 7. Waiting to finish server shutdown. Testing that\n        // SyncRequestProcessor#shutdown holds a lock and waits on\n        // FinalRequestProcessor to complete a pending operation, which in turn\n        // also needs the ZooKeeperServer lock\n        shutdownThread.join();\n    }\n\n    private class SimpleZooKeeperServer extends ZooKeeperServer {\n        private SimpleSyncRequestProcessor syncProcessor;\n        private SimpleFinalRequestProcessor finalProcessor;\n\n        SimpleZooKeeperServer(FileTxnSnapLog ftsl) throws IOException {\n            super(ftsl, 2000, 2000, 4000, null, new ZKDatabase(ftsl));\n        }\n\n        @Override\n        protected void setupRequestProcessors() {\n            finalProcessor = new SimpleFinalRequestProcessor(this);\n            syncProcessor = new SimpleSyncRequestProcessor(this,\n                    finalProcessor);\n            syncProcessor.start();\n            firstProcessor = new PrepRequestProcessor(this, syncProcessor);\n            ((PrepRequestProcessor) firstProcessor).start();\n\n            // add request to the chain\n            addRequestToSyncProcessor();\n        }\n\n        private void addRequestToSyncProcessor() {\n            long zxid = ZxidUtils.makeZxid(3, 7);\n            TxnHeader hdr = new TxnHeader(1, 1, zxid, 1,\n                    ZooDefs.OpCode.setData);\n            Record txn = new SetDataTxn(\"/foo\" + zxid, new byte[0], 1);\n            byte[] buf;\n            try {\n                buf = Util.marshallTxnEntry(hdr, txn);\n            } catch (IOException e) {\n                LOG.error(\"IOException while adding request to SyncRequestProcessor\", e);\n                Assert.fail(\"IOException while adding request to SyncRequestProcessor!\");\n                return;\n            }\n            NettyServerCnxnFactory factory = new NettyServerCnxnFactory();\n            final MockNettyServerCnxn nettyCnxn = new MockNettyServerCnxn(null,\n                    this, factory);\n            Request req = new Request(nettyCnxn, 1, 1, ZooDefs.OpCode.setData,\n                    ByteBuffer.wrap(buf), null);\n            req.hdr = hdr;\n            req.txn = txn;\n            syncProcessor.processRequest(req);\n        }\n\n        void waitForFinalProcessRequest() throws InterruptedException {\n            Assert.assertTrue(\"Waiting for FinalRequestProcessor to start processing request\",\n                    finalProcessor.waitForProcessRequestToBeCalled());\n        }\n\n        void waitForSyncReqProcessorShutdown() throws InterruptedException {\n            Assert.assertTrue(\"Waiting for SyncRequestProcessor to shut down\",\n                    syncProcessor.waitForShutdownToBeCalled());\n        }\n\n        void resumeFinalProcessRequest() throws InterruptedException {\n            finalProcessor.resumeProcessRequest();\n        }\n    }\n\n    private class MockNettyServerCnxn extends NettyServerCnxn {\n        public MockNettyServerCnxn(Channel channel, ZooKeeperServer zks,\n                NettyServerCnxnFactory factory) {\n            super(null, null, factory);\n        }\n\n        @Override\n        protected synchronized void updateStatsForResponse(long cxid, long zxid,\n                String op, long start, long end) {\n            return;\n        }\n\n        @Override\n        public synchronized void sendResponse(ReplyHeader h, Record r,\n                String tag) {\n            return;\n        }\n    }\n\n    private class SimpleFinalRequestProcessor extends FinalRequestProcessor {\n        private CountDownLatch finalReqProcessCalled = new CountDownLatch(1);\n        private CountDownLatch resumeFinalReqProcess = new CountDownLatch(1);\n        private volatile boolean interrupted = false;\n        public SimpleFinalRequestProcessor(ZooKeeperServer zks) {\n            super(zks);\n        }\n\n        @Override\n        public void processRequest(Request request) {\n            finalReqProcessCalled.countDown();\n            try {\n                resumeFinalReqProcess.await(ClientBase.CONNECTION_TIMEOUT,\n                        TimeUnit.MILLISECONDS);\n            } catch (InterruptedException e) {\n                LOG.error(\"Interrupted while waiting to process request\", e);\n                interrupted = true; // Marked as interrupted\n                resumeFinalReqProcess.countDown();\n                return;\n            }\n            super.processRequest(request);\n        }\n\n        boolean waitForProcessRequestToBeCalled() throws InterruptedException {\n            return finalReqProcessCalled.await(ClientBase.CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n        }\n\n        void resumeProcessRequest() throws InterruptedException {\n            resumeFinalReqProcess.countDown();\n            resumeFinalReqProcess.await(ClientBase.CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n            Assert.assertFalse(\"Interrupted while waiting to process request\",\n                    interrupted);\n        }\n    }\n\n    private class SimpleSyncRequestProcessor extends SyncRequestProcessor {\n        private final CountDownLatch shutdownCalled = new CountDownLatch(1);\n\n        public SimpleSyncRequestProcessor(ZooKeeperServer zks,\n                RequestProcessor nextProcessor) {\n            super(zks, nextProcessor);\n        }\n\n        @Override\n        public void shutdown() {\n            shutdownCalled.countDown();\n            super.shutdown();\n        }\n\n        boolean waitForShutdownToBeCalled() throws InterruptedException {\n            return shutdownCalled.await(ClientBase.CONNECTION_TIMEOUT / 3,\n                    TimeUnit.MILLISECONDS);\n        }\n    }\n\n    private void deleteFile(File f) throws IOException {\n        if (f.isDirectory()) {\n            for (File c : f.listFiles())\n                deleteFile(c);\n        }\n        if (!f.delete())\n            // double check for the file existence\n            if (f.exists()) {\n                throw new IOException(\"Failed to delete file: \" + f);\n            }\n    }\n\n    private ServerCnxnFactory startServer(File tmpDir) throws IOException,\n            InterruptedException {\n        final int CLIENT_PORT = PortAssignment.unique();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(CLIENT_PORT, -1);\n        f.startup(zks);\n        Assert.assertNotNull(\"JMX initialization failed!\", zks.jmxServerBean);\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT,\n                        CONNECTION_TIMEOUT));\n        return f;\n    }\n\n    public void process(WatchedEvent event) {\n        // ignore for this test\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This class tests the startup behavior of ZooKeeper server.\n */\npublic class ZooKeeperServerStartupTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(ZooKeeperServerStartupTest.class);\n    private static int PORT = PortAssignment.unique();\n    private static String HOST = \"127.0.0.1\";\n    private static String HOSTPORT = HOST + \":\" + PORT;\n    private static final String ZK_NOT_SERVING = \"This ZooKeeper instance is not currently serving requests\";\n\n    private ServerCnxnFactory servcnxnf;\n    private ZooKeeperServer zks;\n    private File tmpDir;\n    private CountDownLatch startupDelayLatch = new CountDownLatch(1);\n\n    @After\n    public void teardown() throws Exception {\n        // count down to avoid infinite blocking call due to this latch, if\n        // any.\n        startupDelayLatch.countDown();\n\n        if (servcnxnf != null) {\n            servcnxnf.shutdown();\n        }\n        if (zks != null) {\n            zks.shutdown();\n        }\n        if (zks.getZKDatabase() != null) {\n            zks.getZKDatabase().close();\n        }\n        if (tmpDir != null) {\n            ClientBase.recursiveDelete(tmpDir);\n        }\n    }\n\n    /**\n     * Test case for\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.\n     */\n    @Test(timeout = 30000)\n    public void testClientConnectionRequestDuringStartupWithNIOServerCnxn()\n            throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n\n        startSimpleZKServer(startupDelayLatch);\n        SimpleZooKeeperServer simplezks = (SimpleZooKeeperServer) zks;\n        Assert.assertTrue(\n                \"Failed to invoke zks#startup() method during server startup\",\n                simplezks.waitForStartupInvocation(10));\n\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zkClient = new ZooKeeper(HOSTPORT,\n                ClientBase.CONNECTION_TIMEOUT, watcher);\n\n        Assert.assertFalse(\n                \"Since server is not fully started, zks#createSession() shouldn't be invoked\",\n                simplezks.waitForSessionCreation(5));\n\n        LOG.info(\n                \"Decrements the count of the latch, so that server will proceed with startup\");\n        startupDelayLatch.countDown();\n\n        Assert.assertTrue(\"waiting for server being up \", ClientBase\n                .waitForServerUp(HOSTPORT, ClientBase.CONNECTION_TIMEOUT));\n\n        Assert.assertTrue(\n                \"Failed to invoke zks#createSession() method during client session creation\",\n                simplezks.waitForSessionCreation(5));\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zkClient.close();\n    }\n\n    /**\n     * Test case for\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.\n     */\n    @Test(timeout = 30000)\n    public void testClientConnectionRequestDuringStartupWithNettyServerCnxn()\n            throws Exception {\n        tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n\n        String originalServerCnxnFactory = System\n                .getProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n        try {\n            System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                    NettyServerCnxnFactory.class.getName());\n            startSimpleZKServer(startupDelayLatch);\n            SimpleZooKeeperServer simplezks = (SimpleZooKeeperServer) zks;\n            Assert.assertTrue(\n                    \"Failed to invoke zks#startup() method during server startup\",\n                    simplezks.waitForStartupInvocation(10));\n\n            CountdownWatcher watcher = new CountdownWatcher();\n            ZooKeeper zkClient = new ZooKeeper(HOSTPORT,\n                    ClientBase.CONNECTION_TIMEOUT, watcher);\n\n            Assert.assertFalse(\n                    \"Since server is not fully started, zks#createSession() shouldn't be invoked\",\n                    simplezks.waitForSessionCreation(5));\n\n            LOG.info(\n                    \"Decrements the count of the latch, so that server will proceed with startup\");\n            startupDelayLatch.countDown();\n\n            Assert.assertTrue(\"waiting for server being up \", ClientBase\n                    .waitForServerUp(HOSTPORT, ClientBase.CONNECTION_TIMEOUT));\n\n            Assert.assertTrue(\n                    \"Failed to invoke zks#createSession() method during client session creation\",\n                    simplezks.waitForSessionCreation(5));\n            watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n            zkClient.close();\n        } finally {\n            // reset cnxn factory\n            if (originalServerCnxnFactory == null) {\n                System.clearProperty(\n                        ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n            } else {\n                System.setProperty(\n                        ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                        originalServerCnxnFactory);\n            }\n        }\n    }\n\n    /**\n     * Test case for\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.\n     */\n    @Test(timeout = 30000)\n    public void testFourLetterWordsWithNIOServerCnxn() throws Exception {\n        startSimpleZKServer(startupDelayLatch);\n        verify(\"conf\", ZK_NOT_SERVING);\n        verify(\"crst\", ZK_NOT_SERVING);\n        verify(\"cons\", ZK_NOT_SERVING);\n        verify(\"dump\", ZK_NOT_SERVING);\n        verify(\"mntr\", ZK_NOT_SERVING);\n        verify(\"stat\", ZK_NOT_SERVING);\n        verify(\"srst\", ZK_NOT_SERVING);\n        verify(\"wchs\", ZK_NOT_SERVING);\n        verify(\"isro\", \"null\");\n    }\n\n    /**\n     * Test case for\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.\n     */\n    @Test(timeout = 30000)\n    public void testFourLetterWordsWithNettyServerCnxn() throws Exception {\n        String originalServerCnxnFactory = System\n                .getProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n        try {\n            startSimpleZKServer(startupDelayLatch);\n            verify(\"conf\", ZK_NOT_SERVING);\n            verify(\"crst\", ZK_NOT_SERVING);\n            verify(\"cons\", ZK_NOT_SERVING);\n            verify(\"dump\", ZK_NOT_SERVING);\n            verify(\"mntr\", ZK_NOT_SERVING);\n            verify(\"stat\", ZK_NOT_SERVING);\n            verify(\"srst\", ZK_NOT_SERVING);\n            verify(\"wchs\", ZK_NOT_SERVING);\n            verify(\"isro\", \"null\");\n        } finally {\n            // reset cnxn factory\n            if (originalServerCnxnFactory == null) {\n                System.clearProperty(\n                        ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n            } else {\n                System.setProperty(\n                        ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                        originalServerCnxnFactory);\n            }\n        }\n    }\n\n    private void verify(String cmd, String expected)\n            throws IOException {\n        String resp = sendRequest(cmd);\n        LOG.info(\"cmd \" + cmd + \" expected \" + expected + \" got \" + resp);\n        Assert.assertTrue(\"Unexpected response: \" + resp,\n                resp.contains(expected));\n    }\n\n    private String sendRequest(String cmd)\n            throws IOException {\n        return send4LetterWord(HOST, PORT, cmd);\n    }\n\n    private void startSimpleZKServer(CountDownLatch startupDelayLatch)\n            throws IOException {\n        zks = new SimpleZooKeeperServer(tmpDir, tmpDir, 3000,\n                startupDelayLatch);\n        SyncRequestProcessor.setSnapCount(100);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n\n        servcnxnf = ServerCnxnFactory.createFactory(PORT, -1);\n        Thread startupThread = new Thread() {\n            public void run() {\n                try {\n                    servcnxnf.startup(zks);\n                } catch (IOException e) {\n                    LOG.error(\"Unexcepted exception during server startup\", e);\n                    // Ignoring exception. If there is an ioexception\n                    // then one of the following assertion will fail\n                } catch (InterruptedException e) {\n                    LOG.error(\"Unexcepted exception during server startup\", e);\n                    // Ignoring exception. If there is an interrupted exception\n                    // then one of the following assertion will fail\n                }\n            };\n        };\n        LOG.info(\"Starting zk server {}\", HOSTPORT);\n        startupThread.start();\n    }\n\n    private static class SimpleZooKeeperServer extends ZooKeeperServer {\n        private CountDownLatch startupDelayLatch;\n        private CountDownLatch startupInvokedLatch = new CountDownLatch(1);\n        private CountDownLatch createSessionInvokedLatch = new CountDownLatch(\n                1);\n\n        public SimpleZooKeeperServer(File snapDir, File logDir, int tickTime,\n                CountDownLatch startupDelayLatch) throws IOException {\n            super(snapDir, logDir, tickTime);\n            this.startupDelayLatch = startupDelayLatch;\n        }\n\n        @Override\n        public synchronized void startup() {\n            try {\n                startupInvokedLatch.countDown();\n                // Delaying the zk server startup so that\n                // ZooKeeperServer#sessionTracker reference won't be\n                // initialized. In the defect scenario, while processing the\n                // connection request zkServer needs sessionTracker reference,\n                // but this is not yet initialized and the server is still in\n                // the startup phase, resulting in NPE.\n                startupDelayLatch.await();\n            } catch (InterruptedException e) {\n                Assert.fail(\n                        \"Unexpected InterruptedException while startinng up!\");\n            }\n            super.startup();\n        }\n\n        @Override\n        long createSession(ServerCnxn cnxn, byte[] passwd, int timeout) {\n            createSessionInvokedLatch.countDown();\n            return super.createSession(cnxn, passwd, timeout);\n        }\n\n        boolean waitForStartupInvocation(long timeout)\n                throws InterruptedException {\n            return startupInvokedLatch.await(timeout, TimeUnit.SECONDS);\n        }\n\n        boolean waitForSessionCreation(long timeout)\n                throws InterruptedException {\n            return createSessionInvokedLatch.await(timeout, TimeUnit.SECONDS);\n        }\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ZooKeeperServerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ZooKeeperServerTest extends ZKTestCase {\n    @Test\n    public void testSortDataDirAscending() {\n        File[] files = new File[5];\n\n        files[0] = new File(\"foo.10027c6de\");\n        files[1] = new File(\"foo.10027c6df\");\n        files[2] = new File(\"bar.10027c6dd\");\n        files[3] = new File(\"foo.10027c6dc\");\n        files[4] = new File(\"foo.20027c6dc\");\n\n        File[] orig = files.clone();\n\n        List<File> filelist = Util.sortDataDir(files, \"foo\", true);\n\n        Assert.assertEquals(orig[2], filelist.get(0));\n        Assert.assertEquals(orig[3], filelist.get(1));\n        Assert.assertEquals(orig[0], filelist.get(2));\n        Assert.assertEquals(orig[1], filelist.get(3));\n        Assert.assertEquals(orig[4], filelist.get(4));\n    }\n\n    @Test\n    public void testSortDataDirDescending() {\n        File[] files = new File[5];\n\n        files[0] = new File(\"foo.10027c6de\");\n        files[1] = new File(\"foo.10027c6df\");\n        files[2] = new File(\"bar.10027c6dd\");\n        files[3] = new File(\"foo.10027c6dc\");\n        files[4] = new File(\"foo.20027c6dc\");\n\n        File[] orig = files.clone();\n\n        List<File> filelist = Util.sortDataDir(files, \"foo\", false);\n\n        Assert.assertEquals(orig[4], filelist.get(0));\n        Assert.assertEquals(orig[1], filelist.get(1));\n        Assert.assertEquals(orig[0], filelist.get(2));\n        Assert.assertEquals(orig[3], filelist.get(3));\n        Assert.assertEquals(orig[2], filelist.get(4));\n    }\n\n    @Test\n    public void testGetLogFiles() {\n        File[] files = new File[5];\n\n        files[0] = new File(\"log.10027c6de\");\n        files[1] = new File(\"log.10027c6df\");\n        files[2] = new File(\"snapshot.10027c6dd\");\n        files[3] = new File(\"log.10027c6dc\");\n        files[4] = new File(\"log.20027c6dc\");\n\n        File[] orig = files.clone();\n\n        File[] filelist =\n                FileTxnLog.getLogFiles(files,\n                Long.parseLong(\"10027c6de\", 16));\n\n        Assert.assertEquals(3, filelist.length);\n        Assert.assertEquals(orig[0], filelist[0]);\n        Assert.assertEquals(orig[1], filelist[1]);\n        Assert.assertEquals(orig[4], filelist[2]);\n    }\n\n    @Test\n    public void testForceSyncDefaultEnabled() {\n        File file = new File(\"foo.10027c6de\");\n        FileTxnLog log = new FileTxnLog(file);\n        Assert.assertTrue(log.isForceSync());\n    }\n\n    @Test\n    public void testForceSyncDefaultDisabled() {\n        try {\n            File file = new File(\"foo.10027c6de\");\n            System.setProperty(\"zookeeper.forceSync\",\"no\");\n            FileTxnLog log = new FileTxnLog(file);\n            Assert.assertFalse(log.isForceSync());\n        }\n        finally {\n            //Reset back to default.\n            System.setProperty(\"zookeeper.forceSync\",\"yes\");\n        }\n    }\n\n    @Test\n    public void testInvalidSnapshot() {\n        File f = null;\n        File tmpFileDir = null;\n        try {\n            tmpFileDir = ClientBase.createTmpDir();\n            f = new File(tmpFileDir, \"snapshot.0\");\n            if (!f.exists()) {\n                f.createNewFile();\n            }\n            Assert.assertFalse(\"Snapshot file size is greater than 9 bytes\", Util.isValidSnapshot(f));\n            Assert.assertTrue(\"Can't delete file\", f.delete());\n        } catch (IOException e) {\n        } finally {\n            if (null != tmpFileDir) {\n                ClientBase.recursiveDelete(tmpFileDir);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ZooKeeperThreadTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport junit.framework.Assert;\n\nimport org.junit.Test;\n\npublic class ZooKeeperThreadTest {\n    private CountDownLatch runningLatch = new CountDownLatch(1);\n\n    public class MyThread extends ZooKeeperThread {\n\n        public MyThread(String threadName) {\n            super(threadName);\n        }\n\n        public void run() {\n            throw new Error();\n        }\n\n        @Override\n        protected void handleException(String thName, Throwable e) {\n            runningLatch.countDown();\n        }\n    }\n\n    public class MyCriticalThread extends ZooKeeperCriticalThread {\n\n        public MyCriticalThread(String threadName) {\n            super(threadName, new ZooKeeperServerListener() {\n\n                @Override\n                public void notifyStopping(String threadName, int erroCode) {\n\n                }\n            });\n        }\n\n        public void run() {\n            throw new Error();\n        }\n\n        @Override\n        protected void handleException(String thName, Throwable e) {\n            runningLatch.countDown();\n        }\n    }\n\n    /**\n     * Test verifies uncaught exception handling of ZooKeeperThread\n     */\n    @Test(timeout = 30000)\n    public void testUncaughtException() throws Exception {\n        MyThread t1 = new MyThread(\"Test-Thread\");\n        t1.start();\n        Assert.assertTrue(\"Uncaught exception is not properly handled.\",\n                runningLatch.await(10000, TimeUnit.MILLISECONDS));\n\n        runningLatch = new CountDownLatch(1);\n        MyCriticalThread t2 = new MyCriticalThread(\"Test-Critical-Thread\");\n        t2.start();\n        Assert.assertTrue(\"Uncaught exception is not properly handled.\",\n                runningLatch.await(10000, TimeUnit.MILLISECONDS));\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/ZxidRolloverTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server;\n\nimport junit.framework.AssertionFailedError;\nimport junit.framework.TestCase;\n\nimport org.apache.log4j.Logger;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.apache.zookeeper.test.ClientTest;\nimport org.apache.zookeeper.test.QuorumUtil;\nimport org.apache.zookeeper.test.QuorumUtil.PeerStruct;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Verify ZOOKEEPER-1277 - ensure that we handle epoch rollover correctly.\n */\npublic class ZxidRolloverTest extends TestCase {\n    private static final Logger LOG = Logger.getLogger(ZxidRolloverTest.class);\n\n    private QuorumUtil qu;\n    private ZooKeeperServer zksLeader;\n    private ZooKeeper[] zkClients = new ZooKeeper[3];\n    private CountdownWatcher[] zkClientWatchers = new CountdownWatcher[3];\n    private int idxLeader;\n    private int idxFollower;\n    \n    private ZooKeeper getClient(int idx) {\n        return zkClients[idx-1];\n    }\n\n    @Override\n    protected void setUp() throws Exception {\n        LOG.info(\"STARTING \" + getName());\n\n        // set the snap count to something low so that we force log rollover\n        // and verify that is working as part of the epoch rollover.\n        SyncRequestProcessor.setSnapCount(7);\n\n        qu = new QuorumUtil(1);\n        startAll();\n\n        for (int i = 0; i < zkClients.length; i++) {\n            zkClientWatchers[i] = new CountdownWatcher();\n            PeerStruct peer = qu.getPeer(i + 1);\n            zkClients[i] = new ZooKeeper(\n                    \"127.0.0.1:\" + peer.clientPort,\n                    ClientTest.CONNECTION_TIMEOUT, zkClientWatchers[i]);\n        }\n        waitForClientsConnected();\n    }\n    \n    private void waitForClientsConnected() throws Exception {\n        for (int i = 0; i < zkClients.length; i++) {\n            zkClientWatchers[i].waitForConnected(ClientTest.CONNECTION_TIMEOUT);\n            zkClientWatchers[i].reset();\n        }\n    }\n\n    /**\n     * Ensure all clients are able to talk to the service.\n     */\n    private void checkClientsConnected() throws Exception {\n        for (int i = 0; i < zkClients.length; i++) {\n            checkClientConnected(i + 1);\n        }\n    }\n\n    /**\n     * Ensure the client is able to talk to the server.\n     * \n     * @param idx the idx of the server the client is talking to\n     */\n    private void checkClientConnected(int idx) throws Exception {\n        ZooKeeper zk = getClient(idx);\n        if (zk == null) {\n            return;\n        }\n        try {\n            assertNull(zk.exists(\"/foofoofoo-connected\", false));\n        } catch (ConnectionLossException e) {\n            // second chance...\n            // in some cases, leader change in particular, the timing is\n            // very tricky to get right in order to assure that the client has\n            // disconnected and reconnected. In some cases the client will\n            // disconnect, then attempt to reconnect before the server is\n            // back, in which case we'll see another connloss on the operation\n            // in the try, this catches that case and waits for the server\n            // to come back\n            PeerStruct peer = qu.getPeer(idx);\n            Assert.assertTrue(\"Waiting for server down\", ClientBase.waitForServerUp(\n                    \"127.0.0.1:\" + peer.clientPort, ClientBase.CONNECTION_TIMEOUT));\n\n            assertNull(zk.exists(\"/foofoofoo-connected\", false));\n        }\n    }\n\n    /**\n     * Ensure all clients are disconnected from the service.\n     */\n    private void checkClientsDisconnected() throws Exception {\n        for (int i = 0; i < zkClients.length; i++) {\n            checkClientDisconnected(i + 1);\n        }\n    }\n\n    /**\n     * Ensure the client is able to talk to the server\n     * \n     * @param idx the idx of the server the client is talking to\n     */\n    private void checkClientDisconnected(int idx) throws Exception {\n        ZooKeeper zk = getClient(idx);\n        if (zk == null) {\n            return;\n        }\n        try {\n            assertNull(zk.exists(\"/foofoofoo-disconnected\", false));\n            fail(\"expected client to be disconnected\");\n        } catch (KeeperException e) {\n            // success\n        }\n    }\n\n    private void startAll() throws Exception {\n        qu.startAll();\n        checkLeader();\n        // all clients should be connected\n        checkClientsConnected();\n    }\n    private void start(int idx) throws Exception {\n        qu.start(idx);\n        for (String hp : qu.getConnString().split(\",\")) {\n            Assert.assertTrue(\"waiting for server up\", ClientBase.waitForServerUp(hp,\n                    ClientTest.CONNECTION_TIMEOUT));\n        }\n\n        checkLeader();\n        // all clients should be connected\n        checkClientsConnected();\n    }\n\n    private void checkLeader() {\n        idxLeader = 1;\n        while(qu.getPeer(idxLeader).peer.leader == null) {\n            idxLeader++;\n        }\n        idxFollower = (idxLeader == 1 ? 2 : 1);\n\n        zksLeader = qu.getPeer(idxLeader).peer.getActiveServer();\n    }\n\n    private void shutdownAll() throws Exception {\n        qu.shutdownAll();\n        // all clients should be disconnected\n        checkClientsDisconnected();\n    }\n    \n    private void shutdown(int idx) throws Exception {\n        qu.shutdown(idx);\n\n        // leader will shutdown, remaining followers will elect a new leader\n        PeerStruct peer = qu.getPeer(idx);\n        Assert.assertTrue(\"Waiting for server down\", ClientBase.waitForServerDown(\n                \"127.0.0.1:\" + peer.clientPort, ClientBase.CONNECTION_TIMEOUT));\n\n        // if idx is the the leader then everyone will get disconnected,\n        // otherwise if idx is a follower then just that client will get\n        // disconnected\n        if (idx == idxLeader) {\n            checkClientDisconnected(idx);\n            try {\n                checkClientsDisconnected();\n            } catch (AssertionFailedError e) {\n                // the clients may or may not have already reconnected\n                // to the recovered cluster, force a check, but ignore\n            }\n        } else {\n            checkClientDisconnected(idx);\n        }\n    }\n\n    /** Reset the next zxid to be near epoch end */\n    private void adjustEpochNearEnd() {\n        zksLeader.setZxid((zksLeader.getZxid() & 0xffffffff00000000L) | 0xfffffffcL);\n    }\n\n    @Override\n    protected void tearDown() throws Exception {\n        LOG.info(\"tearDown starting\");\n        for (int i = 0; i < zkClients.length; i++) {\n            zkClients[i].close();\n        }\n        qu.shutdownAll();\n    }\n\n    /**\n     * Create the znodes, this may fail if the lower 32 roll over, if so\n     * wait for the clients to be re-connected after the re-election\n     */\n    private int createNodes(ZooKeeper zk, int start, int count) throws Exception {\n        LOG.info(\"Creating nodes \" + start + \" thru \" + (start + count));\n        int j = 0;\n        try {\n            for (int i = start; i < start + count; i++) {\n                zk.create(\"/foo\" + i, new byte[0], Ids.READ_ACL_UNSAFE,\n                        CreateMode.EPHEMERAL);\n                j++;\n            }\n        } catch (ConnectionLossException e) {\n            // this is ok - the leader has dropped leadership\n            waitForClientsConnected();\n        }\n        return j;\n    }\n    /**\n     * Verify the expected znodes were created and that the last znode, which\n     * caused the roll-over, did not.\n     */\n    private void checkNodes(ZooKeeper zk, int start, int count) throws Exception {\n        LOG.info(\"Validating nodes \" + start + \" thru \" + (start + count));\n        for (int i = start; i < start + count; i++) {\n            assertNotNull(zk.exists(\"/foo\" + i, false));\n            LOG.error(\"Exists zxid:\" + Long.toHexString(zk.exists(\"/foo\" + i, false).getCzxid()));\n        }\n        assertNull(zk.exists(\"/foo\" + (start + count), false));\n    }\n\n    /**\n     * Prior to the fix this test would hang for a while, then fail with\n     * connection loss.\n     */\n    @Test\n    public void testSimpleRolloverFollower() throws Exception {\n        adjustEpochNearEnd();\n\n        ZooKeeper zk = getClient((idxLeader == 1 ? 2 : 1));\n        int countCreated = createNodes(zk, 0, 10);\n        \n        checkNodes(zk, 0, countCreated);\n    }\n\n    /**\n     * Similar to testSimpleRollover, but ensure the cluster comes back,\n     * has the right data, and is able to serve new requests.\n     */\n    @Test\n    public void testRolloverThenRestart() throws Exception {\n        ZooKeeper zk = getClient(idxFollower);\n        \n        int countCreated = createNodes(zk, 0, 10);\n\n        adjustEpochNearEnd();\n        \n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdownAll();\n        startAll();\n        zk = getClient(idxLeader);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n        \n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdownAll();\n        startAll();\n        zk = getClient(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdownAll();\n        startAll();\n        zk = getClient(idxLeader);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        // sanity check\n        assertTrue(countCreated > 0);\n        assertTrue(countCreated < 60);\n    }\n\n    /**\n     * Similar to testRolloverThenRestart, but ensure a follower comes back,\n     * has the right data, and is able to serve new requests.\n     */\n    @Test\n    public void testRolloverThenFollowerRestart() throws Exception {\n        ZooKeeper zk = getClient(idxFollower);\n\n        int countCreated = createNodes(zk, 0, 10);\n\n        adjustEpochNearEnd();\n        \n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxFollower);\n        start(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n        \n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxFollower);\n        start(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxFollower);\n        start(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        // sanity check\n        assertTrue(countCreated > 0);\n        assertTrue(countCreated < 60);\n    }\n\n    /**\n     * Similar to testRolloverThenRestart, but ensure leadership can change,\n     * comes back, has the right data, and is able to serve new requests.\n     */\n    @Test\n    public void testRolloverThenLeaderRestart() throws Exception {\n        ZooKeeper zk = getClient(idxLeader);\n\n        int countCreated = createNodes(zk, 0, 10);\n\n        adjustEpochNearEnd();\n        \n        checkNodes(zk, 0, countCreated);\n\n        shutdown(idxLeader);\n        start(idxLeader);\n        zk = getClient(idxLeader);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n        \n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxLeader);\n        start(idxLeader);\n        zk = getClient(idxLeader);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxLeader);\n        start(idxLeader);\n        zk = getClient(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        // sanity check\n        assertTrue(countCreated > 0);\n        assertTrue(countCreated < 50);\n    }\n\n    /**\n     * Similar to testRolloverThenRestart, but ensure we can survive multiple\n     * epoch rollovers between restarts.\n     */\n    @Test\n    public void testMultipleRollover() throws Exception {\n        ZooKeeper zk = getClient(idxFollower);\n\n        int countCreated = createNodes(zk, 0, 10);\n\n        adjustEpochNearEnd();\n        \n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n\n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n        \n        countCreated += createNodes(zk, countCreated, 10);\n\n        adjustEpochNearEnd();\n\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdownAll();\n        startAll();\n        zk = getClient(idxFollower);\n\n        adjustEpochNearEnd();\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        shutdown(idxLeader);\n        start(idxLeader);\n        zk = getClient(idxFollower);\n\n        checkNodes(zk, 0, countCreated);\n        countCreated += createNodes(zk, countCreated, 10);\n\n        // sanity check\n        assertTrue(countCreated > 0);\n        assertTrue(countCreated < 70);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/persistence/FileTxnLogTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.persistence;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\n\npublic class FileTxnLogTest  extends ZKTestCase {\n  protected static final Logger LOG = LoggerFactory.getLogger(FileTxnLogTest.class);\n\n  private static final int KB = 1024;\n\n  @Test\n  public void testInvalidPreallocSize() {\n    Assert.assertEquals(\"file should not be padded\",\n      10 * KB, FileTxnLog.calculateFileSizeWithPadding(7 * KB, 10 * KB, 0));\n    Assert.assertEquals(\"file should not be padded\",\n      10 * KB, FileTxnLog.calculateFileSizeWithPadding(7 * KB, 10 * KB, -1));\n  }\n\n  @Test\n  public void testCalculateFileSizeWithPaddingWhenNotToCurrentSize() {\n    Assert.assertEquals(\"file should not be padded\",\n      10 * KB, FileTxnLog.calculateFileSizeWithPadding(5 * KB, 10 * KB, 10 * KB));\n  }\n\n  @Test\n  public void testCalculateFileSizeWithPaddingWhenCloseToCurrentSize() {\n    Assert.assertEquals(\"file should be padded an additional 10 KB\",\n      20 * KB, FileTxnLog.calculateFileSizeWithPadding(7 * KB, 10 * KB, 10 * KB));\n  }\n\n  @Test\n  public void testFileSizeGreaterThanPosition() {\n    Assert.assertEquals(\"file should be padded to 40 KB\",\n      40 * KB, FileTxnLog.calculateFileSizeWithPadding(31 * KB, 10 * KB, 10 * KB));\n  }\n\n  @Test\n  public void testPreAllocSizeSmallerThanTxnData() throws IOException {\n    File logDir = ClientBase.createTmpDir();\n    FileTxnLog fileTxnLog = new FileTxnLog(logDir);\n\n    // Set a small preAllocSize (.5 MB)\n    final int preAllocSize = 500 * KB;\n    fileTxnLog.setPreallocSize(preAllocSize);\n\n    // Create dummy txn larger than preAllocSize\n    // Since the file padding inserts a 0, we will fill the data with 0xff to ensure we corrupt the data if we put the 0 in the data\n    byte[] data = new byte[2 * preAllocSize];\n    Arrays.fill(data, (byte) 0xff);\n\n    // Append and commit 2 transactions to the log\n    // Prior to ZOOKEEPER-2249, attempting to pad in association with the second transaction will corrupt the first\n    fileTxnLog.append(new TxnHeader(1, 1, 1, 1, ZooDefs.OpCode.create),\n      new CreateTxn(\"/testPreAllocSizeSmallerThanTxnData1\", data, ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 0));\n    fileTxnLog.commit();\n    fileTxnLog.append(new TxnHeader(1, 1, 2, 2, ZooDefs.OpCode.create),\n      new CreateTxn(\"/testPreAllocSizeSmallerThanTxnData2\", new byte[]{}, ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 0));\n    fileTxnLog.commit();\n    fileTxnLog.close();\n\n    // Read the log back from disk, this will throw a java.io.IOException: CRC check failed prior to ZOOKEEPER-2249\n    FileTxnLog.FileTxnIterator fileTxnIterator = new FileTxnLog.FileTxnIterator(logDir, 0);\n\n    // Verify the data in the first transaction\n    CreateTxn createTxn = (CreateTxn) fileTxnIterator.getTxn();\n    Assert.assertTrue(Arrays.equals(createTxn.getData(), data));\n\n    // Verify the data in the second transaction\n    fileTxnIterator.next();\n    createTxn = (CreateTxn) fileTxnIterator.getTxn();\n    Assert.assertTrue(Arrays.equals(createTxn.getData(), new byte[]{}));\n  }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/persistence/FileTxnSnapLogTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.persistence;\n\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.TestUtils;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.io.IOException;\n\npublic class FileTxnSnapLogTest {\n\n    private File tmpDir;\n\n    private File logDir;\n\n    private File snapDir;\n\n    private File logVersionDir;\n\n    private File snapVersionDir;\n\n    @Before\n    public void setUp() throws Exception {\n        tmpDir = ClientBase.createEmptyTestDir();\n        logDir = new File(tmpDir, \"logdir\");\n        snapDir = new File(tmpDir, \"snapdir\");\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if(tmpDir != null){\n            TestUtils.deleteFileRecursively(tmpDir);\n        }\n        this.tmpDir = null;\n        this.logDir = null;\n        this.snapDir = null;\n        this.logVersionDir = null;\n        this.snapVersionDir = null;\n    }\n\n    private File createVersionDir(File parentDir) {\n        File versionDir = new File(parentDir, FileTxnSnapLog.version + FileTxnSnapLog.VERSION);\n        versionDir.mkdirs();\n        return versionDir;\n    }\n\n    private void createLogFile(File dir, long zxid) throws IOException {\n        File file = new File(dir.getPath() + File.separator + Util.makeLogName(zxid));\n        file.createNewFile();\n    }\n\n    private void createSnapshotFile(File dir, long zxid) throws IOException {\n        File file = new File(dir.getPath() + File.separator + Util.makeSnapshotName(zxid));\n        file.createNewFile();\n    }\n\n    private void twoDirSetupWithCorrectFiles() throws IOException {\n        logVersionDir = createVersionDir(logDir);\n        snapVersionDir = createVersionDir(snapDir);\n\n        // transaction log files in log dir\n        createLogFile(logVersionDir,1);\n        createLogFile(logVersionDir,2);\n\n        // snapshot files in snap dir\n        createSnapshotFile(snapVersionDir,1);\n        createSnapshotFile(snapVersionDir,2);\n    }\n\n    private void singleDirSetupWithCorrectFiles() throws IOException {\n        logVersionDir = createVersionDir(logDir);\n\n        // transaction log and snapshot files in the same dir\n        createLogFile(logVersionDir,1);\n        createLogFile(logVersionDir,2);\n        createSnapshotFile(logVersionDir,1);\n        createSnapshotFile(logVersionDir,2);\n    }\n\n    @Test\n    public void testDirCheckWithCorrectFiles() throws IOException {\n        twoDirSetupWithCorrectFiles();\n\n        try {\n            new FileTxnSnapLog(logDir, snapDir);\n        } catch (FileTxnSnapLog.LogDirContentCheckException e) {\n            Assert.fail(\"Should not throw LogDirContentCheckException.\");\n        } catch ( FileTxnSnapLog.SnapDirContentCheckException e){\n            Assert.fail(\"Should not throw SnapDirContentCheckException.\");\n        }\n    }\n\n    @Test\n    public void testDirCheckWithSingleDirSetup() throws IOException {\n        singleDirSetupWithCorrectFiles();\n\n        try {\n            new FileTxnSnapLog(logDir, logDir);\n        } catch (FileTxnSnapLog.LogDirContentCheckException e) {\n            Assert.fail(\"Should not throw LogDirContentCheckException.\");\n        } catch ( FileTxnSnapLog.SnapDirContentCheckException e){\n            Assert.fail(\"Should not throw SnapDirContentCheckException.\");\n        }\n    }\n\n    @Test(expected = FileTxnSnapLog.LogDirContentCheckException.class)\n    public void testDirCheckWithSnapFilesInLogDir() throws IOException {\n        twoDirSetupWithCorrectFiles();\n\n        // add snapshot files to the log version dir\n        createSnapshotFile(logVersionDir,3);\n        createSnapshotFile(logVersionDir,4);\n\n        new FileTxnSnapLog(logDir, snapDir);\n    }\n\n    @Test(expected = FileTxnSnapLog.SnapDirContentCheckException.class)\n    public void testDirCheckWithLogFilesInSnapDir() throws IOException {\n        twoDirSetupWithCorrectFiles();\n\n        // add transaction log files to the snap version dir\n        createLogFile(snapVersionDir,3);\n        createLogFile(snapVersionDir,4);\n\n        new FileTxnSnapLog(logDir, snapDir);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/CnxManagerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\nimport java.net.Socket;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager.Message;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class CnxManagerTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(CnxManagerTest.class);\n    protected static final int THRESHOLD = 4;\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    File peerTmpdir[];\n    int peerQuorumPort[];\n    int peerClientPort[];\n    @Before\n    public void setUp() throws Exception {\n\n        this.count = 3;\n        this.peers = new HashMap<Long,QuorumServer>(count); \n        peerTmpdir = new File[count];\n        peerQuorumPort = new int[count];\n        peerClientPort = new int[count];\n        \n        for(int i = 0; i < count; i++) {\n            peerQuorumPort[i] = PortAssignment.unique();\n            peerClientPort[i] = PortAssignment.unique();\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\",\n                                       peerQuorumPort[i],\n                                       PortAssignment.unique(), null));\n            peerTmpdir[i] = ClientBase.createTmpDir();\n        }\n    }\n\n    ByteBuffer createMsg(int state, long leader, long zxid, long epoch){\n        return FastLeaderElection.buildMsg(state, leader, zxid, 0, epoch);\n    }\n\n    class CnxManagerThread extends Thread {\n\n        boolean failed;\n        CnxManagerThread(){\n            failed = false;\n        }\n\n        public void run(){\n            try {\n                QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[0], peerTmpdir[0], peerClientPort[0], 3, 0, 1000, 2, 2);\n                QuorumCnxManager cnxManager = peer.createCnxnManager();\n                QuorumCnxManager.Listener listener = cnxManager.listener;\n                if(listener != null){\n                    listener.start();\n                } else {\n                    LOG.error(\"Null listener when initializing cnx manager\");\n                }\n\n                long sid = 1;\n                cnxManager.toSend(sid, createMsg(ServerState.LOOKING.ordinal(), 0, -1, 1));\n\n                Message m = null;\n                int numRetries = 1;\n                while((m == null) && (numRetries++ <= THRESHOLD)){\n                    m = cnxManager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n                    if(m == null) cnxManager.connectAll();\n                }\n\n                if(numRetries > THRESHOLD){\n                    failed = true;\n                    return;\n                }\n\n                cnxManager.testInitiateConnection(sid);\n\n                m = cnxManager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n                if(m == null){\n                    failed = true;\n                    return;\n                }\n            } catch (Exception e) {\n                LOG.error(\"Exception while running mock thread\", e);\n                Assert.fail(\"Unexpected exception\");\n            }\n        }\n    }\n\n    @Test\n    public void testCnxManager() throws Exception {\n        CnxManagerThread thread = new CnxManagerThread();\n\n        thread.start();\n        \n        QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);\n        QuorumCnxManager cnxManager = peer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        if(listener != null){\n            listener.start();\n        } else {\n            LOG.error(\"Null listener when initializing cnx manager\");\n        }\n\n        cnxManager.toSend(new Long(0), createMsg(ServerState.LOOKING.ordinal(), 1, -1, 1));\n\n        Message m = null;\n        int numRetries = 1;\n        while((m == null) && (numRetries++ <= THRESHOLD)){\n            m = cnxManager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n            if(m == null) cnxManager.connectAll();\n        }\n        \n        Assert.assertTrue(\"Exceeded number of retries\", numRetries <= THRESHOLD);\n\n        thread.join(5000);\n        if (thread.isAlive()) {\n            Assert.fail(\"Thread didn't join\");\n        } else {\n            if(thread.failed)\n                Assert.fail(\"Did not receive expected message\");\n        }\n        \n    }\n\n    @Test\n    public void testCnxManagerTimeout() throws Exception {\n        Random rand = new Random();\n        byte b = (byte) rand.nextInt();\n        int finalOctet = b & 0xFF;\n        int deadPort = PortAssignment.unique();\n        String deadAddress = new String(\"192.0.2.\" + finalOctet);\n            \n        LOG.info(\"This is the dead address I'm trying: \" + deadAddress);\n            \n        peers.put(Long.valueOf(2),\n                  new QuorumServer(2, deadAddress, deadPort, PortAssignment.unique(), null));\n        peerTmpdir[2] = ClientBase.createTmpDir();\n    \n        QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);\n        QuorumCnxManager cnxManager = peer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        if(listener != null){\n            listener.start();\n        } else {\n            LOG.error(\"Null listener when initializing cnx manager\");\n        }\n\n        long begin = System.currentTimeMillis();\n        cnxManager.toSend(new Long(2), createMsg(ServerState.LOOKING.ordinal(), 1, -1, 1));\n        long end = System.currentTimeMillis();\n            \n        if((end - begin) > 6000) Assert.fail(\"Waited more than necessary\");\n        \n    }       \n    \n    /**\n     * Tests a bug in QuorumCnxManager that causes a spin lock\n     * when a negative value is sent. This test checks if the \n     * connection is being closed upon a message with negative\n     * length.\n     * \n     * @throws Exception\n     */\n    @Test\n    public void testCnxManagerSpinLock() throws Exception {               \n        QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);\n        QuorumCnxManager cnxManager = peer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        if(listener != null){\n            listener.start();\n        } else {\n            LOG.error(\"Null listener when initializing cnx manager\");\n        }\n        \n        int port = peers.get(peer.getId()).electionAddr.getPort();\n        LOG.info(\"Election port: \" + port);\n        InetSocketAddress addr = new InetSocketAddress(port);\n        \n        Thread.sleep(1000);\n        \n        SocketChannel sc = SocketChannel.open();\n        sc.socket().connect(peers.get(new Long(1)).electionAddr, 5000);\n        \n        /*\n         * Write id first then negative length.\n         */\n        byte[] msgBytes = new byte[8];\n        ByteBuffer msgBuffer = ByteBuffer.wrap(msgBytes);\n        msgBuffer.putLong(new Long(2));\n        msgBuffer.position(0);\n        sc.write(msgBuffer);\n        \n        msgBuffer = ByteBuffer.wrap(new byte[4]);\n        msgBuffer.putInt(-20);\n        msgBuffer.position(0);\n        sc.write(msgBuffer);\n        \n        Thread.sleep(1000);\n        \n        try{\n            /*\n             * Write a number of times until it\n             * detects that the socket is broken.\n             */\n            for(int i = 0; i < 100; i++){\n                msgBuffer.position(0);\n                sc.write(msgBuffer);\n            }\n            Assert.fail(\"Socket has not been closed\");\n        } catch (Exception e) {\n            LOG.info(\"Socket has been closed as expected\");\n        }\n        peer.shutdown();\n        cnxManager.halt();\n    }   \n\n    /*\n     * Class used with testCnxFromFutureVersion\n     */\n    class TestCnxManager extends QuorumCnxManager {\n\n        TestCnxManager(QuorumPeer self) {\n            super(self.getId(), self.getView(), self.authServer,\n                    self.authLearner, self.tickTime * self.syncLimit,\n                    self.getQuorumListenOnAllIPs(),\n                    self.quorumCnxnThreadsSize, false);\n        }\n        \n        boolean senderWorkerMapContains(Long l){\n            return senderWorkerMap.containsKey(l);\n        }\n        \n        long getSid(Message m){\n            return m.sid;\n        }\n        \n        String getMsgString(Message m){\n            return new String(m.buffer.array());\n        }\n    }\n    \n    /**\n     * Before 3.5.0 a server sends its id when connecting to another server.\n     * Starting with 3.5.0 a server will send a protocol version, followed by\n     * its id, then number of bytes in the remainder of the message and finally\n     * the rest of the message. The test makes sure that a 3.4.6 server is able\n     * to detect that a connection message has this new format, extract the id,\n     * and skip the remainder of the message. \n     * \n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1633}\n     * \n     * @throws Exception\n     */\n    @Test\n    public void testCnxFromFutureVersion() throws Exception {               \n        QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 20);\n        TestCnxManager cnxManager = new TestCnxManager(peer);\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        if(listener != null){\n            listener.start();\n        } else {\n            Assert.fail(\"Null listener when initializing cnx manager\");\n        }\n        \n        int port = peers.get(peer.getId()).electionAddr.getPort();\n        LOG.info(\"Election port: \" + port);\n        \n        Thread.sleep(1000);\n        \n        SocketChannel sc = SocketChannel.open();\n        sc.socket().connect(peers.get(new Long(1)).electionAddr, 5000);\n        \n        InetSocketAddress otherAddr = peers.get(new Long(2)).electionAddr;\n        DataOutputStream dout = new DataOutputStream(sc.socket().getOutputStream());\n        // protocol version - a negative number\n        dout.writeLong(0xffff0000);\n        // server id\n        dout.writeLong(new Long(2));\n        // other stuff that a 3.5.0 server will send - not important for 3.4.6\n        // the 3.4.6 server should just skip it\n        String addr = otherAddr.getHostName()+ \":\" + otherAddr.getPort();\n        byte[] addr_bytes = addr.getBytes();\n        dout.writeInt(addr_bytes.length);\n        dout.write(addr_bytes);\n        dout.flush();\n        \n        Thread.sleep(1000);\n        \n        Assert.assertEquals(\"Server 1 got connection request from server 2\", \n                true, cnxManager.senderWorkerMapContains(new Long(2)));\n      \n        // send another message to make sure the connection message was processed\n        // properly (mainly that its suffix was removed from the stream)\n        String testStr = \"this is a test message string\";\n        byte[] testStr_bytes = testStr.getBytes();\n        dout.writeInt(testStr_bytes.length);\n        dout.write(testStr_bytes);\n        dout.flush();\n        \n        Message m = null;\n        int numRetries = 1;\n        while((m == null) && (numRetries++ <= THRESHOLD)){\n            m = cnxManager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n            if(m == null) cnxManager.connectAll();\n        }\n\n        if(numRetries > THRESHOLD){\n            Assert.fail(\"Test message hasn't been found in recvQueue\");\n        }\n\n        //Assert.assertEquals(\"Message sender should be 2\", 2, m.sid);\n        Assert.assertEquals(\"Message sender should be 2\", 2, cnxManager.getSid(m));\n        Assert.assertEquals(\"Message from 2 doesn't match test sring\", testStr, \n                cnxManager.getMsgString(m));\n      \n        peer.shutdown();\n        cnxManager.halt();\n    }   \n\n    \n    /*\n     * Test if a receiveConnection is able to timeout on socket errors\n     */\n    @Test\n    public void testSocketTimeout() throws Exception {\n        QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 2000, 2, 2);\n        QuorumCnxManager cnxManager = peer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        if(listener != null){\n            listener.start();\n        } else {\n            LOG.error(\"Null listener when initializing cnx manager\");\n        }\n        int port = peers.get(peer.getId()).electionAddr.getPort();\n        LOG.info(\"Election port: \" + port);\n        InetSocketAddress addr = new InetSocketAddress(port);\n        Thread.sleep(1000);\n        \n        Socket sock = new Socket();\n        sock.connect(peers.get(new Long(1)).electionAddr, 5000);\n        long begin = System.currentTimeMillis();\n        // Read without sending data. Verify timeout.\n        cnxManager.receiveConnection(sock);\n        long end = System.currentTimeMillis();\n        if((end - begin) > ((peer.getSyncLimit() * peer.getTickTime()) + 500)) Assert.fail(\"Waited more than necessary\");\n    }\n\n    /*\n     * Test if Worker threads are getting killed after connection loss\n     */\n    @Test\n    public void testWorkerThreads() throws Exception {\n        ArrayList<QuorumPeer> peerList = new ArrayList<QuorumPeer>();\n        try {\n            for (int sid = 0; sid < 3; sid++) {\n                QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[sid], peerTmpdir[sid],\n                                                 peerClientPort[sid], 3, sid, 1000, 2, 2);\n                LOG.info(\"Starting peer {}\", peer.getId());\n                peer.start();\n                peerList.add(sid, peer);\n            }\n            String failure = verifyThreadCount(peerList, 4);\n            if (failure != null) {\n                Assert.fail(failure);\n            }\n            for (int myid = 0; myid < 3; myid++) {\n                for (int i = 0; i < 5; i++) {\n                    // halt one of the listeners and verify count\n                    QuorumPeer peer = peerList.get(myid);\n                    LOG.info(\"Round {}, halting peer {}\", new Object[] { i,\n                            peer.getId() });\n                    peer.shutdown();\n                    peerList.remove(myid);\n                    failure = verifyThreadCount(peerList, 2);\n                    Assert.assertNull(failure, failure);\n                    // Restart halted node and verify count\n                    peer = new QuorumPeer(peers, peerTmpdir[myid], peerTmpdir[myid],\n                                            peerClientPort[myid], 3, myid, 1000, 2, 2);\n                    LOG.info(\"Round {}, restarting peer {}\"\n                            + new Object[] { i, peer.getId() });\n                    peer.start();\n                    peerList.add(myid, peer);\n                    failure = verifyThreadCount(peerList, 4);\n                    Assert.assertNull(failure, failure);\n                }\n            }\n        } finally {\n            for (QuorumPeer quorumPeer : peerList) {\n                quorumPeer.shutdown();\n            }\n        }\n    }\n\n    /**\n     * Returns null on success, otw the message assoc with the failure \n     * @throws InterruptedException\n     */\n    public String verifyThreadCount(ArrayList<QuorumPeer> peerList, long ecnt)\n        throws InterruptedException\n    {\n        String failure = null;\n        for (int i = 0; i < 480; i++) {\n            Thread.sleep(500);\n\n            failure = _verifyThreadCount(peerList, ecnt);\n            if (failure == null) {\n                return null;\n            }\n        }\n        return failure;\n    }\n    public String _verifyThreadCount(ArrayList<QuorumPeer> peerList, long ecnt) {\n        for (int myid = 0; myid < peerList.size(); myid++) {\n            QuorumPeer peer = peerList.get(myid);\n            QuorumCnxManager cnxManager = peer.getQuorumCnxManager();\n            long cnt = cnxManager.getThreadCount();\n            if (cnt != ecnt) {\n                return new String(new Date()\n                    + \" Incorrect number of Worker threads for sid=\" + myid\n                    + \" expected \" + ecnt + \" found \" + cnt);\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/EphemeralNodeDeletionTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\nimport java.io.IOException;\nimport java.net.SocketTimeoutException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport javax.security.sasl.SaslException;\n\npublic class EphemeralNodeDeletionTest extends QuorumPeerTestBase {\n    private static int SERVER_COUNT = 3;\n    private MainThread[] mt = new MainThread[SERVER_COUNT];\n\n    /**\n     * Test case for https://issues.apache.org/jira/browse/ZOOKEEPER-2355.\n     * ZooKeeper ephemeral node is never deleted if follower fail while reading\n     * the proposal packet.\n     */\n\n    @Test(timeout = 120000)\n    public void testEphemeralNodeDeletion() throws Exception {\n        final int clientPorts[] = new int[SERVER_COUNT];\n        StringBuilder sb = new StringBuilder();\n        String server;\n\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            clientPorts[i] = PortAssignment.unique();\n            server = \"server.\" + i + \"=127.0.0.1:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique();\n            sb.append(server + \"\\n\");\n        }\n        String currentQuorumCfgSection = sb.toString();\n        System.out.println(currentQuorumCfgSection);\n        // start all the servers\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            mt[i] = new MainThread(i, clientPorts[i], currentQuorumCfgSection) {\n                @Override\n                public TestQPMain getTestQPMain() {\n                    return new MockTestQPMain();\n                }\n            };\n            mt[i].start();\n        }\n\n        // ensure all servers started\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            Assert.assertTrue(\"waiting for server \" + i + \" being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + clientPorts[i],\n                            CONNECTION_TIMEOUT));\n        }\n\n        CountdownWatcher watch = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + clientPorts[1],\n                ClientBase.CONNECTION_TIMEOUT, watch);\n        watch.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n\n        /**\n         * now the problem scenario starts\n         */\n\n        // 1: create ephemeral node\n        String nodePath = \"/e1\";\n        zk.create(nodePath, \"1\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n        // 2: inject network problem in one of the follower\n        CustomQuorumPeer follower = (CustomQuorumPeer) getByServerState(mt,\n                ServerState.FOLLOWING);\n        follower.setInjectError(true);\n\n        // 3: close the session so that ephemeral node is deleted\n        zk.close();\n\n        // remove the error\n        follower.setInjectError(false);\n\n        Assert.assertTrue(\"Faulted Follower should have joined quorum by now\",\n                ClientBase.waitForServerUp(\n                        \"127.0.0.1:\" + follower.getClientPort(),\n                        CONNECTION_TIMEOUT));\n\n        QuorumPeer leader = getByServerState(mt, ServerState.LEADING);\n        assertNotNull(\"Leader should not be null\", leader);\n        Assert.assertTrue(\"Leader must be running\", ClientBase.waitForServerUp(\n                \"127.0.0.1:\" + leader.getClientPort(), CONNECTION_TIMEOUT));\n\n        watch = new CountdownWatcher();\n        zk = new ZooKeeper(\"127.0.0.1:\" + leader.getClientPort(),\n                ClientBase.CONNECTION_TIMEOUT, watch);\n        watch.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n\n        Stat exists = zk.exists(nodePath, false);\n        assertNull(\"Node must have been deleted from leader\", exists);\n\n        CountdownWatcher followerWatch = new CountdownWatcher();\n        ZooKeeper followerZK = new ZooKeeper(\n                \"127.0.0.1:\" + follower.getClientPort(),\n                ClientBase.CONNECTION_TIMEOUT, followerWatch);\n        followerWatch.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        Stat nodeAtFollower = followerZK.exists(nodePath, false);\n\n        // Problem 1: Follower had one extra ephemeral node /e1\n        assertNull(\"ephemeral node must not exist\", nodeAtFollower);\n\n        // Create the node with another session\n        zk.create(nodePath, \"2\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n        // close the session and newly created ephemeral node should be deleted\n        zk.close();\n\n        nodeAtFollower = followerZK.exists(nodePath, false);\n\n        // Problem 2: Before fix, after session close the ephemeral node\n        // was not getting deleted. But now after the fix after session close\n        // ephemeral node is getting deleted.\n        assertNull(\"After session close ephemeral node must be deleted\",\n                nodeAtFollower);\n        followerZK.close();\n    }\n\n    @After\n    public void tearDown() {\n        // stop all severs\n        for (int i = 0; i < mt.length; i++) {\n            try {\n                mt[i].shutdown();\n            } catch (InterruptedException e) {\n                LOG.warn(\"Quorum Peer interrupted while shutting it down\", e);\n            }\n        }\n    }\n\n    private QuorumPeer getByServerState(MainThread[] mt, ServerState state) {\n        for (int i = mt.length - 1; i >= 0; i--) {\n            QuorumPeer quorumPeer = mt[i].getQuorumPeer();\n            if (null != quorumPeer && state == quorumPeer.getPeerState()) {\n                return quorumPeer;\n            }\n        }\n        return null;\n    }\n\n    static class CustomQuorumPeer extends QuorumPeer  {\n        private boolean injectError = false;\n\n        public CustomQuorumPeer() throws SaslException {\n        }\n\n        @Override\n        protected Follower makeFollower(FileTxnSnapLog logFactory)\n                throws IOException {\n            return new Follower(this, new FollowerZooKeeperServer(logFactory,\n                    this, null /*DataTreeBuilder is never used*/,\n                    this.getZkDb())) {\n\n                @Override\n                void readPacket(QuorumPacket pp) throws IOException {\n                    /**\n                     * In real scenario got SocketTimeoutException while reading\n                     * the packet from leader because of network problem, but\n                     * here throwing SocketTimeoutException based on whether\n                     * error is injected or not\n                     */\n                    super.readPacket(pp);\n                    if (injectError && pp.getType() == Leader.PROPOSAL) {\n                        String type = LearnerHandler.packetToString(pp);\n                        throw new SocketTimeoutException(\n                                \"Socket timeout while reading the packet for operation \"\n                                        + type);\n                    }\n                }\n\n            };\n        }\n\n        public void setInjectError(boolean injectError) {\n            this.injectError = injectError;\n        }\n\n    }\n\n    static class MockTestQPMain extends TestQPMain {\n        @Override\n        protected QuorumPeer getQuorumPeer() throws SaslException {\n            return new CustomQuorumPeer();\n        }\n    }\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/FLEBackwardElectionRoundTest.java",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.HashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\n\npublic class FLEBackwardElectionRoundTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLELostMessageTest.class);\n    \n    int count;\n    HashMap<Long,QuorumServer> peers;\n    File tmpdir[];\n    int port[];\n\n    QuorumCnxManager cnxManagers[];\n\n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        tmpdir = new File[count];\n        port = new int[count];\n        cnxManagers = new QuorumCnxManager[count - 1];\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for(int i = 0; i < (count - 1); i++){\n            if(cnxManagers[i] != null){\n                cnxManagers[i].halt();\n            }\n        }\n    }\n    \n    /**\n     * This test is checking the following case. A server S is\n     * currently LOOKING and it receives notifications from \n     * a quorum indicating they are following S. The election\n     * round E of S is higher than the election round E' in the \n     * notification messages, so S becomes the leader and sets\n     * its epoch back to E'. In the meanwhile, one or more\n     * followers turn to LOOKING and elect S in election round E.\n     * Having leader and followers with different election rounds\n     * might prevent other servers from electing a leader because\n     * they can't get a consistent set of notifications from a \n     * quorum. \n     * \n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1514}\n     *    \n     * \n     * @throws Exception\n     */\n    \n    @Test\n    public void testBackwardElectionRound() throws Exception {\n        LOG.info(\"TestLE: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            int clientport = PortAssignment.unique();\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", clientport,\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = clientport;\n        }\n\n        ByteBuffer initialMsg0 = getMsg();\n        ByteBuffer initialMsg1 = getMsg();\n\n        /*\n         * Start server 0\n         */\n\n        QuorumPeer peer = new QuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 3, 0, 1000, 2, 2);\n        peer.startLeaderElection();\n        FLETestUtils.LEThread thread = new FLETestUtils.LEThread(peer, 0);\n        thread.start();  \n        \n        \n        /*\n         * Start mock server 1\n         */\n        QuorumPeer mockPeer = new QuorumPeer(peers, tmpdir[1], tmpdir[1], port[1], 3, 1, 1000, 2, 2);\n        cnxManagers[0] = mockPeer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManagers[0].listener;\n        listener.start();\n\n        cnxManagers[0].toSend(0l, initialMsg0);\n        \n        /*\n         * Start mock server 2\n         */\n        mockPeer = new QuorumPeer(peers, tmpdir[2], tmpdir[2], port[2], 3, 2, 1000, 2, 2);\n        cnxManagers[1] = mockPeer.createCnxnManager();\n        listener = cnxManagers[1].listener;\n        listener.start();\n\n        cnxManagers[1].toSend(0l, initialMsg1);\n        \n        /*\n         * Run another instance of leader election.\n         */\n        thread.join(5000);\n        thread = new FLETestUtils.LEThread(peer, 0);\n        thread.start();\n        \n        /*\n         * Send the same messages, this time should not make 0 the leader.\n         */\n        cnxManagers[0].toSend(0l, initialMsg0);\n        cnxManagers[1].toSend(0l, initialMsg1);\n\n        thread.join(5000);\n        \n        if (!thread.isAlive()) {\n            Assert.fail(\"Should not have joined\");\n        }\n        \n    }\n\n    private ByteBuffer getMsg() {\n        return FLETestUtils.createMsg(ServerState.FOLLOWING.ordinal(), 0, 0, 1);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/FLECompatibilityTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection.Notification;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection.ToSend;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger.WorkerReceiver;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager.Message;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.FLETest;\nimport org.apache.zookeeper.test.QuorumBase;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\npublic class FLECompatibilityTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLECompatibilityTest.class);\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    File tmpdir[];\n    int port[];\n    \n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n        peers = new HashMap<Long,QuorumServer>(count);\n        tmpdir = new File[count];\n        port = new int[count];\n    }\n    \n    @After\n    public void tearDown() throws Exception {\n        \n    }\n    \n    class MockFLEMessengerBackward {   \n        QuorumCnxManager manager;\n        QuorumPeer self;\n        long logicalclock = 1L;\n        LinkedBlockingQueue<ToSend> sendqueue = new LinkedBlockingQueue<ToSend>();\n        LinkedBlockingQueue<ToSend> internalqueue = new LinkedBlockingQueue<ToSend>();\n        LinkedBlockingQueue<Notification> recvqueue = new LinkedBlockingQueue<Notification>();\n        WorkerReceiver wr;\n        \n        MockFLEMessengerBackward(QuorumPeer self, QuorumCnxManager manager){\n            this.manager = manager;\n            this.self = self;\n            \n            this.wr = new WorkerReceiver(manager);\n\n            Thread t = new Thread(this.wr,\n                    \"WorkerReceiver[myid=\" + self.getId() + \"]\");\n            t.setDaemon(true);\n            t.start();\n        }\n        \n        void halt() {\n            wr.stop = true;\n        }\n        \n        /*\n         * This class has been copied from before adding versions to notifications.\n         * \n         * {@see https://issues.apache.org/jira/browse/ZOOKEEPER-1808}\n         */\n        class WorkerReceiver implements Runnable {\n            volatile boolean stop;\n            QuorumCnxManager manager;\n            final long proposedLeader = 2;\n            final long proposedZxid = 0x1;\n            final long proposedEpoch = 1;\n\n            WorkerReceiver(QuorumCnxManager manager) {\n                this.stop = false;\n                this.manager = manager;\n            }\n\n            /*\n             * The vote we return here is fixed for test purposes.\n             */\n            Vote getVote(){\n                return new Vote(proposedLeader, proposedZxid, proposedEpoch);\n            }\n            \n            public void run() {\n\n                Message response;\n                while (!stop) {\n                    // Sleeps on receive\n                    try{\n                        response = manager.pollRecvQueue(3000, TimeUnit.MILLISECONDS);\n                        if(response == null) continue;\n\n                        /*\n                         * If it is from an observer, respond right away.\n                         * Note that the following predicate assumes that\n                         * if a server is not a follower, then it must be\n                         * an observer. If we ever have any other type of\n                         * learner in the future, we'll have to change the\n                         * way we check for observers.\n                         */\n                        if(!self.getVotingView().containsKey(response.sid)){\n                            Vote current = self.getCurrentVote();\n                            ToSend notmsg = new ToSend(ToSend.mType.notification,\n                                    current.getId(),\n                                    current.getZxid(),\n                                    logicalclock,\n                                    self.getPeerState(),\n                                    response.sid,\n                                    current.getPeerEpoch());\n\n                            internalqueue.offer(notmsg);\n                        } else {\n                            // Receive new message\n                            if (LOG.isDebugEnabled()) {\n                                LOG.debug(\"Receive new notification message. My id = \"\n                                        + self.getId());\n                            }\n\n                            /*\n                             * We check for 28 bytes for backward compatibility\n                             */\n                            if (response.buffer.capacity() < 28) {\n                                LOG.error(\"Got a short response: \"\n                                        + response.buffer.capacity());\n                                continue;\n                            }\n                            boolean backCompatibility = (response.buffer.capacity() == 28);\n                            response.buffer.clear();\n\n                            // State of peer that sent this message\n                            QuorumPeer.ServerState ackstate = QuorumPeer.ServerState.LOOKING;\n                            switch (response.buffer.getInt()) {\n                            case 0:\n                                ackstate = QuorumPeer.ServerState.LOOKING;\n                                break;\n                            case 1:\n                                ackstate = QuorumPeer.ServerState.FOLLOWING;\n                                break;\n                            case 2:\n                                ackstate = QuorumPeer.ServerState.LEADING;\n                                break;\n                            case 3:\n                                ackstate = QuorumPeer.ServerState.OBSERVING;\n                                break;\n                            }\n\n                            // Instantiate Notification and set its attributes\n                            Notification n = new Notification();\n                            n.leader = response.buffer.getLong();\n                            n.zxid = response.buffer.getLong();\n                            n.electionEpoch = response.buffer.getLong();\n                            n.state = ackstate;\n                            n.sid = response.sid;\n                            if(!backCompatibility){\n                                n.peerEpoch = response.buffer.getLong();\n                            } else {\n                                if(LOG.isInfoEnabled()){\n                                    LOG.info(\"Backward compatibility mode, server id=\" + n.sid);\n                                }\n                                n.peerEpoch = ZxidUtils.getEpochFromZxid(n.zxid);\n                            }\n\n                            /*\n                             * If this server is looking, then send proposed leader\n                             */\n\n                            if(self.getPeerState() == QuorumPeer.ServerState.LOOKING){\n                                recvqueue.offer(n);\n\n                                /*\n                                 * Send a notification back if the peer that sent this\n                                 * message is also looking and its logical clock is\n                                 * lagging behind.\n                                 */\n                                if((ackstate == QuorumPeer.ServerState.LOOKING)\n                                        && (n.electionEpoch < logicalclock)){\n                                    Vote v = getVote();\n                                    ToSend notmsg = new ToSend(ToSend.mType.notification,\n                                            v.getId(),\n                                            v.getZxid(),\n                                            logicalclock,\n                                            self.getPeerState(),\n                                            response.sid,\n                                            v.getPeerEpoch());\n                                    internalqueue.offer(notmsg);\n                                }\n                            } else {\n                                /*\n                                 * If this server is not looking, but the one that sent the ack\n                                 * is looking, then send back what it believes to be the leader.\n                                 */\n                                Vote current = self.getCurrentVote();\n                                if(ackstate == QuorumPeer.ServerState.LOOKING){\n                                    if(LOG.isDebugEnabled()){\n                                        LOG.debug(\"Sending new notification. My id =  \" +\n                                                self.getId() + \" recipient=\" +\n                                                response.sid + \" zxid=0x\" +\n                                                Long.toHexString(current.getZxid()) +\n                                                \" leader=\" + current.getId());\n                                    }\n                                    ToSend notmsg = new ToSend(\n                                            ToSend.mType.notification,\n                                            current.getId(),\n                                            current.getZxid(),\n                                            current.getElectionEpoch(),\n                                            self.getPeerState(),\n                                            response.sid,\n                                            current.getPeerEpoch());\n                                    internalqueue.offer(notmsg);\n                                }\n                            }\n                        }\n                    } catch (InterruptedException e) {\n                        System.out.println(\"Interrupted Exception while waiting for new message\" +\n                                e.toString());\n                    }\n                }\n                LOG.info(\"WorkerReceiver is down\");\n            }\n        }\n    }\n    \n    class MockFLEMessengerForward extends FastLeaderElection {\n        \n        MockFLEMessengerForward(QuorumPeer self, QuorumCnxManager manager){\n            super( self, manager );\n        }\n        \n        void halt() {\n            super.shutdown();\n        }\n    }\n    \n    void populate()\n    throws Exception {\n        for (int i = 0; i < count; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\",\n                                       PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = PortAssignment.unique();\n        }\n    }\n    \n    @Test(timeout=20000)\n    public void testBackwardCompatibility() \n    throws Exception {\n        populate();\n        \n        QuorumPeer peer = new QuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 3, 0, 1000, 2, 2);\n        peer.setPeerState(ServerState.LOOKING);\n        QuorumCnxManager mng = peer.createCnxnManager();\n        \n        /*\n         * Check that it generates an internal notification correctly\n         */\n        MockFLEMessengerBackward fle = new MockFLEMessengerBackward(peer, mng);\n        ByteBuffer buffer = FastLeaderElection.buildMsg(ServerState.LOOKING.ordinal(), 2, 0x1, 1, 1);\n        fle.manager.recvQueue.add(new Message(buffer, 2));\n        Notification n = fle.recvqueue.take();\n        Assert.assertTrue(\"Wrong state\", n.state == ServerState.LOOKING);\n        Assert.assertTrue(\"Wrong leader\", n.leader == 2);\n        Assert.assertTrue(\"Wrong zxid\", n.zxid == 0x1);\n        Assert.assertTrue(\"Wrong epoch\", n.electionEpoch == 1);\n        Assert.assertTrue(\"Wrong epoch\", n.peerEpoch == 1);\n        \n        /*\n         * Check that it sends a notification back to the sender\n         */\n        peer.setPeerState(ServerState.FOLLOWING);\n        peer.setCurrentVote( new Vote(2, 0x1, 1, 1, ServerState.LOOKING) );\n        buffer = FastLeaderElection.buildMsg(ServerState.LOOKING.ordinal(), 1, 0x1, 1, 1);\n        fle.manager.recvQueue.add(new Message(buffer, 1));\n        ToSend m = fle.internalqueue.take();\n        Assert.assertTrue(\"Wrong state\", m.state == ServerState.FOLLOWING);\n        Assert.assertTrue(\"Wrong sid\", m.sid == 1);\n        Assert.assertTrue(\"Wrong leader\", m.leader == 2);\n        Assert.assertTrue(\"Wrong epoch\", m.electionEpoch == 1);\n        Assert.assertTrue(\"Wrong epoch\", m.peerEpoch == 1);\n    }\n    \n    @Test(timeout=20000)\n    public void testForwardCompatibility() \n    throws Exception {\n        populate();\n\n        QuorumPeer peer = new QuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 3, 0, 1000, 2, 2);\n        peer.setPeerState(ServerState.LOOKING);\n        QuorumCnxManager mng = peer.createCnxnManager();\n        \n        /*\n         * Check that it generates an internal notification correctly\n         */\n        MockFLEMessengerForward fle = new MockFLEMessengerForward(peer, mng);\n        ByteBuffer notBuffer = FastLeaderElection.buildMsg(ServerState.LOOKING.ordinal(), 2, 0x1, 1, 1);\n        ByteBuffer buffer = ByteBuffer.allocate( notBuffer.capacity() + 8 );\n        notBuffer.flip();\n        buffer.put(notBuffer);\n        buffer.putLong( Long.MAX_VALUE );\n        buffer.flip();\n        \n        fle.manager.recvQueue.add(new Message(buffer, 2));\n        Notification n = fle.recvqueue.take();\n        Assert.assertTrue(\"Wrong state\", n.state == ServerState.LOOKING);\n        Assert.assertTrue(\"Wrong leader\", n.leader == 2);\n        Assert.assertTrue(\"Wrong zxid\", n.zxid == 0x1);\n        Assert.assertTrue(\"Wrong epoch\", n.electionEpoch == 1);\n        Assert.assertTrue(\"Wrong epoch\", n.peerEpoch == 1);\n        Assert.assertTrue(\"Wrong version\", n.version == FastLeaderElection.Notification.CURRENTVERSION);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/FLEDontCareTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.FLETest;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\n\npublic class FLEDontCareTest {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLEDontCareTest.class);\n\n    class MockFLE extends FastLeaderElection {\n        MockFLE(QuorumPeer peer, QuorumCnxManager cnxManager) {\n            super(peer, cnxManager);\n        }\n\n        public boolean termPredicate(HashMap<Long, Vote> votes, Vote vote) {\n            return super.termPredicate(votes, vote);\n        }\n\n        public boolean checkLeader(HashMap<Long,Vote> votes, long leader, long electionEpoch) {\n            return super.checkLeader(votes, leader, electionEpoch);\n        }\n\n        public boolean ooePredicate(HashMap<Long,Vote> recv,\n                                    HashMap<Long,Vote> ooe,\n                                    FastLeaderElection.Notification n) {\n            return super.ooePredicate(recv, ooe, n);\n\n        }\n    }\n\n    HashMap<Long,QuorumServer> peers;\n    QuorumPeer peer;\n    File tmpdir;\n\n    @Before\n    public void setUp()\n    throws Exception {\n        tmpdir = ClientBase.createTmpDir();\n        peers = new HashMap<Long,QuorumServer>();\n        for(int i = 0; i < 5; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(Long.valueOf(i), \"127.0.0.1\", PortAssignment.unique(), 0, null));\n        }\n        peer = new QuorumPeer(peers,\n                tmpdir,\n                tmpdir,\n                PortAssignment.unique(),\n                3, 3, 1000, 2, 2);\n    }\n\n    @After\n    public void tearDown(){\n        tmpdir.delete();\n    }\n\n    @Test\n    public void testDontCare() {\n        MockFLE fle = new MockFLE(peer, peer.createCnxnManager());\n\n        HashMap<Long, Vote> votes = new HashMap<Long, Vote>();\n        votes.put(0L, new Vote(0x1, 4L, ZxidUtils.makeZxid(1, 1), 1, 2, ServerState.FOLLOWING));\n        votes.put(1L, new Vote(0x1, 4L, ZxidUtils.makeZxid(1, 2), 1, 2, ServerState.FOLLOWING));\n        votes.put(3L, new Vote(0x1, 4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.FOLLOWING));\n        votes.put(4L, new Vote(0x1, 4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.LEADING));\n\n        Assert.assertTrue(fle.termPredicate(votes,\n                new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.FOLLOWING)));\n    }\n\n    @Test\n    public void testDontCareVersion() {\n        MockFLE fle = new MockFLE(peer, peer.createCnxnManager());\n\n        HashMap<Long, Vote> votes = new HashMap<Long, Vote>();\n        votes.put(0L, new Vote(0x1, 4L, ZxidUtils.makeZxid(1, 1), 1, 1, ServerState.FOLLOWING));\n        votes.put(1L, new Vote(0x1, 4L, ZxidUtils.makeZxid(1, 1), 1, 1, ServerState.FOLLOWING));\n        votes.put(3L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.FOLLOWING));\n        votes.put(4L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.LEADING));\n\n        Assert.assertTrue(fle.termPredicate(votes,\n                new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.FOLLOWING)));\n    }\n\n    @Test\n    public void testLookingNormal() {\n        MockFLE fle = new MockFLE(peer, peer.createCnxnManager());\n\n        HashMap<Long, Vote> votes = new HashMap<Long, Vote>();\n        votes.put(0L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 1, 1, ServerState.LOOKING));\n        votes.put(1L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 1, 1, ServerState.LOOKING));\n        votes.put(3L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 1, 1, ServerState.LOOKING));\n        votes.put(4L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 1, 1, ServerState.LEADING));\n\n        Assert.assertTrue(fle.termPredicate(votes,\n                new Vote(4L, ZxidUtils.makeZxid(2, 1), 1, 1, ServerState.LOOKING)));\n    }\n\n    @Test\n    public void testLookingDiffRounds() {\n        MockFLE fle = new MockFLE(peer, peer.createCnxnManager());\n\n        HashMap<Long, Vote> votes = new HashMap<Long, Vote>();\n        votes.put(0L, new Vote(4L, ZxidUtils.makeZxid(1, 1), 1, 1, ServerState.LOOKING));\n        votes.put(1L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.LOOKING));\n        votes.put(3L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 3, 2, ServerState.LOOKING));\n        votes.put(4L, new Vote(4L, ZxidUtils.makeZxid(2, 1), 3, 2, ServerState.LEADING));\n\n        Assert.assertFalse(fle.termPredicate(votes,\n                new Vote(4L, ZxidUtils.makeZxid(2, 1), 2, 2, ServerState.LOOKING)));\n    }\n\n\n    /**\n     * Helper method to build notifications and populate outofelection.\n     *\n     *\n     * @param version\n     * @param leader\n     * @param zxid\n     * @param electionEpoch\n     * @param state\n     * @param sid\n     * @param peerEpoch\n     * @param outofelection\n     * @return\n     */\n    FastLeaderElection.Notification genNotification(int version,\n                                                        long leader,\n                                                        long zxid,\n                                                        long electionEpoch,\n                                                        ServerState state,\n                                                        long sid,\n                                                        long peerEpoch,\n                                                        HashMap<Long,Vote> outofelection) {\n        FastLeaderElection.Notification n = new FastLeaderElection.Notification();\n        n.version = version;\n        n.leader = leader;\n        n.zxid = zxid;\n        n.electionEpoch = electionEpoch;\n        n.state = state;\n        n.sid = sid;\n        n.peerEpoch = peerEpoch;\n\n        outofelection.put(n.sid, new Vote(n.version,\n                                            n.leader,\n                                            n.zxid,\n                                            n.electionEpoch,\n                                            n.peerEpoch,\n                                            n.state));\n\n        return n;\n    }\n\n    @Test\n    public void testOutofElection() {\n        MockFLE fle = new MockFLE(peer, peer.createCnxnManager());\n        HashMap<Long,Vote> outofelection = new HashMap<Long,Vote>();\n\n        /*\n         * Generates notifications emulating servers 1, 2, 4, and 5.\n         * Server 5 is the elected leader.\n         */\n\n        genNotification( 0x0,\n                            5,\n                            ZxidUtils.makeZxid(15, 0),\n                            0xa,\n                            ServerState.FOLLOWING,\n                            1,\n                            0x17,\n                            outofelection);\n\n        genNotification( 0x0,\n                            5,\n                            ZxidUtils.makeZxid(15, 0),\n                            0xa,\n                            ServerState.FOLLOWING,\n                            2,\n                            0x17,\n                            outofelection);\n\n        genNotification( 0x1,\n                            5,\n                            ZxidUtils.makeZxid(15, 0),\n                            0xa,\n                            ServerState.FOLLOWING,\n                            4,\n                            0x18,\n                            outofelection);\n\n        FastLeaderElection.Notification n = genNotification( 0x1,\n                                                                5,\n                                                                ZxidUtils.makeZxid(15, 0),\n                                                                0xa,\n                                                                ServerState.LEADING,\n                                                                5,\n                                                                0x18,\n                                                                outofelection);\n\n        /*\n         * fle represents the FLE instance of server 3.Here we set\n         * its logical clock to 1.\n         */\n        fle.logicalclock.set(0x1);\n\n\n        /*\n         * Here we test the predicates we use in FLE.\n         */\n        Assert.assertTrue(\"Termination predicate failed\",\n                            fle.termPredicate(outofelection,\n                                                new Vote(n.version,\n                                                         n.leader,\n                                                         n.zxid,\n                                                         n.electionEpoch,\n                                                         n.peerEpoch,\n                                                         n.state)));\n        Assert.assertTrue(\"Leader check failed\",\n                            fle.checkLeader(outofelection,\n                                                n.leader,\n                                                n.electionEpoch));\n\n        Assert.assertTrue(\"Out of election predicate failed\",\n                            fle.ooePredicate( outofelection, outofelection, n ));\n\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/FLELostMessageTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class FLELostMessageTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLELostMessageTest.class);\n\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    File tmpdir[];\n    int port[];\n\n    QuorumCnxManager cnxManager;\n\n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        tmpdir = new File[count];\n        port = new int[count];\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        cnxManager.halt();\n    }\n\n    @Test\n    public void testLostMessage() throws Exception {\n        FastLeaderElection le[] = new FastLeaderElection[count];\n\n        LOG.info(\"TestLE: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            int clientport = PortAssignment.unique();\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", clientport,\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = clientport;\n        }\n\n        /*\n         * Start server 0\n         */\n\n        QuorumPeer peer = new QuorumPeer(peers, tmpdir[1], tmpdir[1], port[1], 3, 1, 1000, 2, 2);\n        peer.startLeaderElection();\n        FLETestUtils.LEThread thread = new FLETestUtils.LEThread(peer, 1);\n        thread.start();\n\n        /*\n         * Start mock server 1\n         */\n        mockServer();\n        thread.join(5000);\n        if (thread.isAlive()) {\n            Assert.fail(\"Threads didn't join\");\n        }\n    }\n\n    void mockServer() throws InterruptedException, IOException {\n        /*\n         * Create an instance of the connection manager\n         */\n        QuorumPeer peer = new QuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 3, 0, 1000, 2, 2);\n        cnxManager = peer.createCnxnManager();\n        QuorumCnxManager.Listener listener = cnxManager.listener;\n        listener.start();\n\n\n        cnxManager.toSend(1l, FLETestUtils.createMsg(ServerState.LOOKING.ordinal(), 0, 0, 0));\n        cnxManager.recvQueue.take();\n        cnxManager.toSend(1L, FLETestUtils.createMsg(ServerState.FOLLOWING.ordinal(), 1, 0, 0));\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/FLETestUtils.java",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.nio.ByteBuffer;\n\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.junit.Assert;\n\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\n\npublic class FLETestUtils {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLETestUtils.class);\n    \n    \n    /*\n     * Thread to run an instance of leader election for \n     * a given quorum peer.\n     */\n    static class LEThread extends Thread {\n        private int i;\n        private QuorumPeer peer;\n\n        LEThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n\n        }\n\n        public void run(){\n            try{\n                Vote v = null;\n                peer.setPeerState(ServerState.LOOKING);\n                LOG.info(\"Going to call leader election: \" + i);\n                v = peer.getElectionAlg().lookForLeader();\n\n                if (v == null){\n                    Assert.fail(\"Thread \" + i + \" got a null vote\");\n                }\n\n                /*\n                 * A real zookeeper would take care of setting the current vote. Here\n                 * we do it manually.\n                 */\n                peer.setCurrentVote(v);\n\n                LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n\n                Assert.assertTrue(\"State is not leading.\", peer.getPeerState() == ServerState.LEADING);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            LOG.info(\"Joining\");\n        }\n    }\n    \n    /*\n     * Creates a leader election notification message.\n     */\n    \n    static ByteBuffer createMsg(int state, long leader, long zxid, long epoch){\n        return FastLeaderElection.buildMsg(state, leader, zxid, 1, epoch);\n    }\n\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/LearnerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.Socket;\nimport java.util.ArrayList;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Index;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.Learner;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class LearnerTest extends ZKTestCase {\n  private static final File testData = new File(\n    System.getProperty(\"test.data.dir\", \"build/test/data\"));\n\n\tclass SimpleLearnerZooKeeperServer extends LearnerZooKeeperServer {\n\t\tboolean startupCalled;\n\t\t\n\t\tpublic SimpleLearnerZooKeeperServer(FileTxnSnapLog ftsl, QuorumPeer self) throws IOException {\n\t\t\tsuper(ftsl, 2000, 2000, 2000, null, new ZKDatabase(ftsl), self);\n\t\t}\n\t\tLearner learner;\n\t\t@Override\n\t\tpublic Learner getLearner() {\n\t\t\treturn learner;\n\t\t}\n\t\t\n\t\t@Override\n\t\tpublic void startup() {\n\t\t\tstartupCalled = true;\n\t\t}\n\t}\n\tclass SimpleLearner extends Learner {\n\t\tSimpleLearner(FileTxnSnapLog ftsl) throws IOException {\n            self = QuorumPeer.testingQuorumPeer();\n            zk = new SimpleLearnerZooKeeperServer(ftsl, self);\n\t\t\t((SimpleLearnerZooKeeperServer)zk).learner = this;\n\t\t}\n\t}\n\tstatic private void recursiveDelete(File dir) {\n\t\tif (dir == null || !dir.exists()) {\n\t\t\treturn;\n\t\t}\n\t\tif (!dir.isDirectory()) {\n\t\t\tdir.delete();\n\t\t}\n\t\tfor(File child: dir.listFiles()) {\n\t\t\trecursiveDelete(child);\n\t\t}\n\t}\n\t@Test\n\tpublic void syncTest() throws Exception {\n\t\tFile tmpFile = File.createTempFile(\"test\", \".dir\", testData);\n\t\ttmpFile.delete();\n\t\ttry {\n\t\t\tFileTxnSnapLog ftsl = new FileTxnSnapLog(tmpFile, tmpFile);\n\t\t\tSimpleLearner sl = new SimpleLearner(ftsl);\n\t\t\tlong startZxid = sl.zk.getLastProcessedZxid();\n\t\t\t\n\t\t\t// Set up bogus streams\n\t\t\tByteArrayOutputStream baos = new ByteArrayOutputStream();\n\t\t\tBinaryOutputArchive oa = BinaryOutputArchive.getArchive(baos);\n\t\t\tsl.leaderOs = BinaryOutputArchive.getArchive(new ByteArrayOutputStream());\n\t\t\t\n\t\t\t// make streams and socket do something innocuous\n\t\t\tsl.bufferedOutput = new BufferedOutputStream(System.out);\n\t\t\tsl.sock = new Socket();\n\t\t\t\n\t\t\t// fake messages from the server\n\t\t\tQuorumPacket qp = new QuorumPacket(Leader.SNAP, 0, null, null);\n\t\t\toa.writeRecord(qp, null);\n\t\t\tsl.zk.getZKDatabase().serializeSnapshot(oa);\n\t\t\toa.writeString(\"BenWasHere\", \"signature\");\n\t\t\tTxnHeader hdr = new TxnHeader(0, 0, 0, 0, ZooDefs.OpCode.create);\n\t\t\tCreateTxn txn = new CreateTxn(\"/foo\", new byte[0], new ArrayList<ACL>(), false, sl.zk.getZKDatabase().getNode(\"/\").stat.getCversion());\n\t        ByteArrayOutputStream tbaos = new ByteArrayOutputStream();\n\t        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(tbaos);\n\t        hdr.serialize(boa, \"hdr\");\n\t        txn.serialize(boa, \"txn\");\n\t        tbaos.close();\n\t\t\tqp = new QuorumPacket(Leader.PROPOSAL, 1, tbaos.toByteArray(), null);\n\t\t\toa.writeRecord(qp, null);\n\n\t\t\t// setup the messages to be streamed to follower\n\t\t\tsl.leaderIs = BinaryInputArchive.getArchive(new ByteArrayInputStream(baos.toByteArray()));\n\t\t\t\n\t\t\ttry {\n\t\t\t\tsl.syncWithLeader(3);\n\t\t\t} catch(EOFException e) {}\n\t\t\t\n\t\t\tsl.zk.shutdown();\n\t\t\tsl = new SimpleLearner(ftsl);\n\t\t\tAssert.assertEquals(startZxid, sl.zk.getLastProcessedZxid());\n\t\t} finally {\n\t\t\trecursiveDelete(tmpFile);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/QuorumCnxManagerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.security.sasl.SaslException;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.auth.NullQuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.NullQuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuth;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.QuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.auth.SaslQuorumAuthLearner;\nimport org.apache.zookeeper.server.quorum.auth.SaslQuorumAuthServer;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumMaj;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.anyLong;\nimport static org.mockito.Matchers.eq;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\n\npublic class QuorumCnxManagerTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumCnxManagerTest.class);\n    private int count;\n    private HashMap<Long,QuorumServer> peers;\n    private int peerQuorumPort[];\n    private int peerClientPort[];\n    private ThreadPoolExecutor executor;\n    /**\n     * The maximum number of threads to allow in the connectionExecutors thread\n     * pool which will be used to initiate quorum server connections. Defaulting to 20.\n     * TODO: Need to tune this param.\n     */\n    private final int quorumCnxnThreadsSize = 20;\n    private Set<String> authzHosts;\n\n    private static File saslConfigFile = null;\n\n    @BeforeClass\n    public static void setupSasl() throws Exception {\n        String jaasEntries = new String(\"\"\n                + \"QuorumServer {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       user_test=\\\"mypassword\\\";\\n\"\n                + \"};\\n\"\n                + \"QuorumLearner {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       username=\\\"test\\\"\\n\"\n                + \"       password=\\\"mypassword\\\";\\n\"\n                + \"};\\n\"\n                + \"QuorumLearnerInvalid {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       username=\\\"test\\\"\\n\"\n                + \"       password=\\\"invalid\\\";\\n\"\n                + \"};\\n\");\n\n        saslConfigFile = File.createTempFile(\"jaas.\", \".conf\");\n        FileWriter fwriter = new FileWriter(saslConfigFile);\n        fwriter.write(jaasEntries);\n        fwriter.close();\n        System.setProperty(\"java.security.auth.login.config\",\n                           saslConfigFile.getAbsolutePath());\n    }\n\n    @AfterClass\n    public static void cleanupSasl() throws Exception {\n        if (saslConfigFile != null) {\n            saslConfigFile.delete();\n        }\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        this.count = 3;\n        this.peers = new HashMap<Long,QuorumServer>(count);\n        peerQuorumPort = new int[count];\n        peerClientPort = new int[count];\n        authzHosts = new HashSet<String>();\n        for(int i = 0; i < count; i++) {\n            peerQuorumPort[i] = PortAssignment.unique();\n            peerClientPort[i] = PortAssignment.unique();\n            QuorumServer qs = new QuorumServer(i, \"0.0.0.0\",\n                    peerQuorumPort[i], PortAssignment.unique(), null);\n            peers.put(Long.valueOf(i), qs);\n            authzHosts.add(qs.hostname);\n        }\n        executor = new ThreadPoolExecutor(3, 10,\n                60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if (executor != null) {\n            executor.shutdownNow();\n        }\n    }\n\n    @Test(timeout = 30000)\n    public void testNoAuthConnection() throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0);\n        QuorumCnxManager peer1 = createAndStartManager(1);\n\n        peer0.connectOne(1);\n        assertEventuallyConnected(peer0, 1);\n    }\n\n    @Test(timeout = 30000)\n    public void testAuthConnection() throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0, \"QuorumServer\",\n                                                       \"QuorumLearner\", true, true);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                                                       \"QuorumLearner\", true, true);\n        peer0.connectOne(1);\n        assertEventuallyConnected(peer0, 1);\n    }\n\n    /**\n     * Peer0 has no auth configured, Peer1 has auth configured.\n     * Peer1 connects to peer0, because null auth server sees an auth packet and connection succeeds.\n     * Peer0 connects to peer1, but connection isn't initiated because\n     * peer0's sid is lower than peer1's\n     */\n    @Test(timeout = 30000)\n    public void testClientAuthAgainstNoAuthServerWithLowerSid()\n            throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                                                       \"QuorumLearner\", false, false);\n        peer1.connectOne(0);\n        peer0.connectOne(1);\n        assertEventuallyConnected(peer0, 1);\n    }\n\n    /**\n     * Peer0 has auth configured, Peer1 has no auth configured.\n     * Peer0 connects to peer1, but is disconnected, because peer1's sid is\n     * higher than peer0.\n     * Peer1 connects to peer0, but is disconnected, because peer1 cannot\n     * handle auth.\n     */\n    @Test(timeout = 30000)\n    public void testClientAuthAgainstNoAuthServerWithHigherSid()\n            throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0, \"QuorumServer\",\n                                                       \"QuorumLearner\", false, false);\n        QuorumCnxManager peer1 = createAndStartManager(1);\n        peer0.connectOne(1);\n        peer1.connectOne(0);\n        assertEventuallyConnected(peer0, 1);\n    }\n\n    /**\n     * No auth learner connects to a server that requires auth, when the server\n     * has a higher sid.\n     * The connection should fail in both directions.\n     */\n    @Test(timeout = 30000)\n    public void testNoAuthLearnerConnectToAuthRequiredServerWithLowerSid()\n            throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0, \"QuorumServer\",\n                                                       \"QuorumLearner\", true, true);\n        QuorumCnxManager peer1 = createAndStartManager(1);\n        peer0.connectOne(1);\n        peer1.connectOne(0);\n        assertEventuallyNotConnected(peer0, 1);\n    }\n\n    /**\n     * No auth learner connects to a server that requires auth, when the server\n     * has a higher sid.\n     * The connection should fail in both directions.\n     *\n     * peer0 should attempt to connect to peer1, but disconnect as its sid is lower\n     * peer1 should attempt to connect to peer0, peer0 will accept and add an entry to\n     * the senderWorkerMap but peer1 will disconnect because peer1 will start speaking SASL\n     * and peer0 will consider this invalid.\n     *\n     * Due to the unique behavior of peer0 creating an entry\n     * in senderWorkerMap for peer1 and then deleting it we use mockito spies to track\n     * this behavior.\n     */\n    @Test(timeout = 30000)\n    public void testNoAuthLearnerConnectToAuthRequiredServerWithHigherSid()\n            throws Exception {\n        ConcurrentHashMap<Long, QuorumCnxManager.SendWorker> senderWorkerMap0 =\n                spy(new ConcurrentHashMap<Long, QuorumCnxManager.SendWorker>());\n        ConcurrentHashMap<Long, QuorumCnxManager.SendWorker> senderWorkerMap1 =\n                spy(new ConcurrentHashMap<Long, QuorumCnxManager.SendWorker>());\n\n        QuorumCnxManager peer0 = createAndStartManager(0, senderWorkerMap0);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\", \"QuorumLearner\",\n                true, true, senderWorkerMap1);\n        peer0.connectOne(1);\n        peer1.connectOne(0);\n\n        verify(senderWorkerMap0, timeout(10000)).put(eq(1L), any(QuorumCnxManager.SendWorker.class));\n        verify(senderWorkerMap0, timeout(10000)).remove(eq(1L), any(QuorumCnxManager.SendWorker.class));\n\n        verify(senderWorkerMap1, never()).put(anyLong(), any(QuorumCnxManager.SendWorker.class));\n    }\n\n    /**\n     * An auth learner connects to a auth server, but the credentials are bad.\n     * The peer with the higher sid has the bad credentials.\n     * The connection will be denied.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerBadCredToAuthRequiredServerWithLowerSid()\n            throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0,  \"QuorumServer\",\n                                                       \"QuorumLearner\", true, true);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                                                       \"QuorumLearnerInvalid\", true, true);\n        peer0.connectOne(1);\n        peer1.connectOne(0);\n\n        assertEventuallyNotConnected(peer0, 1);\n    }\n\n    /**\n     * An auth learner connects to a auth server, but the credentials are bad.\n     * The peer with the lower sid has the bad credentials.\n     * The connection will work, because peer1 is connecting to peer0.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerBadCredToAuthRequiredServerWithHigherSid()\n            throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0,  \"QuorumServer\",\n                                                       \"QuorumLearnerInvalid\", true, true);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                                                       \"QuorumLearner\", true, true);\n        peer0.connectOne(1);\n        peer1.connectOne(0);\n        assertEventuallyConnected(peer0, 1);\n        assertEventuallyConnected(peer1, 0);\n    }\n\n    /**\n     * An auth learner connects to a auth server, but the credentials are bad.\n     * The connection should fail in both directions.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerBadCredToNoAuthServerWithHigherSid() throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0, \"QuorumServer\",\n                \"QuorumLearner\", false, false);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                \"QuorumLearnerInvalid\", true, true);\n        peer1.connectOne(0);\n        assertEventuallyNotConnected(peer1, 0);\n    }\n\n    /**\n     * An auth learner connects to a auth server, but the credentials are bad.\n     * The peer with the lower sid has the bad credentials.\n     * The connection will work, because peer0 is connecting to peer1 and peer1\n     * server doesn't require sasl\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerBadCredToNoAuthServerWithLowerSid() throws Exception {\n        QuorumCnxManager peer0 = createAndStartManager(0, \"QuorumServer\",\n                \"QuorumLearnerInvalid\", true, true);\n        QuorumCnxManager peer1 = createAndStartManager(1, \"QuorumServer\",\n                \"QuorumLearner\", false, true);\n        peer0.connectOne(1);\n        assertEventuallyConnected(peer0, 1);\n        assertEventuallyConnected(peer1, 0);\n    }\n\n    /**\n     * Test verifies that the LearnerHandler should authenticate the connecting\n     * quorumpeer. Here its simulating authentication failure and it should throw\n     * SaslException\n     */\n    @Test(timeout = 30000)\n    public void testLearnerHandlerAuthFailed() throws Exception {\n        File testData = ClientBase.createTmpDir();\n        Socket leaderSocket = getSocketPair();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, true, false, true,\n                \"QuorumLearner\", \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        leader = createLeader(tmpDir, peer);\n        peer.leader = leader;\n\n        // authentication failed as qpserver didn't get auth packet from qpclient.\n        try {\n            new LearnerHandler(leaderSocket,\n                    new BufferedInputStream(leaderSocket.getInputStream()), leader);\n            Assert.fail(\"Must throw exception as there is an authentication failure\");\n        } catch (SaslException e){\n            Assert.assertEquals(\"Mistakely added to learners\", 0,\n                    leader.getLearners().size());\n        }\n        ClientBase.recursiveDelete(testData);\n    }\n\n    /**\n     * Test verifies that the Leader should authenticate the connecting learner\n     * quorumpeer. After the successful authentication it should add this\n     * learner to the learnerHandler list.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerConnectsToServerWithAuthRequired()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, true, true,\n                \"QuorumLearner\", \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, true, true, true, \"QuorumLearner\",\n                \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n        String hostname = getLeaderHostname(peer);\n        sl.connectToLeader(peer.getQuorumAddress(), hostname);\n        // wait till leader socket soTimeout period\n        Assert.assertTrue(\"Leader should accept the auth learner connection\",\n                learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 1000,\n                        TimeUnit.MILLISECONDS));\n        Assert.assertEquals(\"Failed to added the learner\", 1,\n                leader.getLearners().size());\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    private String getLeaderHostname(QuorumPeer peer) {\n        String hostname = null;\n        for (QuorumServer p : peer.getView().values()) {\n            if (p.id == peer.getId()) {\n                hostname = p.hostname;\n                break;\n            }\n        }\n        Assert.assertNotNull(\"Didn't find leader\", hostname);\n        return hostname;\n    }\n\n    /**\n     * Test verifies that the Leader should authenticate the connecting learner\n     * quorumpeer. After the successful authentication it should add this\n     * learner to the learnerHandler list.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerConnectsToServerWithAuthNotRequired()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, true, true,\n                \"QuorumLearner\", \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, true, true, false, \"QuorumLearner\",\n                \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n        String hostname = getLeaderHostname(peer);\n        sl.connectToLeader(peer.getQuorumAddress(), hostname);\n        // wait till leader socket soTimeout period\n        Assert.assertTrue(\"Leader should accept the auth learner connection\",\n                learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 1000,\n                        TimeUnit.MILLISECONDS));\n        Assert.assertEquals(\"Failed to added the learner\", 1,\n                leader.getLearners().size());\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    private void startLearnerCnxAcceptorThread(Leader leader)\n            throws InterruptedException {\n        final CountDownLatch cnxAcceptorWatcher = new CountDownLatch(1);\n        leader.cnxAcceptor = leader.new LearnerCnxAcceptor(){\n            @Override\n            public void run() {\n                cnxAcceptorWatcher.countDown();\n                super.run();\n            }\n        };\n        leader.cnxAcceptor.start();\n        // waiting to start the thread\n        Assert.assertTrue(\"Failed to start leader.cnxAcceptor thread!\",\n                cnxAcceptorWatcher.await(15, TimeUnit.SECONDS));\n        LOG.info(\"Started leader.cnxAcceptor:{} thread, state:{}\",\n                leader.cnxAcceptor.getName(), leader.cnxAcceptor.getState());\n    }\n\n    /**\n     * Test verifies that the Auth enabled Learner is connecting to a Null Auth\n     * Leader server. Learner is failing to get an auth response from Null Auth\n     * Leader and fails the connection establishment.\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerConnectsToNullAuthServer()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, true, true,\n                \"QuorumLearner\", \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, false, false, false,\n                \"QuorumLearner\", \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n\n        try {\n            String hostname = getLeaderHostname(peer);\n            sl.connectToLeader(peer.getQuorumAddress(), hostname);\n            Assert.fail(\"Must throw exception as server doesn't supports authentication\");\n        } catch (IOException e) {\n            // expected\n            Assert.assertTrue(\"Leader should accept the auth learner connection\",\n                    learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 500,\n                            TimeUnit.MILLISECONDS));\n        }\n\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    /**\n     * Test verifies that the No Auth enabled Learner is connecting to a No Auth\n     * Leader server. Learner should be able to establish a connection with\n     * Leader as auth is not required.\n     */\n    @Test(timeout = 30000)\n    public void testNoAuthLearnerConnectsToServerWithAuthNotRequired()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, false, false,\n                \"QuorumLearner\", \"QuorumServer\", \"\");\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, true, false, false, \"QuorumLearner\",\n                \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n        String hostname = getLeaderHostname(peer);\n        sl.connectToLeader(peer.getQuorumAddress(), hostname);\n\n        Assert.assertTrue(\"Leader should accept no auth learner connection\",\n                learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 1000,\n                        TimeUnit.MILLISECONDS));\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    /**\n     * Test verifies that the No Auth enabled Learner is connecting to a No Auth\n     * Leader server. Learner shouldn't be able to establish a connection with\n     * Leader as auth as auth is required.\n     */\n    @Test(timeout = 30000)\n    public void testNoAuthLearnerConnectsToServerWithAuthRequired()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, false, false,\n                \"QuorumLearner\", \"QuorumServer\", \"\");\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, true, true, true, \"QuorumLearner\",\n                \"QuorumServer\",\n                QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL_DEFAULT_VALUE);\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n        String hostname = getLeaderHostname(peer);\n        sl.connectToLeader(peer.getQuorumAddress(), hostname);\n        Assert.assertFalse(\"Leader shouldn't accept no auth learner connection\",\n                learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 1000,\n                        TimeUnit.MILLISECONDS));\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    /**\n     * Test verifies that the No Auth enabled Learner is connecting to a No Auth\n     * Leader server. Learner should be able to establish a connection with\n     * Leader as auth is not required.\n     */\n    @Test(timeout = 30000)\n    public void testNoAuthLearnerConnectsToNullAuthServer()\n            throws Exception {\n        File testDataLearner = ClientBase.createTmpDir();\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testDataLearner);\n        tmpDir.delete();\n        FileTxnSnapLog ftsl = new FileTxnSnapLog(tmpDir, tmpDir);\n        QuorumPeer learnerPeer = createQuorumPeer(tmpDir, true, false, false,\n                \"QuorumLearner\", \"QuorumServer\", \"\");\n        SimpleLearner sl = new SimpleLearner(ftsl, learnerPeer);\n\n        File testDataLeader = ClientBase.createTmpDir();\n        tmpDir = File.createTempFile(\"test\", \".dir\", testDataLeader);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        QuorumPeer peer = createQuorumPeer(tmpDir, false, false, false, \"\", \"\",\n                \"\");\n        CountDownLatch learnerLatch = new CountDownLatch(1);\n        leader = createSimpleLeader(tmpDir, peer, learnerLatch);\n        peer.leader = leader;\n\n        startLearnerCnxAcceptorThread(leader);\n        LOG.info(\"Start establishing a connection with the Leader\");\n        String hostname = getLeaderHostname(peer);\n        sl.connectToLeader(peer.getQuorumAddress(), hostname);\n\n        Assert.assertTrue(\"Leader should accept no auth learner connection\",\n                learnerLatch.await(leader.self.tickTime * leader.self.initLimit + 1000,\n                        TimeUnit.MILLISECONDS));\n        ClientBase.recursiveDelete(testDataLearner);\n        ClientBase.recursiveDelete(testDataLeader);\n    }\n\n    /**\n     * SaslQuorumAuthServer throws exception on receiving an invalid quorum\n     * auth packet.\n     */\n    @Test(timeout = 30000)\n    public void testSaslQuorumAuthServerWithInvalidQuorumAuthPacket()\n            throws Exception {\n        Socket socket = getSocketPair();\n        DataOutputStream dout = new DataOutputStream(socket.getOutputStream());\n        BufferedOutputStream bufferedOutput = new BufferedOutputStream(dout);\n        BinaryOutputArchive boa = BinaryOutputArchive\n                .getArchive(bufferedOutput);\n        QuorumAuthPacket authPacket = QuorumAuth\n                .createPacket(QuorumAuth.Status.IN_PROGRESS, null);\n        authPacket.setMagic(Long.MAX_VALUE); // invalid magic number\n        boa.writeRecord(authPacket, null);\n        bufferedOutput.flush();\n        QuorumAuthServer authServer = new SaslQuorumAuthServer(true,\n                \"QuorumServer\", authzHosts);\n        BufferedInputStream is = new BufferedInputStream(\n                socket.getInputStream());\n        try {\n            authServer.authenticate(socket, new DataInputStream(is));\n            Assert.fail(\"Must throw exception as QuorumAuthPacket is invalid\");\n        } catch (SaslException e) {\n            // expected\n        }\n    }\n\n    /**\n     * NullQuorumAuthServer should return true when no auth quorum packet\n     * received and timed out.\n     */\n    @Test(timeout = 30000)\n    public void testNullQuorumAuthServerShouldReturnTrue()\n            throws Exception {\n        Socket socket = getSocketPair();\n        QuorumAuthServer authServer = new NullQuorumAuthServer();\n        BufferedInputStream is = new BufferedInputStream(\n                socket.getInputStream());\n        // It will throw exception and fail the\n        // test if any unexpected error. Not adding any extra assertion.\n        authServer.authenticate(socket, new DataInputStream(is));\n    }\n\n    /**\n     * NullQuorumAuthServer should return true on receiving a valid quorum auth\n     * packet.\n     */\n    @Test(timeout = 30000)\n    public void testNullQuorumAuthServerWithValidQuorumAuthPacket()\n            throws Exception {\n        Socket socket = getSocketPair();\n        DataOutputStream dout = new DataOutputStream(socket.getOutputStream());\n        BufferedOutputStream bufferedOutput = new BufferedOutputStream(dout);\n        BinaryOutputArchive boa = BinaryOutputArchive\n                .getArchive(bufferedOutput);\n        QuorumAuthPacket authPacket = QuorumAuth\n                .createPacket(QuorumAuth.Status.IN_PROGRESS, null);\n        boa.writeRecord(authPacket, null);\n        bufferedOutput.flush();\n        QuorumAuthServer authServer = new NullQuorumAuthServer();\n        BufferedInputStream is = new BufferedInputStream(\n                socket.getInputStream());\n        // It will throw exception and fail the\n        // test if any unexpected error. Not adding any extra assertion.\n        authServer.authenticate(socket, new DataInputStream(is));\n    }\n\n    private QuorumCnxManager createAndStartManager(long sid) {\n        return createAndStartManager(sid, new ConcurrentHashMap<Long, QuorumCnxManager.SendWorker>());\n    }\n\n    private QuorumCnxManager createAndStartManager(long sid, ConcurrentHashMap<Long, QuorumCnxManager.SendWorker> senderWorkerMap) {\n        QuorumCnxManager peer = new QuorumCnxManager(sid, peers,\n                new NullQuorumAuthServer(), new NullQuorumAuthLearner(), 10000,\n                false, quorumCnxnThreadsSize, false,\n                senderWorkerMap);\n        executor.submit(peer.listener);\n        InetSocketAddress electionAddr = peer.view.get(sid).electionAddr;\n        waitForElectionAddrBinding(electionAddr, 15);\n        return peer;\n    }\n\n    private QuorumCnxManager createAndStartManager(long sid,\n                                                   String serverLoginContext,\n                                                   String learnerLoginContext,\n                                                   boolean serverRequireSasl,\n                                                   boolean learnerRequireSasl) throws Exception {\n        return createAndStartManager(sid, serverLoginContext, learnerLoginContext, serverRequireSasl, learnerRequireSasl, new ConcurrentHashMap<Long, QuorumCnxManager.SendWorker>());\n\n    }\n\n    private QuorumCnxManager createAndStartManager(long sid,\n                                                   String serverLoginContext,\n                                                   String learnerLoginContext,\n                                                   boolean serverRequireSasl,\n                                                   boolean learnerRequireSasl,\n                                                   ConcurrentHashMap<Long, QuorumCnxManager.SendWorker> senderWorkerMap)\n            throws Exception {\n        QuorumAuthLearner authClient = new SaslQuorumAuthLearner(learnerRequireSasl,\n                \"NOT_USING_KRB_PRINCIPAL\", learnerLoginContext);\n        QuorumAuthServer authServer = new SaslQuorumAuthServer(serverRequireSasl,\n                serverLoginContext, authzHosts);\n        QuorumCnxManager peer = new QuorumCnxManager(sid, peers,\n                authServer, authClient, 10000, false, quorumCnxnThreadsSize, true, senderWorkerMap);\n        executor.submit(peer.listener);\n        InetSocketAddress electionAddr = peer.view.get(sid).electionAddr;\n        waitForElectionAddrBinding(electionAddr, 15);\n        return peer;\n    }\n\n    private void waitForElectionAddrBinding(InetSocketAddress electionAddr,\n            int retries) {\n        boolean success = false;\n        while (retries > 0) {\n            Socket sock = new Socket();\n            try {\n                sock.setTcpNoDelay(true);\n                sock.setSoTimeout(5000);\n                sock.connect(electionAddr, 5000);\n                success = true;\n            } catch (IOException e) {\n                LOG.error(\"IOException while checking election addr\", e);\n            } finally {\n                cleanup(sock);\n            }\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n            retries--;\n        }\n        Assert.assertTrue(\"Did not connect to election port\", success);\n    }\n\n    private void cleanup(Socket sock) {\n        try {\n            sock.close();\n        } catch (IOException ie) {\n            LOG.error(\"Exception while closing socket\", ie);\n        }\n    }\n\n    private void assertEventuallyConnected(QuorumCnxManager peer, long sid)\n            throws Exception {\n        for (int i = 0; i < 20 && !peer.connectedToPeer(sid); i++) {\n            Thread.sleep(1000);\n        }\n        Assert.assertTrue(\"Not connected to peer\", peer.connectedToPeer(sid));\n    }\n\n    private void assertEventuallyNotConnected(QuorumCnxManager peer, long sid)\n            throws Exception {\n        for (int i = 0; i < 3 && !peer.connectedToPeer(sid); i++) {\n            Thread.sleep(1000);\n        }\n        Assert.assertFalse(\"Connected to peer (shouldn't be)\",\n                           peer.connectedToPeer(sid));\n    }\n\n    private QuorumPeer createQuorumPeer(File tmpDir,\n            boolean isQuorumAuthEnabled, boolean isQuorumLearnerAuthRequired,\n            boolean isQuorumServerAuthRequired, String quorumLearnerLoginContext,\n            String quorumServerLoginContext, String quorumServicePrincipal)\n                    throws IOException, FileNotFoundException {\n        QuorumPeer peer = QuorumPeer.testingQuorumPeer();\n        peer.syncLimit = 2;\n        peer.initLimit = 2;\n        peer.tickTime = 2000;\n        peer.quorumPeers = new HashMap<Long, QuorumServer>();\n        peer.quorumPeers.put(0L,\n                new QuorumServer(0, \"0.0.0.0\", PortAssignment.unique(), null, null));\n        peer.quorumPeers.put(1L,\n                new QuorumServer(1, \"0.0.0.0\", PortAssignment.unique(), null, null));\n        peer.setQuorumVerifier(new QuorumMaj(3));\n        peer.setCnxnFactory(new NullServerCnxnFactory());\n        // auth\n        if (isQuorumAuthEnabled) {\n            peer.authServer = new SaslQuorumAuthServer(\n                    isQuorumServerAuthRequired, quorumServerLoginContext, authzHosts);\n            peer.authLearner = new SaslQuorumAuthLearner(\n                    isQuorumLearnerAuthRequired, quorumServicePrincipal,\n                    quorumLearnerLoginContext);\n        }\n        File version2 = new File(tmpDir, \"version-2\");\n        version2.mkdir();\n        FileOutputStream fos;\n        fos = new FileOutputStream(new File(version2, \"currentEpoch\"));\n        fos.write(\"0\\n\".getBytes());\n        fos.close();\n        fos = new FileOutputStream(new File(version2, \"acceptedEpoch\"));\n        fos.write(\"0\\n\".getBytes());\n        fos.close();\n        return peer;\n    }\n\n    private static final class NullServerCnxnFactory extends ServerCnxnFactory {\n        public void startup(ZooKeeperServer zkServer)\n                throws IOException, InterruptedException {\n        }\n\n        public void start() {\n        }\n\n        public void shutdown() {\n        }\n\n        public void setMaxClientCnxnsPerHost(int max) {\n        }\n\n        public void join() throws InterruptedException {\n        }\n\n        public int getMaxClientCnxnsPerHost() {\n            return 0;\n        }\n\n        public int getLocalPort() {\n            return 0;\n        }\n\n        public InetSocketAddress getLocalAddress() {\n            return null;\n        }\n\n        public Iterable<ServerCnxn> getConnections() {\n            return null;\n        }\n\n        public void configure(InetSocketAddress addr, int maxClientCnxns)\n                throws IOException {\n        }\n\n        public void closeSession(long sessionId) {\n        }\n\n        public void closeAll() {\n        }\n\n        @Override\n        public int getNumAliveConnections() {\n            return 0;\n        }\n    }\n\n    private static Socket getSocketPair() throws IOException {\n        ServerSocket ss = new ServerSocket();\n        ss.bind(null);\n        InetSocketAddress endPoint = (InetSocketAddress) ss\n                .getLocalSocketAddress();\n        Socket s = new Socket(endPoint.getAddress(), endPoint.getPort());\n        s.setSoTimeout(5000);\n        return s;\n    }\n\n    private Leader createLeader(File tmpDir, QuorumPeer peer) throws IOException,\n                    NoSuchFieldException, IllegalAccessException {\n        LeaderZooKeeperServer zk = prepareLeader(tmpDir, peer);\n        return new Leader(peer, zk);\n    }\n\n    private Leader createSimpleLeader(File tmpDir, QuorumPeer peer,\n            CountDownLatch learnerLatch) throws IOException,\n                    NoSuchFieldException, IllegalAccessException {\n        LeaderZooKeeperServer zk = prepareLeader(tmpDir, peer);\n        return new SimpleLeader(peer, zk, learnerLatch);\n    }\n\n    class SimpleLeader extends Leader {\n        final CountDownLatch learnerLatch;\n\n        SimpleLeader(QuorumPeer self, LeaderZooKeeperServer zk,\n                CountDownLatch latch) throws IOException {\n            super(self, zk);\n            this.learnerLatch = latch;\n        }\n\n        @Override\n        void addLearnerHandler(LearnerHandler learner) {\n            super.addLearnerHandler(learner);\n            learnerLatch.countDown();\n        }\n    }\n\n    private LeaderZooKeeperServer prepareLeader(File tmpDir, QuorumPeer peer)\n            throws IOException, NoSuchFieldException, IllegalAccessException {\n        FileTxnSnapLog logFactory = new FileTxnSnapLog(tmpDir, tmpDir);\n        peer.setTxnFactory(logFactory);\n        Field addrField = peer.getClass().getDeclaredField(\"myQuorumAddr\");\n        addrField.setAccessible(true);\n        addrField.set(peer, new InetSocketAddress(PortAssignment.unique()));\n        ZKDatabase zkDb = new ZKDatabase(logFactory);\n        LeaderZooKeeperServer zk = new LeaderZooKeeperServer(logFactory, peer,\n                new ZooKeeperServer.BasicDataTreeBuilder(), zkDb);\n        return zk;\n    }\n\n    class SimpleLearnerZooKeeperServer extends LearnerZooKeeperServer {\n        boolean startupCalled;\n\n        public SimpleLearnerZooKeeperServer(FileTxnSnapLog ftsl,\n                QuorumPeer self) throws IOException {\n            super(ftsl, 2000, 2000, 2000, null, new ZKDatabase(ftsl), self);\n        }\n\n        Learner learner;\n\n        @Override\n        public Learner getLearner() {\n            return learner;\n        }\n\n        @Override\n        public void startup() {\n            startupCalled = true;\n        }\n    }\n\n    class SimpleLearner extends Learner {\n        SimpleLearner(FileTxnSnapLog ftsl, QuorumPeer learner)\n                throws IOException {\n            self = learner;\n            zk = new SimpleLearnerZooKeeperServer(ftsl, self);\n            ((SimpleLearnerZooKeeperServer) zk).learner = this;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerMainTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.doCallRealMethod;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.LineNumberReader;\nimport java.io.OutputStreamWriter;\nimport java.io.StringReader;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Pattern;\n\nimport org.apache.log4j.Layout;\nimport org.apache.log4j.Level;\nimport org.apache.log4j.Logger;\nimport org.apache.log4j.PatternLayout;\nimport org.apache.log4j.WriterAppender;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.common.AtomicFileOutputStream;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.Leader.Proposal;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n\n/**\n * Test stand-alone server.\n *\n */\npublic class QuorumPeerMainTest extends QuorumPeerTestBase {\n    protected static final Logger LOG =\n        Logger.getLogger(QuorumPeerMainTest.class);\n\n    private Servers servers;\n    private int numServers = 0;\n\n    @After\n    public void tearDown() throws Exception {\n        if (servers == null || servers.mt == null) {\n            LOG.info(\"No servers to shutdown!\");\n            return;\n        }\n        for (int i = 0; i < numServers; i++) {\n            if (i < servers.mt.length) {\n                servers.mt[i].shutdown();\n            }\n        }\n    }\n\n\t/**\n     * Verify the ability to start a cluster.\n     */\n    @Test\n    public void testQuorum() throws Exception {\n        ClientBase.setupTestEnv();\n\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();\n        final int CLIENT_PORT_QP2 = PortAssignment.unique();\n\n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" + PortAssignment.unique()\n            + \"\\nserver.2=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" + PortAssignment.unique();\n\n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n        q1.start();\n        q2.start();\n\n        Assert.assertTrue(\"waiting for server 1 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                        CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"waiting for server 2 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                        CONNECTION_TIMEOUT));\n\n\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                ClientBase.CONNECTION_TIMEOUT, this);\n        waitForOne(zk, States.CONNECTED);\n        zk.create(\"/foo_q1\", \"foobar1\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        assertEquals(new String(zk.getData(\"/foo_q1\", null, null)), \"foobar1\");\n        zk.close();\n\n        zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                ClientBase.CONNECTION_TIMEOUT, this);\n        waitForOne(zk, States.CONNECTED);\n        zk.create(\"/foo_q2\", \"foobar2\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        assertEquals(new String(zk.getData(\"/foo_q2\", null, null)), \"foobar2\");\n        zk.close();\n\n        q1.shutdown();\n        q2.shutdown();\n\n        Assert.assertTrue(\"waiting for server 1 down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                        ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"waiting for server 2 down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                        ClientBase.CONNECTION_TIMEOUT));\n    }\n\n    /**\n     * Test early leader abandonment.\n     */\n    @Test\n    public void testEarlyLeaderAbandonment() throws Exception {\n        ClientBase.setupTestEnv();\n\n        final int SERVER_COUNT = 3;\n        final int clientPorts[] = new int[SERVER_COUNT];\n        StringBuilder sb = new StringBuilder();\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tclientPorts[i] = PortAssignment.unique();\n        \tsb.append(\"server.\"+i+\"=127.0.0.1:\"+PortAssignment.unique()+\":\"+PortAssignment.unique()+\"\\n\");\n        }\n        String quorumCfgSection = sb.toString();\n\n        MainThread mt[] = new MainThread[SERVER_COUNT];\n        ZooKeeper zk[] = new ZooKeeper[SERVER_COUNT];\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tmt[i] = new MainThread(i, clientPorts[i], quorumCfgSection);\n        \tmt[i].start();\n        \tzk[i] = new ZooKeeper(\"127.0.0.1:\" + clientPorts[i], ClientBase.CONNECTION_TIMEOUT, this);\n        }\n        \n        waitForAll(zk, States.CONNECTED);\n        \n        // we need to shutdown and start back up to make sure that the create session isn't the first transaction since\n        // that is rather innocuous.\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tmt[i].shutdown();\n        }\n        \n        waitForAll(zk, States.CONNECTING);\n        \n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tmt[i].start();\n        }\n        \n        waitForAll(zk, States.CONNECTED);\n        \n        // ok lets find the leader and kill everything else, we have a few\n        // seconds, so it should be plenty of time\n        int leader = -1;\n        Map<Long, Proposal> outstanding = null;\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tif (mt[i].main.quorumPeer.leader == null) {\n        \t\tmt[i].shutdown();\n        \t} else {\n        \t\tleader = i;\n        \t\toutstanding = mt[leader].main.quorumPeer.leader.outstandingProposals;\n        \t}\n        }\n        \n        try {\n        \tzk[leader].create(\"/zk\"+leader, \"zk\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n        \t\t\tCreateMode.PERSISTENT);\n        \tAssert.fail(\"create /zk\" + leader + \" should have failed\");\n        } catch(KeeperException e) {}\n        \n        // just make sure that we actually did get it in process at the \n        // leader\n        Assert.assertTrue(outstanding.size() == 1);\n        Assert.assertTrue(((Proposal)outstanding.values().iterator().next()).request.hdr.getType() == OpCode.create);\n        // make sure it has a chance to write it to disk\n        Thread.sleep(1000);\n        mt[leader].shutdown();\n        waitForAll(zk, States.CONNECTING);\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tif (i != leader) {\n        \t\tmt[i].start();\n        \t}\n        }\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tif (i != leader) {\n        \t\twaitForOne(zk[i], States.CONNECTED);\n        \t\tzk[i].create(\"/zk\" + i, \"zk\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        \t}\n        }\n        \n        mt[leader].start();\n        waitForAll(zk, States.CONNECTED);\n        // make sure everything is consistent\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tfor(int j = 0; j < SERVER_COUNT; j++) {\n        \t\tif (i == leader) {\n         \t\t\tAssert.assertTrue((j==leader?(\"Leader (\"+leader+\")\"):(\"Follower \"+j))+\" should not have /zk\" + i, zk[j].exists(\"/zk\"+i, false) == null);\n        \t\t} else {\n         \t\t\tAssert.assertTrue((j==leader?(\"Leader (\"+leader+\")\"):(\"Follower \"+j))+\" does not have /zk\" + i, zk[j].exists(\"/zk\"+i, false) != null);\n        \t\t}\n        \t}\n        }\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tzk[i].close();\n        }\n        for(int i = 0; i < SERVER_COUNT; i++) {\n        \tmt[i].shutdown();\n        }\n    }\n    \n    /**\n     * Test the case of server with highest zxid not present at leader election and joining later.\n     * This test case is for reproducing the issue and fixing the bug mentioned in  ZOOKEEPER-1154\n\t * and ZOOKEEPER-1156.\n     */\n    @Test\n    public void testHighestZxidJoinLate() throws Exception {\n        numServers = 3;\n        servers = LaunchServers(numServers);\n        String path = \"/hzxidtest\";\n        int leader = servers.findLeader();\n\n        // make sure there is a leader\n        Assert.assertTrue(\"There should be a leader\", leader >=0);\n\n        int nonleader = (leader+1)%numServers;\n\n        byte[] input = new byte[1];\n        input[0] = 1;\n        byte[] output;\n\n        // Create a couple of nodes\n        servers.zk[leader].create(path+leader, input, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        servers.zk[leader].create(path+nonleader, input, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        \n        // make sure the updates indeed committed. If it is not\n        // the following statement will throw.\n        output = servers.zk[leader].getData(path+nonleader, false, null);\n        \n        // Shutdown every one else but the leader\n        for (int i=0; i < numServers; i++) {\n            if (i != leader) {\n                servers.mt[i].shutdown();\n            }\n        }\n\n        input[0] = 2;\n\n        // Update the node on the leader\n        servers.zk[leader].setData(path+leader, input, -1, null, null);     \n        \n        // wait some time to let this get written to disk\n        Thread.sleep(500);\n\n        // shut the leader down\n        servers.mt[leader].shutdown();\n\n        System.gc();\n\n        waitForAll(servers.zk, States.CONNECTING);\n\n        // Start everyone but the leader\n        for (int i=0; i < numServers; i++) {\n            if (i != leader) {\n                servers.mt[i].start();\n            }\n        }\n\n        // wait to connect to one of these\n        waitForOne(servers.zk[nonleader], States.CONNECTED);\n\n        // validate that the old value is there and not the new one\n        output = servers.zk[nonleader].getData(path+leader, false, null);\n\n        assertEquals(\n                \"Expecting old value 1 since 2 isn't committed yet\",\n                output[0], 1);\n\n        // Do some other update, so we bump the maxCommttedZxid\n        // by setting the value to 2\n        servers.zk[nonleader].setData(path+nonleader, input, -1);\n\n        // start the old leader \n        servers.mt[leader].start();\n\n        // connect to it\n        waitForOne(servers.zk[leader], States.CONNECTED);\n\n        // make sure it doesn't have the new value that it alone had logged\n        output = servers.zk[leader].getData(path+leader, false, null);\n        assertEquals(\n                \"Validating that the deposed leader has rolled back that change it had written\",\n                output[0], 1);\n        \n        // make sure the leader has the subsequent changes that were made while it was offline\n        output = servers.zk[leader].getData(path+nonleader, false, null);\n        assertEquals(\n                \"Validating that the deposed leader caught up on changes it missed\",\n                output[0], 2);\n    }\n\n    /**\n     * This test validates that if a quorum member determines that it is leader without the support of the rest of the\n     * quorum (the other members do not believe it to be the leader) it will stop attempting to lead and become a follower.\n     *\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    @Test\n    public void testElectionFraud() throws IOException, InterruptedException {\n        // capture QuorumPeer logging\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        String loggingPattern = ((PatternLayout) Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout()).getConversionPattern();\n        WriterAppender appender = new WriterAppender(new PatternLayout(loggingPattern), os);\n        appender.setThreshold(Level.INFO);\n        Logger qlogger = Logger.getLogger(QuorumPeer.class);\n        qlogger.addAppender(appender);\n\n        numServers = 3;\n\n        // used for assertions later\n        boolean foundLeading = false;\n        boolean foundLooking = false;\n        boolean foundFollowing = false;\n\n        try {\n          // spin up a quorum, we use a small ticktime to make the test run faster\n          servers = LaunchServers(numServers, 500);\n\n          // find the leader\n          int trueLeader = servers.findLeader();\n          Assert.assertTrue(\"There should be a leader\", trueLeader >= 0);\n\n          // find a follower\n          int falseLeader = (trueLeader + 1) % numServers;\n          Assert.assertTrue(\"All servers should join the quorum\", servers.mt[falseLeader].main.quorumPeer.follower != null);\n\n          // to keep the quorum peer running and force it to go into the looking state, we kill leader election\n          // and close the connection to the leader\n          servers.mt[falseLeader].main.quorumPeer.electionAlg.shutdown();\n          servers.mt[falseLeader].main.quorumPeer.follower.getSocket().close();\n\n          // wait for the falseLeader to disconnect\n          waitForOne(servers.zk[falseLeader], States.CONNECTING);\n\n          // convince falseLeader that it is the leader\n          servers.mt[falseLeader].main.quorumPeer.setPeerState(QuorumPeer.ServerState.LEADING);\n\n          // provide time for the falseleader to realize no followers have connected\n          // (this is twice the timeout used in Leader#getEpochToPropose)\n          Thread.sleep(2 * servers.mt[falseLeader].main.quorumPeer.initLimit * servers.mt[falseLeader].main.quorumPeer.tickTime);\n\n          // Restart leader election\n          servers.mt[falseLeader].main.quorumPeer.startLeaderElection();\n\n          // The previous client connection to falseLeader likely closed, create a new one\n          servers.zk[falseLeader] = new ZooKeeper(\"127.0.0.1:\" + servers.mt[falseLeader].getClientPort(), ClientBase.CONNECTION_TIMEOUT, this);\n\n          // Wait for falseLeader to rejoin the quorum\n          waitForOne(servers.zk[falseLeader], States.CONNECTED);\n\n          // and ensure trueLeader is still the leader\n          Assert.assertTrue(servers.mt[trueLeader].main.quorumPeer.leader != null);\n\n          // Look through the logs for output that indicates the falseLeader is LEADING, then LOOKING, then FOLLOWING\n          LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n          Pattern leading = Pattern.compile(\".*myid=\" + falseLeader + \".*LEADING.*\");\n          Pattern looking = Pattern.compile(\".*myid=\" + falseLeader + \".*LOOKING.*\");\n          Pattern following = Pattern.compile(\".*myid=\" + falseLeader + \".*FOLLOWING.*\");\n\n          String line;\n          while ((line = r.readLine()) != null) {\n            if (!foundLeading) {\n              foundLeading = leading.matcher(line).matches();\n            } else if(!foundLooking) {\n              foundLooking = looking.matcher(line).matches();\n            } else if (following.matcher(line).matches()){\n              foundFollowing = true;\n              break;\n            }\n          }\n        } finally {\n          qlogger.removeAppender(appender);\n        }\n\n        Assert.assertTrue(\"falseLeader never attempts to become leader\", foundLeading);\n        Assert.assertTrue(\"falseLeader never gives up on leadership\", foundLooking);\n        Assert.assertTrue(\"falseLeader never rejoins the quorum\", foundFollowing);\n    }\n\n    private void waitForOne(ZooKeeper zk, States state) throws InterruptedException {\n        int iterations = ClientBase.CONNECTION_TIMEOUT / 500;\n        while (zk.getState() != state) {\n            if (iterations-- == 0) {\n                throw new RuntimeException(\"Waiting too long \" + zk.getState() + \" != \" + state);\n            }\n            Thread.sleep(500);\n        }\n    }\n\n    private void waitForAll(Servers servers, States state) throws InterruptedException {\n        waitForAll(servers.zk, state);\n    }\n\n    private void waitForAll(ZooKeeper[] zks, States state) throws InterruptedException {\n        int iterations = ClientBase.CONNECTION_TIMEOUT / 1000;\n        boolean someoneNotConnected = true;\n        while (someoneNotConnected) {\n            if (iterations-- == 0) {\n                ClientBase.logAllStackTraces();\n                throw new RuntimeException(\"Waiting too long\");\n            }\n\n            someoneNotConnected = false;\n            for (ZooKeeper zk : zks) {\n                if (zk.getState() != state) {\n                    someoneNotConnected = true;\n                    break;\n                }\n            }\n            Thread.sleep(1000);\n        }\n\t}\n\n    // This class holds the servers and clients for those servers\n    private class Servers {\n        MainThread mt[];\n        ZooKeeper zk[];\n        int[] clientPorts;\n\n        public void shutDownAllServers() throws InterruptedException {\n            for (MainThread t: mt) {\n                t.shutdown();\n            }\n        }\n\n        public void restartAllServersAndClients(Watcher watcher) throws IOException {\n            for (MainThread t : mt) {\n                if (!t.isAlive()) {\n                    t.start();\n                }\n            }\n            for (int i = 0; i < zk.length; i++) {\n                restartClient(i, watcher);\n            }\n        }\n\n        public void restartClient(int clientIndex, Watcher watcher) throws IOException {\n            zk[clientIndex] = new ZooKeeper(\"127.0.0.1:\" + clientPorts[clientIndex], ClientBase.CONNECTION_TIMEOUT, watcher);\n        }\n\n        public int findLeader() {\n            for (int i = 0; i < mt.length; i++) {\n                if (mt[i].main.quorumPeer.leader != null) {\n                    return i;\n                }\n            }\n            return -1;\n        }\n    }\n\n    private Servers LaunchServers(int numServers) throws IOException, InterruptedException {\n  \t    return LaunchServers(numServers, null);\n    }\n\n    /**\n     * This is a helper function for launching a set of servers\n     *\n     * @param numServers the number of servers\n     * @param tickTime A ticktime to pass to MainThread\n     * @return\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    private Servers LaunchServers(int numServers, Integer tickTime) throws IOException, InterruptedException {\n        int SERVER_COUNT = numServers;\n        Servers svrs = new Servers();\n        svrs.clientPorts = new int[SERVER_COUNT];\n        StringBuilder sb = new StringBuilder();\n        for(int i = 0; i < SERVER_COUNT; i++) {\n            svrs.clientPorts[i] = PortAssignment.unique();\n            sb.append(\"server.\"+i+\"=127.0.0.1:\"+PortAssignment.unique()+\":\"+PortAssignment.unique()+\"\\n\");\n        }\n        String quorumCfgSection = sb.toString();\n\n        svrs.mt = new MainThread[SERVER_COUNT];\n        svrs.zk = new ZooKeeper[SERVER_COUNT];\n        for(int i = 0; i < SERVER_COUNT; i++) {\n            if (tickTime != null) {\n                svrs.mt[i] = new MainThread(i, svrs.clientPorts[i], quorumCfgSection, new HashMap<String, String>(), tickTime);\n            } else {\n                svrs.mt[i] = new MainThread(i, svrs.clientPorts[i], quorumCfgSection);\n            }\n            svrs.mt[i].start();\n            svrs.restartClient(i, this);\n        }\n\n        waitForAll(svrs, States.CONNECTED);\n\n        return svrs;\n    }\n\n\n    /**\n     * Verify handling of bad quorum address\n     */\n    @Test\n    public void testBadPeerAddressInQuorum() throws Exception {\n        ClientBase.setupTestEnv();\n\n        // setup the logger to capture all logs\n        Layout layout =\n            Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setThreshold(Level.WARN);\n        Logger qlogger = Logger.getLogger(\"org.apache.zookeeper.server.quorum\");\n        qlogger.addAppender(appender);\n\n        try {\n            final int CLIENT_PORT_QP1 = PortAssignment.unique();\n            final int CLIENT_PORT_QP2 = PortAssignment.unique();\n\n            String quorumCfgSection =\n                \"server.1=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique()\n                + \"\\nserver.2=fee.fii.foo.fum:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique();\n\n            MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n            q1.start();\n\n            boolean isup =\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                        30000);\n\n            Assert.assertFalse(\"Server never came up\", isup);\n\n            q1.shutdown();\n\n            Assert.assertTrue(\"waiting for server 1 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n        } finally {\n            qlogger.removeAppender(appender);\n        }\n\n        LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n        String line;\n        boolean found = false;\n        Pattern p =\n            Pattern.compile(\".*Cannot open channel to .* at election address .*\");\n        while ((line = r.readLine()) != null) {\n            found = p.matcher(line).matches();\n            if (found) {\n                break;\n            }\n        }\n        Assert.assertTrue(\"complains about host\", found);\n    }\n\n    @Test\n    public void testValidIpv6AddressInQuorum() throws Exception {\n        assumeIPv6Available();\n\n        ClientBase.setupTestEnv();\n\n        // setup the logger to capture all logs\n        Layout layout =\n                Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setImmediateFlush(true);\n        appender.setThreshold(Level.INFO);\n        Logger qlogger = Logger.getLogger(\"org.apache.zookeeper.server.quorum\");\n        qlogger.addAppender(appender);\n\n        try {\n            final int CLIENT_PORT_QP1 = PortAssignment.unique();\n            final int CLIENT_PORT_QP2 = PortAssignment.unique();\n\n            String quorumCfgSection =\n                    \"server.1=127.0.0.1:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique()\n                    + \"\\nserver.2=[0:0:0:0:0:0:0:1]:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique();\n\n            MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n            MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n\n            q1.start();\n            q2.start();\n\n            Assert.assertTrue(\"waiting for server 1 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n            Assert.assertTrue(\"waiting for server 2 being up\",\n                    ClientBase.waitForServerUp(\"[0:0:0:0:0:0:0:1]:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n            q1.shutdown();\n            q2.shutdown();\n\n            Assert.assertTrue(\"waiting for server 1 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n            Assert.assertTrue(\"waiting for server 2 down\",\n                    ClientBase.waitForServerDown(\"[0:0:0:0:0:0:0:1]:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n        } finally {\n            qlogger.removeAppender(appender);\n        }\n\n        os.close();\n        LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n        String line;\n        boolean found = false;\n        Pattern p =\n                Pattern.compile(\".*Resolved hostname: 0:0:0:0:0:0:0:1.*\");\n        while ((line = r.readLine()) != null) {\n            found = p.matcher(line).matches();\n            if (found) {\n                break;\n            }\n        }\n        Assert.assertTrue(\"IPv6 address resolved\", found);\n    }\n\n    @Test\n    public void testInvalidIpv6AddressInQuorum() throws Exception {\n        assumeIPv6Available();\n\n        ClientBase.setupTestEnv();\n\n        // setup the logger to capture all logs\n        Layout layout =\n                Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setImmediateFlush(true);\n        appender.setThreshold(Level.INFO);\n        Logger qlogger = Logger.getLogger(\"org.apache.zookeeper.server.quorum\");\n        qlogger.addAppender(appender);\n\n        try {\n            final int CLIENT_PORT_QP1 = PortAssignment.unique();\n\n            String quorumCfgSection =\n                    \"server.1=127.0.0.1:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique()\n                    + \"\\nserver.2=[0:0:0:0:0:0:0:1:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique();\n\n            MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n            q1.start();\n\n            boolean isup =\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            30000);\n\n            Assert.assertFalse(\"Server never came up\", isup);\n\n            q1.shutdown();\n\n            Assert.assertTrue(\"waiting for server 1 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n        } finally {\n            qlogger.removeAppender(appender);\n        }\n\n        os.close();\n        LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n        String line;\n        boolean found = false;\n        Pattern p =\n                Pattern.compile(\".*QuorumPeerConfig\\\\$ConfigException.*\");\n        while ((line = r.readLine()) != null) {\n            found = p.matcher(line).matches();\n            if (found) {\n                break;\n            }\n        }\n        Assert.assertTrue(\"complains about configuration\", found);\n    }\n\n    /**\n     * Verify handling of inconsistent peer type\n     */\n    @Test\n    public void testInconsistentPeerType() throws Exception {\n        ClientBase.setupTestEnv();\n\n        // setup the logger to capture all logs\n        Layout layout =\n            Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setThreshold(Level.INFO);\n        Logger qlogger = Logger.getLogger(\"org.apache.zookeeper.server.quorum\");\n        qlogger.addAppender(appender);\n\n        // test the most likely situation only: server is stated as observer in\n        // servers list, but there's no \"peerType=observer\" token in config\n        try {\n            final int CLIENT_PORT_QP1 = PortAssignment.unique();\n            final int CLIENT_PORT_QP2 = PortAssignment.unique();\n            final int CLIENT_PORT_QP3 = PortAssignment.unique();\n\n            String quorumCfgSection =\n                \"server.1=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique()\n                + \"\\nserver.2=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique()\n                + \"\\nserver.3=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique() + \":observer\";\n\n            MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n            MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n            MainThread q3 = new MainThread(3, CLIENT_PORT_QP3, quorumCfgSection);\n            q1.start();\n            q2.start();\n            q3.start();\n\n            Assert.assertTrue(\"waiting for server 1 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 2 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                            CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 3 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP3,\n                            CONNECTION_TIMEOUT));\n\n            q1.shutdown();\n            q2.shutdown();\n            q3.shutdown();\n\n            Assert.assertTrue(\"waiting for server 1 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 2 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                            ClientBase.CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 3 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP3,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n        } finally {\n            qlogger.removeAppender(appender);\n        }\n\n        LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n        String line;\n        boolean warningPresent = false;\n        boolean defaultedToObserver = false;\n        Pattern pWarn =\n            Pattern.compile(\".*Peer type from servers list.* doesn't match peerType.*\");\n        Pattern pObserve = Pattern.compile(\".*OBSERVING.*\");\n        while ((line = r.readLine()) != null) {\n            if (pWarn.matcher(line).matches()) {\n                warningPresent = true;\n            }\n            if (pObserve.matcher(line).matches()) {\n                defaultedToObserver = true;\n            }\n            if (warningPresent && defaultedToObserver) {\n                break;\n            }\n        }\n        Assert.assertTrue(\"Should warn about inconsistent peer type\",\n                warningPresent && defaultedToObserver);\n    }\n\n    /**\n     * verify if bad packets are being handled properly\n     * at the quorum port\n     * @throws Exception\n     */\n    @Test\n    public void testBadPackets() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();\n        final int CLIENT_PORT_QP2 = PortAssignment.unique();\n        int electionPort1 = PortAssignment.unique();\n        int electionPort2 = PortAssignment.unique();\n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" + electionPort1\n            + \"\\nserver.2=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" +  electionPort2;\n        \n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n        q1.start();\n        q2.start();\n        \n        Assert.assertTrue(\"waiting for server 1 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                        CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"waiting for server 2 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                            CONNECTION_TIMEOUT));\n            \n        byte[] b = new byte[4];\n        int length = 1024*1024*1024;\n        ByteBuffer buff = ByteBuffer.wrap(b);\n        buff.putInt(length);\n        buff.position(0);\n        SocketChannel s = SocketChannel.open(new InetSocketAddress(\"127.0.0.1\", electionPort1));\n        s.write(buff);\n        s.close();\n        buff.position(0);\n        s = SocketChannel.open(new InetSocketAddress(\"127.0.0.1\", electionPort2));\n        s.write(buff);\n        s.close();\n        \n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                ClientBase.CONNECTION_TIMEOUT, this);\n        waitForOne(zk, States.CONNECTED);\n        zk.create(\"/foo_q1\", \"foobar1\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        assertEquals(new String(zk.getData(\"/foo_q1\", null, null)), \"foobar1\");\n        zk.close();\n        q1.shutdown();\n        q2.shutdown();\n    }\n\n\n    /**\n     * Verify handling of quorum defaults\n     * * default electionAlg is fast leader election\n     */\n    @Test\n    public void testQuorumDefaults() throws Exception {\n        ClientBase.setupTestEnv();\n\n        // setup the logger to capture all logs\n        Layout layout =\n            Logger.getRootLogger().getAppender(\"CONSOLE\").getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setImmediateFlush(true);\n        appender.setThreshold(Level.INFO);\n        Logger zlogger = Logger.getLogger(\"org.apache.zookeeper\");\n        zlogger.addAppender(appender);\n\n        try {\n            final int CLIENT_PORT_QP1 = PortAssignment.unique();\n            final int CLIENT_PORT_QP2 = PortAssignment.unique();\n\n            String quorumCfgSection =\n                \"server.1=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique()\n                + \"\\nserver.2=127.0.0.1:\" + PortAssignment.unique()\n                + \":\" + PortAssignment.unique();\n\n            MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n            MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n            q1.start();\n            q2.start();\n\n            Assert.assertTrue(\"waiting for server 1 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 2 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                            CONNECTION_TIMEOUT));\n\n            q1.shutdown();\n            q2.shutdown();\n\n            Assert.assertTrue(\"waiting for server 1 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            ClientBase.CONNECTION_TIMEOUT));\n            Assert.assertTrue(\"waiting for server 2 down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                            ClientBase.CONNECTION_TIMEOUT));\n\n        } finally {\n            zlogger.removeAppender(appender);\n        }\n        os.close();\n        LineNumberReader r = new LineNumberReader(new StringReader(os.toString()));\n        String line;\n        boolean found = false;\n        Pattern p =\n            Pattern.compile(\".*FastLeaderElection.*\");\n        while ((line = r.readLine()) != null) {\n            found = p.matcher(line).matches();\n            if (found) {\n                break;\n            }\n        }\n        Assert.assertTrue(\"fastleaderelection used\", found);\n    }\n\n    /**\n     * Verifies that QuorumPeer exits immediately\n     */\n    @Test\n    public void testQuorumPeerExitTime() throws Exception {\n        long maxwait = 3000;\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();\n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" + PortAssignment.unique()\n            + \"\\nserver.2=127.0.0.1:\" + PortAssignment.unique()\n            + \":\" + PortAssignment.unique();\n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        q1.start();\n        // Let the notifications timeout\n        Thread.sleep(30000);\n        long start = Time.currentElapsedTime();\n        q1.shutdown();\n        long end = Time.currentElapsedTime();\n        if ((end - start) > maxwait) {\n           Assert.fail(\"QuorumPeer took \" + (end -start) +\n                    \" to shutdown, expected \" + maxwait);\n        }\n    }\n\n    static long readLongFromFile(File file) throws IOException {\n        BufferedReader br = new BufferedReader(new FileReader(file));\n        String line = \"\";\n        try {\n            line = br.readLine();\n            return Long.parseLong(line);\n        } catch(NumberFormatException e) {\n            throw new IOException(\"Found \" + line + \" in \" + file);\n        } finally {\n            br.close();\n        }\n    }\n\n    static void writeLongToFile(File file, long value) throws IOException {\n        AtomicFileOutputStream out = new AtomicFileOutputStream(file);\n        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));\n        try {\n            bw.write(Long.toString(value));\n            bw.flush();\n            out.flush();\n            out.close();\n        } catch (IOException e) {\n            LOG.error(\"Failed to write new file \" + file, e);\n            out.abort();\n            throw e;\n        }\n    }\n\n    /**\n     * ZOOKEEPER-1653 Make sure the server starts if the current epoch is less\n     * than the epoch from last logged zxid and updatingEpoch file exists.\n     */\n    @Test\n    public void testUpdatingEpoch() throws Exception {\n        // Create a cluster and restart them multiple times to bump the epoch.\n        numServers = 3;\n        servers = LaunchServers(numServers);\n        File currentEpochFile;\n        for (int i = 0; i < 10; i++) {\n            for (int j = 0; j < numServers; j++) {\n                servers.mt[j].shutdown();\n            }\n            waitForAll(servers.zk, States.CONNECTING);\n            for (int j = 0; j < numServers; j++) {\n                servers.mt[j].start();\n            }\n            waitForAll(servers.zk, States.CONNECTED);\n        }\n\n        // Current epoch is 11 now.\n        for (int i = 0; i < numServers; i++) {\n            currentEpochFile = new File(\n                new File(servers.mt[i].dataDir, \"version-2\"),\n                QuorumPeer.CURRENT_EPOCH_FILENAME);\n            LOG.info(\"Validating current epoch: \" + servers.mt[i].dataDir);\n            assertEquals(\"Current epoch should be 11.\", 11,\n                                readLongFromFile(currentEpochFile));\n        }\n\n        // Find a follower and get epoch from the last logged zxid.\n        int followerIndex = -1;\n        for (int i = 0; i < numServers; i++) {\n            if (servers.mt[i].main.quorumPeer.leader == null) {\n                followerIndex = i;\n                break;\n            }\n        }\n        Assert.assertTrue(\"Found a valid follower\",\n                          followerIndex >= 0 && followerIndex < numServers);\n        MainThread follower = servers.mt[followerIndex];\n        long zxid = follower.main.quorumPeer.getLastLoggedZxid();\n        long epochFromZxid = ZxidUtils.getEpochFromZxid(zxid);\n\n        // Shutdown the cluster\n        for (int i = 0; i < numServers; i++) {\n          servers.mt[i].shutdown();\n        }\n        waitForAll(servers.zk, States.CONNECTING);\n\n        // Make current epoch less than epoch from the last logged zxid.\n        // The server should fail to start.\n        File followerDataDir = new File(follower.dataDir, \"version-2\");\n        currentEpochFile = new File(followerDataDir,\n                QuorumPeer.CURRENT_EPOCH_FILENAME);\n        writeLongToFile(currentEpochFile, epochFromZxid - 1);\n        follower.start();\n        Assert.assertTrue(follower.mainFailed.await(10, TimeUnit.SECONDS));\n\n        // Touch the updateEpoch file. Now the server should start.\n        File updatingEpochFile = new File(followerDataDir,\n                QuorumPeer.UPDATING_EPOCH_FILENAME);\n        updatingEpochFile.createNewFile();\n        for (int i = 0; i < numServers; i++) {\n          servers.mt[i].start();\n        }\n        waitForAll(servers.zk, States.CONNECTED);\n        Assert.assertNotNull(\"Make sure the server started with acceptEpoch\",\n                             follower.main.quorumPeer.getActiveServer());\n        Assert.assertFalse(\"updatingEpoch file should get deleted\",\n                           updatingEpochFile.exists());\n    }\n\n    @Test\n    public void testNewFollowerRestartAfterNewEpoch() throws Exception {\n        numServers = 3;\n\n        servers = LaunchServers(numServers);\n        waitForAll(servers.zk, States.CONNECTED);\n        String inputString = \"test\";\n        byte[] input = inputString.getBytes();\n        byte[] output;\n        String path = \"/newepochzxidtest\";\n\n        // Create a couple of nodes\n        servers.zk[0].create(path, input, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        servers.zk[0].setData(path, input, -1);\n\n        // make sure the updates indeed committed. If it is not\n        // the following statement will throw.\n        output = servers.zk[1].getData(path, false, null);\n\n        // Shutdown every one\n        for (int i=0; i < numServers; i++) {\n            servers.mt[i].shutdown();\n        }\n\n        LOG.info(\"resetting follower\");\n        MainThread follower = servers.mt[0];\n        // delete followers information\n        File followerDataDir = new File(follower.dataDir, \"version-2\");\n        for(File file: followerDataDir.listFiles()) {\n            LOG.info(\"deleting \" + file.getName());\n            file.delete();\n        }\n\n        // Startup everyone except follower, wait for election.\n        for (int i=1; i < numServers; i++) {\n            servers.mt[i].start();\n        }\n        for (int i=1; i < numServers; i++) {\n            waitForOne(servers.zk[i], States.CONNECTED);\n        }\n\n        follower.start();\n        waitForAll(servers.zk, States.CONNECTED); // snapshot should be recieved\n\n        follower.shutdown();\n        follower.start();\n\n        Assert.assertFalse(follower.mainFailed.await(10, TimeUnit.SECONDS));\n        waitForAll(servers.zk, States.CONNECTED);\n    }\n\n    @Test\n    public void testDataDirAndDataLogDir() throws Exception {\n        // Arrange\n        QuorumPeerConfig configMock = mock(QuorumPeerConfig.class);\n        when(configMock.getDataDir()).thenReturn(\"/tmp/zookeeper\");\n        when(configMock.getDataLogDir()).thenReturn(\"/tmp/zookeeperLog\");\n\n        QuorumPeer qpMock = mock(QuorumPeer.class);\n\n        doCallRealMethod().when(qpMock).setTxnFactory(any(FileTxnSnapLog.class));\n        when(qpMock.getTxnFactory()).thenCallRealMethod();\n        InjectableQuorumPeerMain qpMain = new InjectableQuorumPeerMain(qpMock);\n\n        // Act\n        qpMain.runFromConfig(configMock);\n\n        // Assert\n        FileTxnSnapLog txnFactory = qpMain.getQuorumPeer().getTxnFactory();\n        assertEquals(\"/tmp/zookeeperLog/version-2\", txnFactory.getDataDir().getAbsolutePath());\n        assertEquals(\"/tmp/zookeeper/version-2\", txnFactory.getSnapDir().getAbsolutePath());\n    }\n\n    private class InjectableQuorumPeerMain extends QuorumPeerMain {\n        QuorumPeer qp;\n\n        InjectableQuorumPeerMain(QuorumPeer qp) {\n            this.qp = qp;\n        }\n\n        @Override\n        protected QuorumPeer getQuorumPeer() {\n            return qp;\n        }\n    }\n\n    @Test\n    public void testFailedTxnAsPartOfQuorumLoss() throws Exception {\n        final int LEADER_TIMEOUT_MS = 10000;\n        // 1. start up server and wait for leader election to finish\n        ClientBase.setupTestEnv();\n        final int SERVER_COUNT = 3;\n        servers = LaunchServers(SERVER_COUNT);\n\n        waitForAll(servers, States.CONNECTED);\n\n        // we need to shutdown and start back up to make sure that the create session isn't the first transaction since\n        // that is rather innocuous.\n        servers.shutDownAllServers();\n        waitForAll(servers, States.CONNECTING);\n        servers.restartAllServersAndClients(this);\n        waitForAll(servers, States.CONNECTED);\n\n        // 2. kill all followers\n        int leader = servers.findLeader();\n        Map<Long, Proposal> outstanding =  servers.mt[leader].main.quorumPeer.leader.outstandingProposals;\n        // increase the tick time to delay the leader going to looking\n        servers.mt[leader].main.quorumPeer.tickTime = LEADER_TIMEOUT_MS;\n        LOG.warn(\"LEADER \" + leader);\n\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            if (i != leader) {\n                servers.mt[i].shutdown();\n            }\n        }\n\n        // 3. start up the followers to form a new quorum\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            if (i != leader) {\n                servers.mt[i].start();\n            }\n        }\n\n        // 4. wait one of the follower to be the new leader\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            if (i != leader) {\n                // Recreate a client session since the previous session was not persisted.\n                servers.restartClient(i, this);\n                waitForOne(servers.zk[i], States.CONNECTED);\n            }\n        }\n\n        // 5. send a create request to old leader and make sure it's synced to disk,\n        //    which means it acked from itself\n        try {\n            servers.zk[leader].create(\"/zk\" + leader, \"zk\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n            Assert.fail(\"create /zk\" + leader + \" should have failed\");\n        } catch (KeeperException e) {\n        }\n\n        // just make sure that we actually did get it in process at the\n        // leader\n        Assert.assertEquals(1, outstanding.size());\n        Proposal p = outstanding.values().iterator().next();\n        Assert.assertEquals(OpCode.create, p.request.hdr.getType());\n\n        // make sure it has a chance to write it to disk\n        int sleepTime = 0;\n        Long longLeader = new Long(leader);\n        while (!p.ackSet.contains(longLeader)) {\n            if (sleepTime > 2000) {\n                Assert.fail(\"Transaction not synced to disk within 1 second \" + p.ackSet\n                    + \" expected \" + leader);\n            }\n            Thread.sleep(100);\n            sleepTime += 100;\n        }\n\n        // 6. wait for the leader to quit due to not enough followers and come back up as a part of the new quorum\n        LOG.info(\"Waiting for leader \" + leader + \" to timeout followers\");\n        sleepTime = 0;\n        Follower f = servers.mt[leader].main.quorumPeer.follower;\n        while (f == null || !f.isRunning()) {\n            if (sleepTime > LEADER_TIMEOUT_MS * 2) {\n                Assert.fail(\"Took too long for old leader to time out \" + servers.mt[leader].main.quorumPeer.getPeerState());\n            }\n            Thread.sleep(100);\n            sleepTime += 100;\n            f = servers.mt[leader].main.quorumPeer.follower;\n        }\n\n        int newLeader = servers.findLeader();\n        // make sure a different leader was elected\n        Assert.assertTrue(leader != newLeader);\n\n        // 7. restart the previous leader to force it to replay the edits and possibly come up in a bad state\n        servers.mt[leader].shutdown();\n        servers.mt[leader].start();\n        waitForAll(servers, States.CONNECTED);\n\n        // 8. check the node exist in previous leader but not others\n        //    make sure everything is consistent\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            Assert.assertNull(\"server \" + i + \" should not have /zk\" + leader, servers.zk[i].exists(\"/zk\" + leader, false));\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerTestBase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * \n */\npackage org.apache.zookeeper.server.quorum;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.QuorumBase;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Has some common functionality for tests that work with QuorumPeers. Override\n * process(WatchedEvent) to implement the Watcher interface\n */\npublic class QuorumPeerTestBase extends ZKTestCase implements Watcher {\n    protected static final Logger LOG = LoggerFactory\n            .getLogger(QuorumPeerTestBase.class);\n\n    public static final int TIMEOUT = 5000;\n\n    public void process(WatchedEvent event) {\n        // ignore for this test\n    }\n\n    public static class TestQPMain extends QuorumPeerMain {\n        public void shutdown() {\n            // ensure it closes - in particular wait for thread to exit\n            if (quorumPeer != null) {\n                QuorumBase.shutdown(quorumPeer);\n            }\n        }\n    }\n\n    public static class MainThread implements Runnable {\n        final File confFile;\n        volatile TestQPMain main;\n        final File dataDir;\n        CountDownLatch mainFailed;\n        File baseDir;\n        private final int myid;\n        private final int clientPort;\n        private final String quorumCfgSection;\n        private final Map<String, String> otherConfigs;\n\n        /**\n         * Create a MainThread\n         *\n         * @param myid\n         * @param clientPort\n         * @param quorumCfgSection\n         * @param otherConfigs\n         * @param tickTime initLimit will be 10 and syncLimit will be 5\n         * @throws IOException\n         */\n        public MainThread(int myid, int clientPort, String quorumCfgSection,\n                Map<String, String> otherConfigs, int tickTime) throws IOException {\n            baseDir = ClientBase.createTmpDir();\n            this.myid = myid;\n            this.clientPort = clientPort;\n            this.quorumCfgSection = quorumCfgSection;\n            this.otherConfigs = otherConfigs;\n            LOG.info(\"id = \" + myid + \" tmpDir = \" + baseDir + \" clientPort = \"\n                    + clientPort);\n            confFile = new File(baseDir, \"zoo.cfg\");\n\n            FileWriter fwriter = new FileWriter(confFile);\n            fwriter.write(\"tickTime=\" + tickTime + \"\\n\");\n            fwriter.write(\"initLimit=10\\n\");\n            fwriter.write(\"syncLimit=5\\n\");\n\n            dataDir = new File(baseDir, \"data\");\n            if (!dataDir.mkdir()) {\n                throw new IOException(\"Unable to mkdir \" + dataDir);\n            }\n\n            // Convert windows path to UNIX to avoid problems with \"\\\"\n            String dir = dataDir.toString();\n            String osname = java.lang.System.getProperty(\"os.name\");\n            if (osname.toLowerCase().contains(\"windows\")) {\n                dir = dir.replace('\\\\', '/');\n            }\n            fwriter.write(\"dataDir=\" + dir + \"\\n\");\n\n            fwriter.write(\"clientPort=\" + clientPort + \"\\n\");\n\n            // write extra configurations\n            Set<Entry<String, String>> entrySet = otherConfigs.entrySet();\n            for (Entry<String, String> entry : entrySet) {\n                fwriter.write(entry.getKey() + \"=\" + entry.getValue() + \"\\n\");\n            }\n\n            fwriter.write(quorumCfgSection + \"\\n\");\n            fwriter.flush();\n            fwriter.close();\n\n            File myidFile = new File(dataDir, \"myid\");\n            fwriter = new FileWriter(myidFile);\n            fwriter.write(Integer.toString(myid));\n            fwriter.flush();\n            fwriter.close();\n        }\n\n        public MainThread(int myid, int clientPort, String quorumCfgSection)\n                throws IOException {\n            this(myid, clientPort, quorumCfgSection,\n                    new HashMap<String, String>());\n        }\n\n        public MainThread(int myid, int clientPort, String quorumCfgSection,\n                          Map<String, String> otherConfigs) throws IOException {\n            this(myid, clientPort, quorumCfgSection, otherConfigs, 4000);\n        }\n\n        Thread currentThread;\n\n        synchronized public void start() {\n            main = getTestQPMain();\n            currentThread = new Thread(this);\n            currentThread.start();\n            mainFailed = new CountDownLatch(1);\n        }\n\n        public void run() {\n            String args[] = new String[1];\n            args[0] = confFile.toString();\n            try {\n                main.initializeAndRun(args);\n            } catch (Exception e) {\n                // test will still fail even though we just log/ignore\n                LOG.error(\"unexpected exception in run\", e);\n                main.shutdown();\n                mainFailed.countDown();\n            } finally {\n                currentThread = null;\n            }\n        }\n\n        public void shutdown() throws InterruptedException {\n            Thread t = currentThread;\n            if (t != null && t.isAlive()) {\n                main.shutdown();\n                t.join(500);\n            }\n        }\n\n        public void join(long timeout) throws InterruptedException {\n            Thread t = currentThread;\n            if (t != null) {\n                t.join(timeout);\n            }\n        }\n\n        public boolean isAlive() {\n            Thread t = currentThread;\n            return t != null && t.isAlive();\n        }\n\n        public void clean() {\n            ClientBase.recursiveDelete(main.quorumPeer.getTxnFactory()\n                    .getDataDir());\n        }\n\n        public QuorumPeer getQuorumPeer() {\n            return main.quorumPeer;\n        }\n\n        public void deleteBaseDir() {\n            ClientBase.recursiveDelete(baseDir);\n        }\n\n        public int getMyid() {\n            return myid;\n        }\n\n        public int getClientPort() {\n            return clientPort;\n        }\n\n        public String getQuorumCfgSection() {\n            return quorumCfgSection;\n        }\n\n        public Map<String, String> getOtherConfigs() {\n            return otherConfigs;\n        }\n\n        public File getConfFile() {\n            return confFile;\n        }\n\n        public TestQPMain getTestQPMain() {\n            return new TestQPMain();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/WatchLeakTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with this\n * work for additional information regarding copyright ownership. The ASF\n * licenses this file to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\nimport static org.junit.Assert.*;\n\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectableChannel;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.zookeeper.MockPacket;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.proto.ConnectRequest;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.proto.SetWatches;\nimport org.apache.zookeeper.server.MockNIOServerCnxn;\nimport org.apache.zookeeper.server.NIOServerCnxnFactory;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooTrace;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.junit.Test;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Demonstrate ZOOKEEPER-1382 : Watches leak on expired session\n */\npublic class WatchLeakTest {\n\n    protected static final Logger LOG = LoggerFactory\n            .getLogger(WatchLeakTest.class);\n\n    final long SESSION_ID = 0xBABEL;\n\n    /**\n     * ZOOKEEPR-1382 test class\n     */\n    @Test\n    public void testWatchesWithClientSessionTimeout() throws Exception {\n\n        NIOServerCnxnFactory serverCnxnFactory = new NIOServerCnxnFactory();\n\n        ZKDatabase database = new ZKDatabase(null);\n        database.setlastProcessedZxid(2L);\n        QuorumPeer quorumPeer = mock(QuorumPeer.class);\n        FileTxnSnapLog logfactory = mock(FileTxnSnapLog.class);\n        // Directories are not used but we need it to avoid NPE\n        when(logfactory.getDataDir()).thenReturn(new File(\"/tmp\"));\n        when(logfactory.getSnapDir()).thenReturn(new File(\"/tmp\"));\n        FollowerZooKeeperServer fzks = null;\n        try {\n            fzks = new FollowerZooKeeperServer(logfactory, quorumPeer, null,\n                    database);\n            fzks.startup();\n            fzks.setServerCnxnFactory(serverCnxnFactory);\n            quorumPeer.follower = new MyFollower(quorumPeer, fzks);\n            final SelectionKey sk = new FakeSK();\n            // Simulate a socket channel between a client and a follower\n            final SocketChannel socketChannel = createClientSocketChannel();\n            // Create the NIOServerCnxn that will handle the client requests\n            final MockNIOServerCnxn nioCnxn = new MockNIOServerCnxn(fzks,\n                    socketChannel, sk, serverCnxnFactory);\n            // Send the connection request as a client do\n            nioCnxn.doIO(sk);\n            // Send the invalid session packet to the follower\n            QuorumPacket qp = createInvalidSessionPacket();\n            quorumPeer.follower.processPacket(qp);\n            // OK, now the follower knows that the session is invalid, let's try\n            // to\n            // send it the watches\n            nioCnxn.doIO(sk);\n            // wait for the the request processor to do his job\n            Thread.sleep(1000L);\n            // Session has not been re-validated !\n            // If session has not been validated, there must be NO watches\n            int watchCount = database.getDataTree().getWatchCount();\n            LOG.info(\"watches = \" + watchCount);\n            assertEquals(0, watchCount);\n        } finally {\n            if (fzks != null) {\n                fzks.shutdown();\n            }\n        }\n    }\n\n    /**\n     * A follower with no real leader connection\n     */\n    public static class MyFollower extends Follower {\n        /**\n         * Create a follower with a mocked leader connection\n         * \n         * @param self\n         * @param zk\n         */\n        MyFollower(QuorumPeer self, FollowerZooKeeperServer zk) {\n            super(self, zk);\n            leaderOs = mock(OutputArchive.class);\n            leaderIs = mock(InputArchive.class);\n            bufferedOutput = mock(BufferedOutputStream.class);\n        }\n    }\n\n    /**\n     * Simulate the behavior of a real selection key\n     */\n    private static class FakeSK extends SelectionKey {\n\n        @Override\n        public SelectableChannel channel() {\n            return null;\n        }\n\n        @Override\n        public Selector selector() {\n            return mock(Selector.class);\n        }\n\n        @Override\n        public boolean isValid() {\n            return true;\n        }\n\n        @Override\n        public void cancel() {\n        }\n\n        @Override\n        public int interestOps() {\n            return ops;\n        }\n\n        private int ops = OP_WRITE + OP_READ;\n\n        @Override\n        public SelectionKey interestOps(int ops) {\n            this.ops = ops;\n            return this;\n        }\n\n        @Override\n        public int readyOps() {\n            return ops;\n        }\n\n    }\n\n    /**\n     * Create a watches message with a single watch on /\n     * \n     * @return\n     */\n    private ByteBuffer createWatchesMessage() {\n        List<String> dataWatches = new ArrayList<String>(1);\n        dataWatches.add(\"/\");\n        List<String> existWatches = Collections.emptyList();\n        List<String> childWatches = Collections.emptyList();\n        SetWatches sw = new SetWatches(1L, dataWatches, existWatches,\n                childWatches);\n        RequestHeader h = new RequestHeader();\n        h.setType(ZooDefs.OpCode.setWatches);\n        h.setXid(-8);\n        MockPacket p = new MockPacket(h, new ReplyHeader(), sw, null, null);\n        return p.createAndReturnBB();\n    }\n\n    /**\n     * This is the secret that we use to generate passwords, for the moment it\n     * is more of a sanity check.\n     */\n    static final private long superSecret = 0XB3415C00L;\n\n    /**\n     * Create a connection request\n     * \n     * @return\n     */\n    private ByteBuffer createConnRequest() {\n        Random r = new Random(SESSION_ID ^ superSecret);\n        byte p[] = new byte[16];\n        r.nextBytes(p);\n        ConnectRequest conReq = new ConnectRequest(0, 1L, 30000, SESSION_ID, p);\n        MockPacket packet = new MockPacket(null, null, conReq, null, null, false);\n        return packet.createAndReturnBB();\n    }\n\n    /**\n     * Mock a client channel with a connection request and a watches message\n     * inside.\n     * \n     * @return a socket channel\n     * @throws IOException\n     */\n    private SocketChannel createClientSocketChannel() throws IOException {\n\n        SocketChannel socketChannel = mock(SocketChannel.class);\n        Socket socket = mock(Socket.class);\n        InetSocketAddress socketAddress = new InetSocketAddress(1234);\n        when(socket.getRemoteSocketAddress()).thenReturn(socketAddress);\n        when(socketChannel.socket()).thenReturn(socket);\n\n        // Send watches packet to server connection\n        final ByteBuffer connRequest = createConnRequest();\n        final ByteBuffer watchesMessage = createWatchesMessage();\n        final ByteBuffer request = ByteBuffer.allocate(connRequest.limit()\n                + watchesMessage.limit());\n        request.put(connRequest);\n        request.put(watchesMessage);\n\n        Answer<Integer> answer = new Answer<Integer>() {\n            int i = 0;\n\n            @Override\n            public Integer answer(InvocationOnMock invocation) throws Throwable {\n                Object[] args = invocation.getArguments();\n                ByteBuffer bb = (ByteBuffer) args[0];\n                for (int k = 0; k < bb.limit(); k++) {\n                    bb.put(request.get(i));\n                    i = i + 1;\n                }\n                return bb.limit();\n            }\n        };\n        when(socketChannel.read(any(ByteBuffer.class))).thenAnswer(answer);\n        return socketChannel;\n    }\n\n    /**\n     * Forge an invalid session packet as a LEADER do\n     * \n     * @throws Exception\n     */\n    private QuorumPacket createInvalidSessionPacket() throws Exception {\n        QuorumPacket qp = createValidateSessionQuorumPacket();\n        ByteArrayInputStream bis = new ByteArrayInputStream(qp.getData());\n        DataInputStream dis = new DataInputStream(bis);\n        long id = dis.readLong();\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        DataOutputStream dos = new DataOutputStream(bos);\n        dos.writeLong(id);\n        // false means that the session has expired\n        dos.writeBoolean(false);\n        qp.setData(bos.toByteArray());\n        return qp;\n    }\n\n    /**\n     * Forge an validate session packet as a LEARNER do\n     * \n     * @return\n     * @throws Exception\n     */\n    private QuorumPacket createValidateSessionQuorumPacket() throws Exception {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        DataOutputStream dos = new DataOutputStream(baos);\n        dos.writeLong(SESSION_ID);\n        dos.writeInt(3000);\n        dos.close();\n        QuorumPacket qp = new QuorumPacket(Leader.REVALIDATE, -1,\n                baos.toByteArray(), null);\n        if (LOG.isTraceEnabled()) {\n            ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,\n                    \"To validate session 0x\" + Long.toHexString(2L));\n        }\n        return qp;\n    }\n\n}"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/Zab1_0Test.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.verify;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.EOFException;\nimport java.lang.reflect.Field;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.InputArchive;\nimport org.apache.jute.OutputArchive;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ByteBufferInputStream;\nimport org.apache.zookeeper.server.ByteBufferOutputStream;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.ZooKeeperServer.DataTreeBuilder;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.Util;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumMaj;\nimport org.apache.zookeeper.server.util.ZxidUtils;\nimport org.apache.zookeeper.txn.CreateSessionTxn;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.ErrorTxn;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Zab1_0Test {\n    private static final int SYNC_LIMIT = 2;\n\n    private static final Logger LOG = LoggerFactory.getLogger(Zab1_0Test.class);\n\n    private static final File testData = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"));\n\n    private static final class LeadThread extends Thread {\n        private final Leader leader;\n\n        private LeadThread(Leader leader) {\n            this.leader = leader;\n        }\n\n        public void run() {\n            try {\n                leader.lead();\n            } catch (InterruptedException e) {\n                LOG.info(\"Leader thread interrupted\", e);\n            } catch (Exception e) {\n                LOG.warn(\"Unexpected exception in leader thread\", e);\n            } finally {\n                leader.shutdown(\"lead ended\");\n            }\n        }\n    }\n           \n    private static final class MockLeader extends Leader {\n           \n        MockLeader(QuorumPeer qp, LeaderZooKeeperServer zk)\n        throws IOException {\n            super(qp, zk);\n        }\n           \n        /**\n         * This method returns the value of the variable that holds the epoch\n         * to be proposed and that has been proposed, depending on the point\n         * of the execution in which it is called. \n         * \n         * @return epoch\n         */\n        public long getCurrentEpochToPropose() {\n            return epoch;\n        }\n    }\n     \n   public static final class FollowerMockThread extends Thread {\n    \tprivate final Leader leader;\n    \tprivate final long followerSid;\n    \tpublic long epoch = -1;\n    \tpublic String msg = null;\n    \tprivate boolean onlyGetEpochToPropose;\n    \t\n    \tprivate FollowerMockThread(long followerSid, Leader leader, boolean onlyGetEpochToPropose) {\n            this.leader = leader;\n            this.followerSid = followerSid;\n            this.onlyGetEpochToPropose = onlyGetEpochToPropose;\n        }\n\n        public void run() {\n            if (onlyGetEpochToPropose) {\n\t            try {\n\t            \tepoch = leader.getEpochToPropose(followerSid, 0);\n\t            } catch (Exception e) {\n\t            }\n            } else {\t            \n\t            try{\n\t                leader.waitForEpochAck(followerSid, new StateSummary(0, 0)); \n\t                msg = \"FollowerMockThread (id = \" + followerSid + \")  returned from waitForEpochAck\";      \n\t            } catch (Exception e) {\t            \t\n\t            }\n            }\n        }       \n    }\n    @Test\n    public void testLeaderInConnectingFollowers() throws Exception {    \n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        try {\n            QuorumPeer peer = createQuorumPeer(tmpDir);\n            leader = createLeader(tmpDir, peer);\n            peer.leader = leader;\n            peer.setAcceptedEpoch(5);\n            \n            FollowerMockThread f1 = new FollowerMockThread(1, leader, true);\n            FollowerMockThread f2 = new FollowerMockThread(2, leader, true);\n            f1.start();\n            f2.start();\n            \n            // wait until followers time out in getEpochToPropose - they shouldn't return\n            // normally because the leader didn't execute getEpochToPropose and so its epoch was not\n            // accounted for\n            f1.join(leader.self.getInitLimit()*leader.self.getTickTime() + 5000);\n            f2.join(leader.self.getInitLimit()*leader.self.getTickTime() + 5000);\n                \n            // even though followers timed out, their ids are in connectingFollowers, and their\n            // epoch were accounted for, so the leader should not block and since it started with \n            // accepted epoch = 5 it should now have 6\n            try {\n            \tlong epoch = leader.getEpochToPropose(leader.self.getId(), leader.self.getAcceptedEpoch());\n            \tAssert.assertEquals(\"leader got wrong epoch from getEpochToPropose\", 6, epoch);\t\n            } catch (Exception e){ \n            \tAssert.fail(\"leader timed out in getEpochToPropose\");\n            }\n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n    \n    /**\n     * In this test, the leader sets the last accepted epoch to 5. The call\n     * to getEpochToPropose should set epoch to 6 and wait until another \n     * follower executes it. If in getEpochToPropose we don't check if\n     * lastAcceptedEpoch == epoch, then the call from the subsequent\n     * follower with lastAcceptedEpoch = 6 doesn't change the value\n     * of epoch, and the test fails. It passes with the fix to predicate.\n     * \n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1343}\n     * \n     * \n     * @throws Exception\n     */\n        \n    @Test\n    public void testLastAcceptedEpoch() throws Exception {    \n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        LeadThread leadThread = null;\n        try {\n            QuorumPeer peer = createQuorumPeer(tmpDir);\n            leader = createMockLeader(tmpDir, peer);\n            peer.leader = leader;\n            peer.setAcceptedEpoch(5);\n            leadThread = new LeadThread(leader); \n            leadThread.start();\n            \n            while(((MockLeader) leader).getCurrentEpochToPropose() != 6){\n                Thread.sleep(20);\n            }\n                \n            try {\n                long epoch = leader.getEpochToPropose(1, 6);\n                Assert.assertEquals(\"New proposed epoch is wrong\", 7, epoch);  \n            } catch (Exception e){ \n                Assert.fail(\"Timed out in getEpochToPropose\");\n            }\n            \n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            if (leadThread != null) {\n                leadThread.interrupt();\n                leadThread.join();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n        \n    @Test\n    public void testLeaderInElectingFollowers() throws Exception {    \n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Leader leader = null;\n        try {\n            QuorumPeer peer = createQuorumPeer(tmpDir);\n            leader = createLeader(tmpDir, peer);\n            peer.leader = leader;            \n            \n            FollowerMockThread f1 = new FollowerMockThread(1, leader, false);\n            FollowerMockThread f2 = new FollowerMockThread(2, leader, false);\n\n            // things needed for waitForEpochAck to run (usually in leader.lead(), but we're not running leader here)\n            leader.readyToStart = true;\n            leader.leaderStateSummary = new StateSummary(leader.self.getCurrentEpoch(), leader.zk.getLastProcessedZxid());\n            \n            f1.start();\n            f2.start();         \n            \n            // wait until followers time out in waitForEpochAck - they shouldn't return\n            // normally because the leader didn't execute waitForEpochAck\n            f1.join(leader.self.getInitLimit()*leader.self.getTickTime() + 5000);\n            f2.join(leader.self.getInitLimit()*leader.self.getTickTime() + 5000);\n                        \n            // make sure that they timed out and didn't return normally  \n            Assert.assertTrue(f1.msg + \" without waiting for leader\", f1.msg == null);            \n            Assert.assertTrue(f2.msg + \" without waiting for leader\", f2.msg == null);\n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n\n    private static final class NullServerCnxnFactory extends ServerCnxnFactory {\n        public void startup(ZooKeeperServer zkServer) throws IOException,\n                InterruptedException {\n        }\n        public void start() {\n        }\n        public void shutdown() {\n        }\n        public void setMaxClientCnxnsPerHost(int max) {\n        }\n        public void join() throws InterruptedException {\n        }\n        public int getMaxClientCnxnsPerHost() {\n            return 0;\n        }\n        public int getLocalPort() {\n            return 0;\n        }\n        public InetSocketAddress getLocalAddress() {\n            return null;\n        }\n        public Iterable<ServerCnxn> getConnections() {\n            return null;\n        }\n        public void configure(InetSocketAddress addr, int maxClientCnxns)\n                throws IOException {\n        }\n        public void closeSession(long sessionId) {\n        }\n        public void closeAll() {\n        }\n        @Override\n        public int getNumAliveConnections() {\n            return 0;\n        }\n    }\n    static Socket[] getSocketPair() throws IOException {\n        ServerSocket ss = new ServerSocket();\n        ss.bind(null);\n        InetSocketAddress endPoint = (InetSocketAddress) ss.getLocalSocketAddress();\n        Socket s = new Socket(endPoint.getAddress(), endPoint.getPort());\n        return new Socket[] { s, ss.accept() };\n    }\n    static void readPacketSkippingPing(InputArchive ia, QuorumPacket qp) throws IOException {\n        while(true) {\n            ia.readRecord(qp, null);\n            if (qp.getType() != Leader.PING) {\n                return;\n            }\n        }\n    }\n    \n    static public interface LeaderConversation {\n        void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l) throws Exception;\n    }\n    \n    static public interface PopulatedLeaderConversation {\n        void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l, long zxid) throws Exception;\n    }\n    \n    static public interface FollowerConversation {\n        void converseWithFollower(InputArchive ia, OutputArchive oa, Follower f) throws Exception;\n    }\n    \n    static public interface ObserverConversation {\n        void converseWithObserver(InputArchive ia, OutputArchive oa, Observer o) throws Exception;\n    }\n\n    public void testLeaderConversation(LeaderConversation conversation) throws Exception {\n        Socket pair[] = getSocketPair();\n        Socket leaderSocket = pair[0];\n        Socket followerSocket = pair[1];\n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        LeadThread leadThread = null;\n        Leader leader = null;\n        try {\n            QuorumPeer peer = createQuorumPeer(tmpDir);\n            leader = createLeader(tmpDir, peer);\n            peer.leader = leader;\n            leadThread = new LeadThread(leader);\n            leadThread.start();\n\n            while(!leader.readyToStart) {\n                Thread.sleep(20);\n            }\n            \n            LearnerHandler lh = new LearnerHandler(leaderSocket,\n                    new BufferedInputStream(leaderSocket.getInputStream()),\n                    leader);\n            lh.start();\n            leaderSocket.setSoTimeout(4000);\n\n            InputArchive ia = BinaryInputArchive.getArchive(followerSocket\n                    .getInputStream());\n            OutputArchive oa = BinaryOutputArchive.getArchive(followerSocket\n                    .getOutputStream());\n\n            conversation.converseWithLeader(ia, oa, leader);\n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            if (leadThread != null) {\n                leadThread.interrupt();\n                leadThread.join();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n    \n    public void testPopulatedLeaderConversation(PopulatedLeaderConversation conversation, int ops) throws Exception {\n        Socket pair[] = getSocketPair();\n        Socket leaderSocket = pair[0];\n        Socket followerSocket = pair[1];\n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        LeadThread leadThread = null;\n        Leader leader = null;\n        try {              \n            // Setup a database with two znodes\n            FileTxnSnapLog snapLog = new FileTxnSnapLog(tmpDir, tmpDir);\n            ZKDatabase zkDb = new ZKDatabase(snapLog);\n            \n            Assert.assertTrue(ops >= 1);\n            long zxid = ZxidUtils.makeZxid(1, 0);            \n            for(int i = 1; i <= ops; i++){\n                zxid = ZxidUtils.makeZxid(1, i);\n                String path = \"/foo-\"+ i;\n                zkDb.processTxn(new TxnHeader(13,1000+i,zxid,30+i,ZooDefs.OpCode.create), \n                                                new CreateTxn(path, \"fpjwasalsohere\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 1));\n                Stat stat = new Stat();\n                Assert.assertEquals(\"fpjwasalsohere\", new String(zkDb.getData(path, stat, null)));\n            }                \n            Assert.assertTrue(zxid > ZxidUtils.makeZxid(1, 0));\n            \n            // Generate snapshot and close files.\n            snapLog.save(zkDb.getDataTree(), zkDb.getSessionWithTimeOuts());\n            snapLog.close();\n            \n            QuorumPeer peer = createQuorumPeer(tmpDir);\n                        \n            leader = createLeader(tmpDir, peer);\n            peer.leader = leader;\n            \n            // Set the last accepted epoch and current epochs to be 1\n            peer.setAcceptedEpoch(1);\n            peer.setCurrentEpoch(1);\n\n            \n            leadThread = new LeadThread(leader);\n            leadThread.start();\n\n            while(leader.cnxAcceptor == null || !leader.cnxAcceptor.isAlive()) {\n                Thread.sleep(20);\n            }\n\n            LearnerHandler lh = new LearnerHandler(leaderSocket,\n                    new BufferedInputStream(leaderSocket.getInputStream()),\n                    leader);\n            lh.start();\n            leaderSocket.setSoTimeout(4000);\n\n            InputArchive ia = BinaryInputArchive.getArchive(followerSocket\n                    .getInputStream());\n            OutputArchive oa = BinaryOutputArchive.getArchive(followerSocket\n                    .getOutputStream());\n\n            conversation.converseWithLeader(ia, oa, leader, zxid);\n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            if (leadThread != null) {\n                leadThread.interrupt();\n                leadThread.join();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n    \n    public void testFollowerConversation(FollowerConversation conversation) throws Exception {\n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Thread followerThread = null;\n        ConversableFollower follower = null;\n        QuorumPeer peer = null;\n        try {\n            peer = createQuorumPeer(tmpDir);\n            follower = createFollower(tmpDir, peer);\n            peer.follower = follower;\n            \n            ServerSocket ss = new ServerSocket();\n            ss.bind(null);\n            QuorumServer leaderQS = new QuorumServer(1,\n                    (InetSocketAddress) ss.getLocalSocketAddress());\n            follower.setLeaderQuorumServer(leaderQS);\n            final Follower followerForThread = follower;\n            \n            followerThread = new Thread() {\n                public void run() {\n                    try {\n                        followerForThread.followLeader();\n                    } catch (InterruptedException e) {\n                        LOG.info(\"Follower thread interrupted\", e);\n                    } catch (Exception e) {\n                        LOG.warn(\"Unexpected exception in follower thread\", e);\n                    }\n                }\n            };\n            followerThread.start();\n            Socket leaderSocket = ss.accept();\n            \n            InputArchive ia = BinaryInputArchive.getArchive(leaderSocket\n                    .getInputStream());\n            OutputArchive oa = BinaryOutputArchive.getArchive(leaderSocket\n                    .getOutputStream());\n\n            conversation.converseWithFollower(ia, oa, follower);\n        } finally {\n            if (follower != null) {\n                follower.shutdown();\n            }\n            if (followerThread != null) {\n                followerThread.interrupt();\n                followerThread.join();\n            }\n            if (peer != null) {\n                peer.shutdown();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n\n    public void testObserverConversation(ObserverConversation conversation) throws Exception {\n        File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        Thread observerThread = null;\n        ConversableObserver observer = null;\n        QuorumPeer peer = null;\n        try {\n            peer = createQuorumPeer(tmpDir);\n            peer.setSyncEnabled(true);\n            observer = createObserver(tmpDir, peer);\n            peer.observer = observer;\n\n            ServerSocket ss = new ServerSocket();\n            ss.bind(null);\n            QuorumServer leaderQS = new QuorumServer(1,\n                    (InetSocketAddress) ss.getLocalSocketAddress());\n            observer.setLeaderQuorumServer(leaderQS);\n            final Observer observerForThread = observer;\n\n            observerThread = new Thread() {\n                public void run() {\n                    try {\n                        observerForThread.observeLeader();\n                    } catch(Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            };\n            observerThread.start();\n            Socket leaderSocket = ss.accept();\n\n            InputArchive ia = BinaryInputArchive.getArchive(leaderSocket\n                    .getInputStream());\n            OutputArchive oa = BinaryOutputArchive.getArchive(leaderSocket\n                    .getOutputStream());\n\n            conversation.converseWithObserver(ia, oa, observer);\n        } finally {\n            if (observer != null) {\n                observer.shutdown();\n            }\n            if (observerThread != null) {\n                observerThread.interrupt();\n                observerThread.join();\n            }\n            if (peer != null) {\n                peer.shutdown();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n\n    @Test\n    public void testUnnecessarySnap() throws Exception {\n        testPopulatedLeaderConversation(new PopulatedLeaderConversation() {\n           @Override\n           public void converseWithLeader(InputArchive ia, OutputArchive oa,\n                    Leader l, long zxid) throws Exception {\n               \n               Assert.assertEquals(1, l.self.getAcceptedEpoch());\n               Assert.assertEquals(1, l.self.getCurrentEpoch());\n               \n               /* we test a normal run. everything should work out well. */\n               LearnerInfo li = new LearnerInfo(1, 0x10000);\n               byte liBytes[] = new byte[12];\n               ByteBufferOutputStream.record2ByteBuffer(li,\n                       ByteBuffer.wrap(liBytes));\n               QuorumPacket qp = new QuorumPacket(Leader.FOLLOWERINFO, 1,\n                       liBytes, null);\n               oa.writeRecord(qp, null);\n               \n               readPacketSkippingPing(ia, qp);\n               Assert.assertEquals(Leader.LEADERINFO, qp.getType());\n               Assert.assertEquals(ZxidUtils.makeZxid(2, 0), qp.getZxid());\n               Assert.assertEquals(ByteBuffer.wrap(qp.getData()).getInt(),\n                       0x10000);\n               Assert.assertEquals(2, l.self.getAcceptedEpoch());\n               Assert.assertEquals(1, l.self.getCurrentEpoch());\n               \n               byte epochBytes[] = new byte[4];\n               final ByteBuffer wrappedEpochBytes = ByteBuffer.wrap(epochBytes);\n               wrappedEpochBytes.putInt(1);\n               qp = new QuorumPacket(Leader.ACKEPOCH, zxid, epochBytes, null);\n               oa.writeRecord(qp, null);\n               \n               readPacketSkippingPing(ia, qp);\n               Assert.assertEquals(Leader.DIFF, qp.getType());\n           \n           }\n       }, 2);\n    }\n\n    // We want to track the change with a callback rather than depending on timing\n    class TrackerWatcher implements Watcher {\n        boolean changed;\n        synchronized void waitForChange() throws InterruptedException {\n            while(!changed) {\n                wait();\n            }\n        }\n\n        @Override\n        public void process(WatchedEvent event) {\n            if (event.getType() == EventType.NodeDataChanged) {\n                synchronized(this) {\n                    changed = true;\n                    notifyAll();\n                }\n            }\n        }\n        synchronized public boolean changed() {\n            return changed;\n        } \n    };\n\n\n    @Test\n    public void testNormalFollowerRun() throws Exception {\n        testFollowerConversation(new FollowerConversation() {\n            @Override\n            public void converseWithFollower(InputArchive ia, OutputArchive oa,\n                    Follower f) throws Exception {\n                File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n                tmpDir.delete();\n                tmpDir.mkdir();\n                File logDir = f.fzk.getTxnLogFactory().getDataDir().getParentFile();\n                File snapDir = f.fzk.getTxnLogFactory().getSnapDir().getParentFile();\n                //Spy on ZK so we can check if a snapshot happened or not.\n                f.zk = spy(f.zk);\n                try {\n                    Assert.assertEquals(0, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, f.self.getCurrentEpoch());\n\n                    // Setup a database with a single /foo node\n                    ZKDatabase zkDb = new ZKDatabase(new FileTxnSnapLog(tmpDir, tmpDir));\n                    final long firstZxid = ZxidUtils.makeZxid(1, 1);\n                    zkDb.processTxn(new TxnHeader(13, 1313, firstZxid, 33, ZooDefs.OpCode.create), new CreateTxn(\"/foo\", \"data1\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 1));\n                    Stat stat = new Stat();\n                    Assert.assertEquals(\"data1\", new String(zkDb.getData(\"/foo\", stat, null)));\n\n                    QuorumPacket qp = new QuorumPacket();\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.FOLLOWERINFO, qp.getType());\n                    Assert.assertEquals(qp.getZxid(), 0);\n                    LearnerInfo learnInfo = new LearnerInfo();\n                    ByteBufferInputStream.byteBuffer2Record(ByteBuffer.wrap(qp.getData()), learnInfo);\n                    Assert.assertEquals(learnInfo.getProtocolVersion(), 0x10000);\n                    Assert.assertEquals(learnInfo.getServerid(), 0);\n                \n                    // We are simulating an established leader, so the epoch is 1\n                    qp.setType(Leader.LEADERINFO);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    byte protoBytes[] = new byte[4];\n                    ByteBuffer.wrap(protoBytes).putInt(0x10000);\n                    qp.setData(protoBytes);\n                    oa.writeRecord(qp, null);\n                \n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACKEPOCH, qp.getType());\n                    Assert.assertEquals(0, qp.getZxid());\n                    Assert.assertEquals(ZxidUtils.makeZxid(0, 0), ByteBuffer.wrap(qp.getData()).getInt());\n                    Assert.assertEquals(1, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, f.self.getCurrentEpoch());\n                    \n                    // Send the snapshot we created earlier\n                    qp.setType(Leader.SNAP);\n                    qp.setData(new byte[0]);\n                    qp.setZxid(zkDb.getDataTreeLastProcessedZxid());\n                    oa.writeRecord(qp, null);\n                    zkDb.serializeSnapshot(oa);\n                    oa.writeString(\"BenWasHere\", null);\n                    Thread.sleep(10); //Give it some time to process the snap\n                    //No Snapshot taken yet, the SNAP was applied in memory\n                    verify(f.zk, never()).takeSnapshot();\n\n                    qp.setType(Leader.NEWLEADER);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    oa.writeRecord(qp, null);\n\n                    // Get the ack of the new leader\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                    Assert.assertEquals(1, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(1, f.self.getCurrentEpoch());\n                    //Make sure that we did take the snapshot now\n                    verify(f.zk).takeSnapshot();\n                    Assert.assertEquals(firstZxid, f.fzk.getLastProcessedZxid());\n                    \n                    // Make sure the data was recorded in the filesystem ok\n                    ZKDatabase zkDb2 = new ZKDatabase(new FileTxnSnapLog(logDir, snapDir));\n                    long lastZxid = zkDb2.loadDataBase();\n                    Assert.assertEquals(\"data1\", new String(zkDb2.getData(\"/foo\", stat, null)));\n                    Assert.assertEquals(firstZxid, lastZxid);\n\n                    // Propose an update\n                    long proposalZxid = ZxidUtils.makeZxid(1, 1000);\n                    proposeSetData(qp, proposalZxid, \"data2\", 2);\n                    oa.writeRecord(qp, null);\n                    \n                    TrackerWatcher watcher = new TrackerWatcher();\n                    \n                    // The change should not have happened yet, since we haven't committed\n                    Assert.assertEquals(\"data1\", new String(f.fzk.getZKDatabase().getData(\"/foo\", stat, watcher)));\n                    \n                    // The change should happen now\n                    qp.setType(Leader.COMMIT);\n                    qp.setZxid(proposalZxid);\n                    oa.writeRecord(qp, null);\n                    \n                    qp.setType(Leader.UPTODATE);\n                    qp.setZxid(0);\n                    oa.writeRecord(qp, null);\n                    \n                    // Read the uptodate ack\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                    \n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(proposalZxid, qp.getZxid());\n                    \n                    watcher.waitForChange();\n                    Assert.assertEquals(\"data2\", new String(f.fzk.getZKDatabase().getData(\"/foo\", stat, null)));\n                    \n                    // check and make sure the change is persisted\n                    zkDb2 = new ZKDatabase(new FileTxnSnapLog(logDir, snapDir));\n                    lastZxid = zkDb2.loadDataBase();\n                    Assert.assertEquals(\"data2\", new String(zkDb2.getData(\"/foo\", stat, null)));\n                    Assert.assertEquals(proposalZxid, lastZxid);\n                } finally {\n                    recursiveDelete(tmpDir);\n                }\n                \n            }\n\n            private void proposeSetData(QuorumPacket qp, long zxid, String data, int version) throws IOException {\n                qp.setType(Leader.PROPOSAL);\n                qp.setZxid(zxid);\n                TxnHeader hdr = new TxnHeader(4, 1414, qp.getZxid(), 55, ZooDefs.OpCode.setData);\n                SetDataTxn sdt = new SetDataTxn(\"/foo\", data.getBytes(), version);\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                OutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeRecord(hdr, null);\n                boa.writeRecord(sdt, null);\n                qp.setData(baos.toByteArray());\n            }\n        });\n    }\n    \n    @Test\n    public void testNormalFollowerRunWithDiff() throws Exception {\n        testFollowerConversation(new FollowerConversation() {\n            @Override\n            public void converseWithFollower(InputArchive ia, OutputArchive oa,\n                    Follower f) throws Exception {\n                File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n                tmpDir.delete();\n                tmpDir.mkdir();\n                File logDir = f.fzk.getTxnLogFactory().getDataDir().getParentFile();\n                File snapDir = f.fzk.getTxnLogFactory().getSnapDir().getParentFile();\n                //Spy on ZK so we can check if a snapshot happened or not.\n                f.zk = spy(f.zk);\n                try {\n                    Assert.assertEquals(0, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, f.self.getCurrentEpoch());\n\n                    // Setup a database with a single /foo node\n                    ZKDatabase zkDb = new ZKDatabase(new FileTxnSnapLog(tmpDir, tmpDir));\n                    final long firstZxid = ZxidUtils.makeZxid(1, 1);\n                    zkDb.processTxn(new TxnHeader(13, 1313, firstZxid, 33, ZooDefs.OpCode.create), new CreateTxn(\"/foo\", \"data1\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 1));\n                    Stat stat = new Stat();\n                    Assert.assertEquals(\"data1\", new String(zkDb.getData(\"/foo\", stat, null)));\n\n                    QuorumPacket qp = new QuorumPacket();\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.FOLLOWERINFO, qp.getType());\n                    Assert.assertEquals(qp.getZxid(), 0);\n                    LearnerInfo learnInfo = new LearnerInfo();\n                    ByteBufferInputStream.byteBuffer2Record(ByteBuffer.wrap(qp.getData()), learnInfo);\n                    Assert.assertEquals(learnInfo.getProtocolVersion(), 0x10000);\n                    Assert.assertEquals(learnInfo.getServerid(), 0);\n                \n                    // We are simulating an established leader, so the epoch is 1\n                    qp.setType(Leader.LEADERINFO);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    byte protoBytes[] = new byte[4];\n                    ByteBuffer.wrap(protoBytes).putInt(0x10000);\n                    qp.setData(protoBytes);\n                    oa.writeRecord(qp, null);\n                \n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACKEPOCH, qp.getType());\n                    Assert.assertEquals(0, qp.getZxid());\n                    Assert.assertEquals(ZxidUtils.makeZxid(0, 0), ByteBuffer.wrap(qp.getData()).getInt());\n                    Assert.assertEquals(1, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, f.self.getCurrentEpoch());\n                    \n                    // Send a diff\n                    qp.setType(Leader.DIFF);\n                    qp.setData(new byte[0]);\n                    qp.setZxid(zkDb.getDataTreeLastProcessedZxid());\n                    oa.writeRecord(qp, null);\n                    final long createSessionZxid = ZxidUtils.makeZxid(1, 2);\n                    proposeNewSession(qp, createSessionZxid, 0x333);\n                    oa.writeRecord(qp, null);\n                    qp.setType(Leader.COMMIT);\n                    qp.setZxid(createSessionZxid);\n                    oa.writeRecord(qp, null);\n                    qp.setType(Leader.NEWLEADER);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    oa.writeRecord(qp, null);\n                    qp.setType(Leader.UPTODATE);\n                    qp.setZxid(0);\n                    oa.writeRecord(qp, null);\n                    \n                    // Read the uptodate ack\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                    \n                  \n                    // Get the ack of the new leader\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                    Assert.assertEquals(1, f.self.getAcceptedEpoch());\n                    Assert.assertEquals(1, f.self.getCurrentEpoch());\n                    \n                    //Wait for the transactions to be written out. The thread that writes them out\n                    // does not send anything back when it is done.\n                    long start = System.currentTimeMillis();\n                    while (createSessionZxid != f.fzk.getLastProcessedZxid() && (System.currentTimeMillis() - start) < 50) {\n                        Thread.sleep(1);\n                    }\n                    \n                    Assert.assertEquals(createSessionZxid, f.fzk.getLastProcessedZxid());\n                    \n                    // Make sure the data was recorded in the filesystem ok\n                    ZKDatabase zkDb2 = new ZKDatabase(new FileTxnSnapLog(logDir, snapDir));\n                    start = System.currentTimeMillis();\n                    zkDb2.loadDataBase();\n                    while (zkDb2.getSessionWithTimeOuts().isEmpty() && (System.currentTimeMillis() - start) < 50) {\n                        Thread.sleep(1);\n                        zkDb2.loadDataBase();\n                    }\n                    LOG.info(\"zkdb2 sessions:\" + zkDb2.getSessions());\n                    LOG.info(\"zkdb2 with timeouts:\" + zkDb2.getSessionWithTimeOuts());\n                    Assert.assertNotNull(zkDb2.getSessionWithTimeOuts().get(4L));\n                    //Snapshot was never taken during very simple sync\n                    verify(f.zk, never()).takeSnapshot();\n                } finally {\n                    recursiveDelete(tmpDir);\n                }\n                \n            }\n\n            private void proposeNewSession(QuorumPacket qp, long zxid, long sessionId) throws IOException {\n                qp.setType(Leader.PROPOSAL);\n                qp.setZxid(zxid);\n                TxnHeader hdr = new TxnHeader(4, 1414, qp.getZxid(), 55, ZooDefs.OpCode.createSession);\n                CreateSessionTxn cst = new CreateSessionTxn(30000);\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                OutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeRecord(hdr, null);\n                boa.writeRecord(cst, null);\n                qp.setData(baos.toByteArray());\n            }\n        });\n    }\n    \n    @Test\n    public void testNormalRun() throws Exception {\n        testLeaderConversation(new LeaderConversation() {\n            public void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l)\n                    throws IOException {\n                Assert.assertEquals(0, l.self.getAcceptedEpoch());\n                Assert.assertEquals(0, l.self.getCurrentEpoch());\n                \n                /* we test a normal run. everything should work out well. */\n                LearnerInfo li = new LearnerInfo(1, 0x10000);\n                byte liBytes[] = new byte[12];\n                ByteBufferOutputStream.record2ByteBuffer(li,\n                        ByteBuffer.wrap(liBytes));\n                QuorumPacket qp = new QuorumPacket(Leader.FOLLOWERINFO, 0,\n                        liBytes, null);\n                oa.writeRecord(qp, null);\n                \n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.LEADERINFO, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                Assert.assertEquals(ByteBuffer.wrap(qp.getData()).getInt(),\n                        0x10000);\n                Assert.assertEquals(1, l.self.getAcceptedEpoch());\n                Assert.assertEquals(0, l.self.getCurrentEpoch());\n                \n                qp = new QuorumPacket(Leader.ACKEPOCH, 0, new byte[4], null);\n                oa.writeRecord(qp, null);\n                \n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.DIFF, qp.getType());\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.NEWLEADER, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                Assert.assertEquals(1, l.self.getAcceptedEpoch());\n                Assert.assertEquals(1, l.self.getCurrentEpoch());\n                \n                qp = new QuorumPacket(Leader.ACK, qp.getZxid(), null, null);\n                oa.writeRecord(qp, null);\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.UPTODATE, qp.getType());\n            }\n        });\n    }\n\n    @Test\n    public void testTxnTimeout() throws Exception {\n        testLeaderConversation(new LeaderConversation() {\n            public void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l)\n                    throws IOException, InterruptedException, org.apache.zookeeper.server.quorum.Leader.XidRolloverException {\n                Assert.assertEquals(0, l.self.getAcceptedEpoch());\n                Assert.assertEquals(0, l.self.getCurrentEpoch());\n                \n                LearnerInfo li = new LearnerInfo(1, 0x10000);\n                byte liBytes[] = new byte[20];\n                ByteBufferOutputStream.record2ByteBuffer(li,\n                        ByteBuffer.wrap(liBytes));\n                QuorumPacket qp = new QuorumPacket(Leader.FOLLOWERINFO, 0,\n                        liBytes, null);\n                oa.writeRecord(qp, null);\n                \n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.LEADERINFO, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                Assert.assertEquals(ByteBuffer.wrap(qp.getData()).getInt(),\n                        0x10000);\n                Assert.assertEquals(1, l.self.getAcceptedEpoch());\n                Assert.assertEquals(0, l.self.getCurrentEpoch());\n                \n                qp = new QuorumPacket(Leader.ACKEPOCH, 0, new byte[4], null);\n                oa.writeRecord(qp, null);\n                \n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.DIFF, qp.getType());\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.NEWLEADER, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                Assert.assertEquals(1, l.self.getAcceptedEpoch());\n                Assert.assertEquals(1, l.self.getCurrentEpoch());\n                \n                qp = new QuorumPacket(Leader.ACK, qp.getZxid(), null, null);\n                oa.writeRecord(qp, null);\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.UPTODATE, qp.getType());\n\n                l.propose(createNodeRequest(l.zk.getZxid()));\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.PROPOSAL, qp.getType());\n\n                LOG.info(\"Proposal sent.\");\n\n                for (int i = 0; i < (2 * SYNC_LIMIT) + 2; i++) {\n                    try {\n                        ia.readRecord(qp, null);\n                        LOG.info(\"Ping received: \" + i);\n                        qp = new  QuorumPacket(Leader.PING, qp.getZxid(), \"\".getBytes(), null);\n                        oa.writeRecord(qp, null);\n                    } catch (EOFException e) {\n                        return;\n                    }\n                }\n\n                Assert.fail(\"Connection hasn't been closed by leader after transaction times out.\");\n            }\n\n            private Request createNodeRequest(long zxid) throws IOException {\n                TxnHeader hdr = new TxnHeader(1, 1, zxid, 1, ZooDefs.OpCode.create);\n                CreateTxn ct = new CreateTxn(\"/foo\", \"data\".getBytes(), null, true, 0);\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                OutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeRecord(hdr, \"header\");\n                boa.writeRecord(ct, \"txn\");\n                baos.close();\n                Request rq = new Request(null, 1, 1, ZooDefs.OpCode.create, ByteBuffer.wrap(baos.toByteArray()), null);\n                rq.zxid = zxid;\n                rq.hdr = hdr;\n                rq.txn = ct;\n                return rq;\n            }\n        });\n    }\n\n    private void deserializeSnapshot(InputArchive ia)\n            throws IOException {\n        ZKDatabase zkdb = new ZKDatabase(null);\n        zkdb.deserializeSnapshot(ia);\n        String signature = ia.readString(\"signature\");\n        assertEquals(\"BenWasHere\", signature);\n    }\n\n    @Test\n    public void testNormalObserverRun() throws Exception {\n        testObserverConversation(new ObserverConversation() {\n            @Override\n            public void converseWithObserver(InputArchive ia, OutputArchive oa,\n                    Observer o) throws Exception {\n                File tmpDir = File.createTempFile(\"test\", \"dir\", testData);\n                tmpDir.delete();\n                tmpDir.mkdir();\n                File logDir = o.zk.getTxnLogFactory().getDataDir().getParentFile();\n                File snapDir = o.zk.getTxnLogFactory().getSnapDir().getParentFile();\n                try {\n                    Assert.assertEquals(0, o.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, o.self.getCurrentEpoch());\n\n                    // Setup a database with a single /foo node\n                    ZKDatabase zkDb = new ZKDatabase(new FileTxnSnapLog(tmpDir, tmpDir));\n                    final long foo1Zxid = ZxidUtils.makeZxid(1, 1);\n                    final long foo2Zxid = ZxidUtils.makeZxid(1, 2);\n                    zkDb.processTxn(new TxnHeader(13, 1313, foo1Zxid, 33,\n                            ZooDefs.OpCode.create), new CreateTxn(\"/foo1\",\n                            \"data1\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                            false, 1));\n                    zkDb.processTxn(new TxnHeader(13, 1313, foo2Zxid, 33,\n                            ZooDefs.OpCode.create), new CreateTxn(\"/foo2\",\n                            \"data1\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                            false, 1));\n                    Stat stat = new Stat();\n                    Assert.assertEquals(\"data1\",\n                            new String(zkDb.getData(\"/foo1\", stat, null)));\n                    Assert.assertEquals(\"data1\",\n                            new String(zkDb.getData(\"/foo2\", stat, null)));\n\n                    QuorumPacket qp = new QuorumPacket();\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.OBSERVERINFO, qp.getType());\n                    Assert.assertEquals(qp.getZxid(), 0);\n                    LearnerInfo learnInfo = new LearnerInfo();\n                    ByteBufferInputStream.byteBuffer2Record(\n                            ByteBuffer.wrap(qp.getData()), learnInfo);\n                    Assert.assertEquals(learnInfo.getProtocolVersion(), 0x10000);\n                    Assert.assertEquals(learnInfo.getServerid(), 0);\n\n                    // We are simulating an established leader, so the epoch is 1\n                    qp.setType(Leader.LEADERINFO);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    byte protoBytes[] = new byte[4];\n                    ByteBuffer.wrap(protoBytes).putInt(0x10000);\n                    qp.setData(protoBytes);\n                    oa.writeRecord(qp, null);\n\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACKEPOCH, qp.getType());\n                    Assert.assertEquals(0, qp.getZxid());\n                    Assert.assertEquals(ZxidUtils.makeZxid(0, 0), ByteBuffer\n                            .wrap(qp.getData()).getInt());\n                    Assert.assertEquals(1, o.self.getAcceptedEpoch());\n                    Assert.assertEquals(0, o.self.getCurrentEpoch());\n\n                    // Send the snapshot we created earlier\n                    qp.setType(Leader.SNAP);\n                    qp.setData(new byte[0]);\n                    qp.setZxid(zkDb.getDataTreeLastProcessedZxid());\n                    oa.writeRecord(qp, null);\n                    zkDb.serializeSnapshot(oa);\n                    oa.writeString(\"BenWasHere\", null);\n                    qp.setType(Leader.NEWLEADER);\n                    qp.setZxid(ZxidUtils.makeZxid(1, 0));\n                    oa.writeRecord(qp, null);\n\n                    // Get the ack of the new leader\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                    Assert.assertEquals(1, o.self.getAcceptedEpoch());\n                    Assert.assertEquals(1, o.self.getCurrentEpoch());\n\n                    Assert.assertEquals(foo2Zxid, o.zk.getLastProcessedZxid());\n\n                    // Make sure the data was recorded in the filesystem ok\n                    ZKDatabase zkDb2 = new ZKDatabase(new FileTxnSnapLog(\n                            logDir, snapDir));\n                    long lastZxid = zkDb2.loadDataBase();\n                    Assert.assertEquals(\"data1\",\n                            new String(zkDb2.getData(\"/foo1\", stat, null)));\n                    Assert.assertEquals(foo2Zxid, lastZxid);\n\n                    // Register watch\n                    TrackerWatcher watcher = new TrackerWatcher();\n                    Assert.assertEquals(\"data1\", new String(o.zk\n                            .getZKDatabase().getData(\"/foo2\", stat, watcher)));\n\n                    // Propose /foo1 update\n                    long proposalZxid = ZxidUtils.makeZxid(1, 1000);\n                    proposeSetData(qp, \"/foo1\", proposalZxid, \"data2\", 2);\n                    oa.writeRecord(qp, null);\n\n                    // Commit /foo1 update\n                    qp.setType(Leader.COMMIT);\n                    qp.setZxid(proposalZxid);\n                    oa.writeRecord(qp, null);\n\n                    // Inform /foo2 update\n                    long informZxid = ZxidUtils.makeZxid(1, 1001);\n                    proposeSetData(qp, \"/foo2\", informZxid, \"data2\", 2);\n                    qp.setType(Leader.INFORM);\n                    oa.writeRecord(qp, null);\n\n                    qp.setType(Leader.UPTODATE);\n                    qp.setZxid(0);\n                    oa.writeRecord(qp, null);\n\n                    // Read the uptodate ack\n                    readPacketSkippingPing(ia, qp);\n                    Assert.assertEquals(Leader.ACK, qp.getType());\n                    Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n\n                    // Data should get updated\n                    watcher.waitForChange();\n                    Assert.assertEquals(\"data2\", new String(o.zk\n                            .getZKDatabase().getData(\"/foo1\", stat, null)));\n                    Assert.assertEquals(\"data2\", new String(o.zk\n                            .getZKDatabase().getData(\"/foo2\", stat, null)));\n\n                    // Shutdown sequence guarantee that all pending requests\n                    // in sync request processor get flush to disk\n                    o.zk.shutdown();\n\n                    zkDb2 = new ZKDatabase(new FileTxnSnapLog(logDir, snapDir));\n                    lastZxid = zkDb2.loadDataBase();\n                    Assert.assertEquals(\"data2\", new String(zkDb2.getData(\"/foo1\", stat, null)));\n                    Assert.assertEquals(\"data2\", new String(zkDb2.getData(\"/foo2\", stat, null)));\n                    Assert.assertEquals(informZxid, lastZxid);\n                } finally {\n                    recursiveDelete(tmpDir);\n                }\n\n            }\n\n            private void proposeSetData(QuorumPacket qp, String path,\n                    long zxid, String data, int version) throws IOException {\n                qp.setType(Leader.PROPOSAL);\n                qp.setZxid(zxid);\n                TxnHeader hdr = new TxnHeader(4, 1414, qp.getZxid(), 55,\n                        ZooDefs.OpCode.setData);\n                SetDataTxn sdt = new SetDataTxn(path, data.getBytes(), version);\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                OutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeRecord(hdr, null);\n                boa.writeRecord(sdt, null);\n                qp.setData(baos.toByteArray());\n            }\n        });\n    }\n\n    @Test\n    public void testLeaderBehind() throws Exception {\n        testLeaderConversation(new LeaderConversation() {\n            public void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l)\n                    throws IOException {\n                /* we test a normal run. everything should work out well. */\n                LearnerInfo li = new LearnerInfo(1, 0x10000);\n                byte liBytes[] = new byte[12];\n                ByteBufferOutputStream.record2ByteBuffer(li,\n                        ByteBuffer.wrap(liBytes));\n                /* we are going to say we last acked epoch 20 */\n                QuorumPacket qp = new QuorumPacket(Leader.FOLLOWERINFO, ZxidUtils.makeZxid(20, 0),\n                        liBytes, null);\n                oa.writeRecord(qp, null);\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.LEADERINFO, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(21, 0), qp.getZxid());\n                Assert.assertEquals(ByteBuffer.wrap(qp.getData()).getInt(),\n                        0x10000);\n                qp = new QuorumPacket(Leader.ACKEPOCH, 0, new byte[4], null);\n                oa.writeRecord(qp, null);\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.DIFF, qp.getType());\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.NEWLEADER, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(21, 0), qp.getZxid());\n\n                qp = new QuorumPacket(Leader.ACK, qp.getZxid(), null, null);\n                oa.writeRecord(qp, null);\n\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.UPTODATE, qp.getType());\n            }\n        });\n    }\n\n    /**\n     * Tests that when a quorum of followers send LearnerInfo but do not ack the epoch (which is sent\n     * by the leader upon receipt of LearnerInfo from a quorum), the leader does not start using this epoch\n     * as it would in the normal case (when a quorum do ack the epoch). This tests ZK-1192\n     * @throws Exception\n     */\n    @Test\n    public void testAbandonBeforeACKEpoch() throws Exception {\n        testLeaderConversation(new LeaderConversation() {\n            public void converseWithLeader(InputArchive ia, OutputArchive oa, Leader l)\n                    throws IOException, InterruptedException {\n                /* we test a normal run. everything should work out well. */            \t\n                LearnerInfo li = new LearnerInfo(1, 0x10000);\n                byte liBytes[] = new byte[12];\n                ByteBufferOutputStream.record2ByteBuffer(li,\n                        ByteBuffer.wrap(liBytes));\n                QuorumPacket qp = new QuorumPacket(Leader.FOLLOWERINFO, 0,\n                        liBytes, null);\n                oa.writeRecord(qp, null);\n                readPacketSkippingPing(ia, qp);\n                Assert.assertEquals(Leader.LEADERINFO, qp.getType());\n                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());\n                Assert.assertEquals(ByteBuffer.wrap(qp.getData()).getInt(),\n                        0x10000);                \n                Thread.sleep(l.self.getInitLimit()*l.self.getTickTime() + 5000);\n                \n                // The leader didn't get a quorum of acks - make sure that leader's current epoch is not advanced\n                Assert.assertEquals(0, l.self.getCurrentEpoch());\t\t\t\n            }\n        });\n    }\n    \n    /**\n     * verify that a peer with dirty snapshot joining an established cluster\n     * does not go into an inconsistent state.\n     *\n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1558}\n     */\n    @Test\n    public void testDirtySnapshot()\n    throws IOException,\n        InterruptedException,\n        KeeperException,\n        NoSuchFieldException,\n        IllegalAccessException {\n        Socket pair[] = getSocketPair();\n        Socket leaderSocket = pair[0];\n        Socket followerSocket = pair[1];\n        File tmpDir = File.createTempFile(\"test\", \"dir\");\n        tmpDir.delete();\n        tmpDir.mkdir();\n        LeadThread leadThread = null;\n        Leader leader = null;\n        try {\n            // Setup a database with two znodes\n            FileTxnSnapLog snapLog = new FileTxnSnapLog(tmpDir, tmpDir);\n            ZKDatabase zkDb = new ZKDatabase(snapLog);\n\n            long zxid = ZxidUtils.makeZxid(0, 1);\n            String path = \"/foo\";\n            zkDb.processTxn(new TxnHeader(13,1000,zxid,30,ZooDefs.OpCode.create),\n                                            new CreateTxn(path, \"fpjwasalsohere\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, false, 1));\n            Stat stat = new Stat();\n            Assert.assertEquals(\"fpjwasalsohere\", new String(zkDb.getData(path, stat, null)));\n\n            // Close files\n            snapLog.close();\n\n            QuorumPeer peer = createQuorumPeer(tmpDir);\n\n            leader = createLeader(tmpDir, peer);\n            peer.leader = leader;\n\n            // Set the last accepted epoch and current epochs to be 1\n            peer.setAcceptedEpoch(0);\n            peer.setCurrentEpoch(0);\n\n            leadThread = new LeadThread(leader);\n            leadThread.start();\n\n            while(leader.cnxAcceptor == null || !leader.cnxAcceptor.isAlive()) {\n                Thread.sleep(20);\n            }\n\n            leader.shutdown(\"Shutting down the leader\");\n\n            // Check if there is a valid snapshot (we better not have it)\n            File snapDir = new File (tmpDir, FileTxnSnapLog.version + FileTxnSnapLog.VERSION);\n            List<File> files = Util.sortDataDir(snapDir.listFiles(),\"snapshot\", false);\n\n            for (File f : files) {\n                try {\n                    Assert.assertFalse(\"Found a valid snapshot\", Util.isValidSnapshot(f));\n                } catch (IOException e) {\n                    LOG.info(\"invalid snapshot \" + f, e);\n                }\n            }\n\n        } finally {\n            if (leader != null) {\n                leader.shutdown(\"end of test\");\n            }\n            if (leadThread != null) {\n                leadThread.interrupt();\n                leadThread.join();\n            }\n            recursiveDelete(tmpDir);\n        }\n    }\n\n    private void recursiveDelete(File file) {\n        if (file.isFile()) {\n            file.delete();\n        } else {\n            // might return null if deleted out from under us...\n            File[] files = file.listFiles();\n            if (files != null) {\n                for(File c: files) {\n                    recursiveDelete(c);\n                }\n            }\n            file.delete();\n        }\n    }\n\n    private Leader createLeader(File tmpDir, QuorumPeer peer)\n    throws IOException, NoSuchFieldException, IllegalAccessException{\n        LeaderZooKeeperServer zk = prepareLeader(tmpDir, peer);\n        return new Leader(peer, zk);\n    }\n            \n    private Leader createMockLeader(File tmpDir, QuorumPeer peer)\n    throws IOException, NoSuchFieldException, IllegalAccessException{\n        LeaderZooKeeperServer zk = prepareLeader(tmpDir, peer);\n        return new MockLeader(peer, zk);\n    }\n            \n    private LeaderZooKeeperServer prepareLeader(File tmpDir, QuorumPeer peer)\n    throws IOException, NoSuchFieldException, IllegalAccessException {\n        FileTxnSnapLog logFactory = new FileTxnSnapLog(tmpDir, tmpDir);\n        peer.setTxnFactory(logFactory);\n        Field addrField = peer.getClass().getDeclaredField(\"myQuorumAddr\");\n        addrField.setAccessible(true);\n        addrField.set(peer, new InetSocketAddress(PortAssignment.unique()));\n        ZKDatabase zkDb = new ZKDatabase(logFactory);\n        LeaderZooKeeperServer zk = new LeaderZooKeeperServer(logFactory, peer, new ZooKeeperServer.BasicDataTreeBuilder(), zkDb);\n        return zk;\n    }\n\n    static class ConversableFollower extends Follower {\n\n        ConversableFollower(QuorumPeer self, FollowerZooKeeperServer zk) {\n            super(self, zk);\n        }\n\n        QuorumServer leaderQuorumServer;\n        public void setLeaderQuorumServer(QuorumServer quorumServer) {\n            leaderQuorumServer = quorumServer;\n        }\n        \n        @Override\n        protected QuorumServer findLeader() {\n            return leaderQuorumServer;\n        }\n    }\n    private ConversableFollower createFollower(File tmpDir, QuorumPeer peer)\n    throws IOException {\n        FileTxnSnapLog logFactory = new FileTxnSnapLog(tmpDir, tmpDir);\n        peer.setTxnFactory(logFactory);\n        ZKDatabase zkDb = new ZKDatabase(logFactory);\n        FollowerZooKeeperServer zk = new FollowerZooKeeperServer(logFactory, peer, new ZooKeeperServer.BasicDataTreeBuilder(), zkDb);\n        peer.setZKDatabase(zkDb);\n        return new ConversableFollower(peer, zk);\n    }\n\n    static class ConversableObserver extends Observer {\n        \n        ConversableObserver(QuorumPeer self, ObserverZooKeeperServer zk) {\n            super(self, zk);\n        }\n        \n        QuorumServer leaderQuorumServer;\n        public void setLeaderQuorumServer(QuorumServer quorumServer) {\n            leaderQuorumServer = quorumServer;\n        }\n        \n        @Override\n        protected QuorumServer findLeader() {\n            return leaderQuorumServer;\n        }\n    }\n        \n    private ConversableObserver createObserver(File tmpDir, QuorumPeer peer)\n            throws IOException {\n        FileTxnSnapLog logFactory = new FileTxnSnapLog(tmpDir, tmpDir);\n        peer.setTxnFactory(logFactory);\n        DataTreeBuilder treeBuilder = new ZooKeeperServer.BasicDataTreeBuilder();\n        ZKDatabase zkDb = new ZKDatabase(logFactory);\n        ObserverZooKeeperServer zk = new ObserverZooKeeperServer(logFactory, peer, treeBuilder, zkDb);\n        peer.setZKDatabase(zkDb);\n        return new ConversableObserver(peer, zk);\n    }\n        \n    \n    private QuorumPeer createQuorumPeer(File tmpDir) throws IOException,\n            FileNotFoundException {\n        QuorumPeer peer = QuorumPeer.testingQuorumPeer();\n        peer.syncLimit = SYNC_LIMIT;\n        peer.initLimit = 2;\n        peer.tickTime = 2000;\n        peer.quorumPeers = new HashMap<Long, QuorumServer>();\n        peer.quorumPeers.put(1L, new QuorumServer(0, \"0.0.0.0\", 33221, 0, null));\n        peer.quorumPeers.put(1L, new QuorumServer(1, \"0.0.0.0\", 33223, 0, null));\n        peer.setQuorumVerifier(new QuorumMaj(3));\n        peer.setCnxnFactory(new NullServerCnxnFactory());\n        File version2 = new File(tmpDir, \"version-2\");\n        version2.mkdir();\n        FileOutputStream fos;\n        fos = new FileOutputStream(new File(version2, \"currentEpoch\"));\n        fos.write(\"0\\n\".getBytes());\n        fos.close();\n        fos = new FileOutputStream(new File(version2, \"acceptedEpoch\"));\n        fos.write(\"0\\n\".getBytes());\n        fos.close();\n        return peer;\n    }\n\n    private String readContentsOfFile(File f) throws IOException {\n        return new BufferedReader(new FileReader(f)).readLine();\n    }\n\n    @Test\n    public void testInitialAcceptedCurrent() throws Exception {\n        File tmpDir = File.createTempFile(\"test\", \".dir\", testData);\n        tmpDir.delete();\n        tmpDir.mkdir();\n        try {\n            FileTxnSnapLog logFactory = new FileTxnSnapLog(tmpDir, tmpDir);\n            File version2 = new File(tmpDir, \"version-2\");\n            version2.mkdir();\n            long zxid = ZxidUtils.makeZxid(3, 3);\n\n            TxnHeader hdr = new TxnHeader(1, 1, zxid, 1, ZooDefs.OpCode.error);\n            ErrorTxn txn = new ErrorTxn(1);\n            byte[] buf = Util.marshallTxnEntry(hdr, txn);\n            Request req = new Request(null, 1, 1, ZooDefs.OpCode.error,\n                    ByteBuffer.wrap(buf), null);\n            req.hdr = hdr;\n            req.txn = txn;\n            logFactory.append(req);\n            logFactory.commit();\n            ZKDatabase zkDb = new ZKDatabase(logFactory);\n            QuorumPeer peer = QuorumPeer.testingQuorumPeer();\n            peer.setZKDatabase(zkDb);\n            peer.setTxnFactory(logFactory);\n            peer.getLastLoggedZxid();\n            Assert.assertEquals(3, peer.getAcceptedEpoch());\n            Assert.assertEquals(3, peer.getCurrentEpoch());\n            Assert.assertEquals(3, Integer\n                    .parseInt(readContentsOfFile(new File(version2,\n                            QuorumPeer.CURRENT_EPOCH_FILENAME))));\n            Assert.assertEquals(3, Integer\n                    .parseInt(readContentsOfFile(new File(version2,\n                            QuorumPeer.ACCEPTED_EPOCH_FILENAME))));\n        } finally {\n            recursiveDelete(tmpDir);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/KerberosSecurityTestcase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport org.apache.commons.io.FileUtils;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Properties;\n\n/*\n * This code is originally from HDFS, see the similarly named file there\n * in case of bug fixing, history, etc.\n *\n * Branch : trunk\n * Github Revision: 1d1ab587e4e92ce3aea4cb144811f69145cb3b33\n */\n\n/**\n * KerberosSecurityTestcase provides a base class for using MiniKdc with other\n * test cases. KerberosSecurityTestcase starts the MiniKdc (@Before) before\n * running tests, and stop the MiniKdc (@After) after the testcases, using\n * default settings (working dir and kdc configurations).\n * <p>\n * Users can directly inherit this class and implement their own test functions\n * using the default settings, or override functions getTestDir() and\n * createMiniKdcConf() to provide new settings.\n */\npublic class KerberosSecurityTestcase extends QuorumAuthTestBase {\n    private static MiniKdc kdc;\n    private static File workDir;\n    private static Properties conf;\n\n    @BeforeClass\n    public static void setUpSasl() throws Exception {\n        startMiniKdc();\n    }\n\n    @AfterClass\n    public static void tearDownSasl() throws Exception {\n        stopMiniKdc();\n        FileUtils.deleteQuietly(workDir);\n    }\n\n    public static void startMiniKdc() throws Exception {\n        createTestDir();\n        createMiniKdcConf();\n\n        kdc = new MiniKdc(conf, workDir);\n        kdc.start();\n    }\n\n    /**\n     * Create a working directory, it should be the build directory. Under this\n     * directory an ApacheDS working directory will be created, this directory\n     * will be deleted when the MiniKdc stops.\n     *\n     * @throws IOException\n     */\n    public static void createTestDir() throws IOException {\n        workDir = createTmpDir(\n                new File(System.getProperty(\"build.test.dir\", \"build\")));\n    }\n\n    static File createTmpDir(File parentDir) throws IOException {\n        File tmpFile = File.createTempFile(\"test\", \".junit\", parentDir);\n        // don't delete tmpFile - this ensures we don't attempt to create\n        // a tmpDir with a duplicate name\n        File tmpDir = new File(tmpFile + \".dir\");\n        // never true if tmpfile does it's job\n        Assert.assertFalse(tmpDir.exists());\n        Assert.assertTrue(tmpDir.mkdirs());\n        return tmpDir;\n    }\n\n    /**\n     * Create a Kdc configuration\n     */\n    public static void createMiniKdcConf() {\n        conf = MiniKdc.createConf();\n    }\n\n    public static void stopMiniKdc() {\n        if (kdc != null) {\n            kdc.stop();\n        }\n    }\n\n    public static MiniKdc getKdc() {\n        return kdc;\n    }\n\n    public static File getWorkDir() {\n        return workDir;\n    }\n\n    public static Properties getConf() {\n        return conf;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/KerberosTestUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.File;\nimport java.util.UUID;\n\nimport org.apache.zookeeper.util.SecurityUtils;\n\npublic class KerberosTestUtils {\n    private static String keytabFile = new File(System.getProperty(\"test.dir\", \"build\"), UUID.randomUUID().toString())\n            .getAbsolutePath();\n\n    public static String getRealm() {\n        return \"EXAMPLE.COM\";\n    }\n\n    public static String getLearnerPrincipal() {\n        return \"learner@EXAMPLE.COM\";\n    }\n\n    public static String getServerPrincipal() {\n        return \"zkquorum/localhost@EXAMPLE.COM\";\n    }\n\n    public static String getHostLearnerPrincipal() {\n        return \"learner/_HOST@EXAMPLE.COM\";\n    }\n\n    public static String getHostServerPrincipal() {\n        return \"zkquorum/_HOST@EXAMPLE.COM\";\n    }\n\n    public static String getHostNamedLearnerPrincipal(String myHostname) {\n        return \"learner/\" + myHostname + \"@EXAMPLE.COM\";\n    }\n\n    public static String getKeytabFile() {\n        return keytabFile;\n    }\n\n    public static String replaceHostPattern(String principal) {\n        String[] components = principal.split(\"[/@]\");\n        if (components == null || components.length < 2\n                || !components[1].equals(SecurityUtils.QUORUM_HOSTNAME_PATTERN)) {\n            return principal;\n        } else {\n            return replacePattern(components, \"localhost\");\n        }\n    }\n\n    public static String replacePattern(String[] components, String hostname) {\n        if (components.length == 3) {\n            return components[0] + \"/\" + hostname.toLowerCase() + \"@\"\n                    + components[2];\n        } else {\n            return components[0] + \"/\" + hostname.toLowerCase();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport org.apache.commons.io.Charsets;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.text.StrSubstitutor;\nimport org.apache.directory.api.ldap.model.schema.SchemaManager;\nimport org.apache.directory.api.ldap.schemaextractor.SchemaLdifExtractor;\nimport org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;\nimport org.apache.directory.api.ldap.schemaloader.LdifSchemaLoader;\nimport org.apache.directory.api.ldap.schemamanager.impl.DefaultSchemaManager;\nimport org.apache.directory.server.constants.ServerDNConstants;\nimport org.apache.directory.server.core.DefaultDirectoryService;\nimport org.apache.directory.server.core.api.CacheService;\nimport org.apache.directory.server.core.api.DirectoryService;\nimport org.apache.directory.server.core.api.InstanceLayout;\nimport org.apache.directory.server.core.api.schema.SchemaPartition;\nimport org.apache.directory.server.core.kerberos.KeyDerivationInterceptor;\nimport org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;\nimport org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;\nimport org.apache.directory.server.core.partition.ldif.LdifPartition;\nimport org.apache.directory.server.kerberos.KerberosConfig;\nimport org.apache.directory.server.kerberos.kdc.KdcServer;\nimport org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;\nimport org.apache.directory.server.kerberos.shared.keytab.Keytab;\nimport org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;\nimport org.apache.directory.server.protocol.shared.transport.TcpTransport;\nimport org.apache.directory.server.protocol.shared.transport.UdpTransport;\nimport org.apache.directory.server.xdbm.Index;\nimport org.apache.directory.shared.kerberos.KerberosTime;\nimport org.apache.directory.shared.kerberos.codec.types.EncryptionType;\nimport org.apache.directory.shared.kerberos.components.EncryptionKey;\nimport org.apache.directory.api.ldap.model.entry.DefaultEntry;\nimport org.apache.directory.api.ldap.model.entry.Entry;\nimport org.apache.directory.api.ldap.model.ldif.LdifEntry;\nimport org.apache.directory.api.ldap.model.ldif.LdifReader;\nimport org.apache.directory.api.ldap.model.name.Dn;\nimport org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.StringReader;\nimport java.lang.reflect.Method;\nimport java.net.InetAddress;\nimport java.net.ServerSocket;\nimport java.text.MessageFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.UUID;\n\n/**\n * Mini KDC based on Apache Directory Server that can be embedded in testcases\n * or used from command line as a standalone KDC.\n * <p>\n * <b>From within testcases:</b>\n * <p>\n * MiniKdc sets 2 System properties when started and un-sets them when stopped:\n * <ul>\n * <li>java.security.krb5.conf: set to the MiniKDC real/host/port</li>\n * <li>sun.security.krb5.debug: set to the debug value provided in the\n * configuration</li>\n * </ul>\n * Because of this, multiple MiniKdc instances cannot be started in parallel.\n * For example, running testcases in parallel that start a KDC each. To\n * accomplish this a single MiniKdc should be used for all testcases running\n * in parallel.\n * <p>\n * MiniKdc default configuration values are:\n * <ul>\n *   <li>org.name=EXAMPLE (used to create the REALM)</li>\n *   <li>org.domain=COM (used to create the REALM)</li>\n *   <li>kdc.bind.address=localhost</li>\n *   <li>kdc.port=0 (ephemeral port)</li>\n *   <li>instance=DefaultKrbServer</li>\n *   <li>max.ticket.lifetime=86400000 (1 day)</li>\n *   <li>max.renewable.lifetime=604800000 (7 days)</li>\n *   <li>transport=TCP</li>\n *   <li>debug=false</li>\n * </ul>\n * The generated krb5.conf forces TCP connections.\n */\n/*\n * This code is originally from HDFS, see the file name MiniKdc there\n * in case of bug fixing, history, etc.\n *\n * Branch : trunk\n * Github Revision: 42e3a805117ff7cb054c2442f7b0e0cc54be63ad\n */\npublic class MiniKdc {\n\n    public static final String JAVA_SECURITY_KRB5_CONF =\n            \"java.security.krb5.conf\";\n    public static final String SUN_SECURITY_KRB5_DEBUG =\n            \"sun.security.krb5.debug\";\n    private static final File testData = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"));\n\n    public static void main(String[] args) throws Exception {\n        if (args.length < 4) {\n            System.out.println(\"Arguments: <WORKDIR> <MINIKDCPROPERTIES> \" +\n                    \"<KEYTABFILE> [<PRINCIPALS>]+\");\n            System.exit(1);\n        }\n        File workDir = new File(args[0]);\n        if (!workDir.exists()) {\n            throw new RuntimeException(\"Specified work directory does not exists: \"\n                    + workDir.getAbsolutePath());\n        }\n        Properties conf = createConf();\n        File file = new File(args[1]);\n        if (!file.exists()) {\n            throw new RuntimeException(\"Specified configuration does not exists: \"\n                    + file.getAbsolutePath());\n        }\n        Properties userConf = new Properties();\n        InputStreamReader r = null;\n        try {\n            r = new InputStreamReader(new FileInputStream(file), Charsets.UTF_8);\n            userConf.load(r);\n        } finally {\n            if (r != null) {\n                r.close();\n            }\n        }\n        for (Map.Entry<?, ?> entry : userConf.entrySet()) {\n            conf.put(entry.getKey(), entry.getValue());\n        }\n        final MiniKdc miniKdc = new MiniKdc(conf, workDir);\n        miniKdc.start();\n        File krb5conf = new File(workDir, \"krb5.conf\");\n        if (miniKdc.getKrb5conf().renameTo(krb5conf)) {\n            File keytabFile = new File(args[2]).getAbsoluteFile();\n            String[] principals = new String[args.length - 3];\n            System.arraycopy(args, 3, principals, 0, args.length - 3);\n            miniKdc.createPrincipal(keytabFile, principals);\n            System.out.println();\n            System.out.println(\"Standalone MiniKdc Running\");\n            System.out.println(\"---------------------------------------------------\");\n            System.out.println(\"  Realm           : \" + miniKdc.getRealm());\n            System.out.println(\"  Running at      : \" + miniKdc.getHost() + \":\" +\n                    miniKdc.getHost());\n            System.out.println(\"  krb5conf        : \" + krb5conf);\n            System.out.println();\n            System.out.println(\"  created keytab  : \" + keytabFile);\n            System.out.println(\"  with principals : \" + Arrays.asList(principals));\n            System.out.println();\n            System.out.println(\" Do <CTRL-C> or kill <PID> to stop it\");\n            System.out.println(\"---------------------------------------------------\");\n            System.out.println();\n            Runtime.getRuntime().addShutdownHook(new Thread() {\n                @Override\n                public void run() {\n                    miniKdc.stop();\n                }\n            });\n        } else {\n            throw new RuntimeException(\"Cannot rename KDC's krb5conf to \"\n                    + krb5conf.getAbsolutePath());\n        }\n    }\n\n    private static final Logger LOG = LoggerFactory.getLogger(MiniKdc.class);\n\n    public static final String ORG_NAME = \"org.name\";\n    public static final String ORG_DOMAIN = \"org.domain\";\n    public static final String KDC_BIND_ADDRESS = \"kdc.bind.address\";\n    public static final String KDC_PORT = \"kdc.port\";\n    public static final String INSTANCE = \"instance\";\n    public static final String MAX_TICKET_LIFETIME = \"max.ticket.lifetime\";\n    public static final String MAX_RENEWABLE_LIFETIME = \"max.renewable.lifetime\";\n    public static final String TRANSPORT = \"transport\";\n    public static final String DEBUG = \"debug\";\n\n    private static final Set<String> PROPERTIES = new HashSet<String>();\n    private static final Properties DEFAULT_CONFIG = new Properties();\n\n    static {\n        PROPERTIES.add(ORG_NAME);\n        PROPERTIES.add(ORG_DOMAIN);\n        PROPERTIES.add(KDC_BIND_ADDRESS);\n        PROPERTIES.add(KDC_BIND_ADDRESS);\n        PROPERTIES.add(KDC_PORT);\n        PROPERTIES.add(INSTANCE);\n        PROPERTIES.add(TRANSPORT);\n        PROPERTIES.add(MAX_TICKET_LIFETIME);\n        PROPERTIES.add(MAX_RENEWABLE_LIFETIME);\n\n        DEFAULT_CONFIG.setProperty(KDC_BIND_ADDRESS, \"localhost\");\n        DEFAULT_CONFIG.setProperty(KDC_PORT, \"0\");\n        DEFAULT_CONFIG.setProperty(INSTANCE, \"DefaultKrbServer\");\n        DEFAULT_CONFIG.setProperty(ORG_NAME, \"EXAMPLE\");\n        DEFAULT_CONFIG.setProperty(ORG_DOMAIN, \"COM\");\n        DEFAULT_CONFIG.setProperty(TRANSPORT, \"TCP\");\n        DEFAULT_CONFIG.setProperty(MAX_TICKET_LIFETIME, \"86400000\");\n        DEFAULT_CONFIG.setProperty(MAX_RENEWABLE_LIFETIME, \"604800000\");\n        DEFAULT_CONFIG.setProperty(DEBUG, \"true\");\n    }\n\n    /**\n     * Convenience method that returns MiniKdc default configuration.\n     * <p>\n     * The returned configuration is a copy, it can be customized before using\n     * it to create a MiniKdc.\n     * @return a MiniKdc default configuration.\n     */\n    public static Properties createConf() {\n        return (Properties) DEFAULT_CONFIG.clone();\n    }\n\n    private Properties conf;\n    private DirectoryService ds;\n    private KdcServer kdc;\n    private int port;\n    private String realm;\n    private File workDir;\n    private File krb5conf;\n\n    /**\n     * Creates a MiniKdc.\n     *\n     * @param conf MiniKdc configuration.\n     * @param workDir working directory, it should be the build directory. Under\n     * this directory an ApacheDS working directory will be created, this\n     * directory will be deleted when the MiniKdc stops.\n     * @throws Exception thrown if the MiniKdc could not be created.\n     */\n    public MiniKdc(Properties conf, File workDir) throws Exception {\n        if (!conf.keySet().containsAll(PROPERTIES)) {\n            Set<String> missingProperties = new HashSet<String>(PROPERTIES);\n            missingProperties.removeAll(conf.keySet());\n            throw new IllegalArgumentException(\"Missing configuration properties: \"\n                    + missingProperties);\n        }\n        this.workDir = new File(workDir, Long.toString(System.currentTimeMillis()));\n        if (!this.workDir.exists()\n                && !this.workDir.mkdirs()) {\n            throw new RuntimeException(\"Cannot create directory \" + this.workDir);\n        }\n        LOG.info(\"Configuration:\");\n        LOG.info(\"---------------------------------------------------------------\");\n        for (Map.Entry<?, ?> entry : conf.entrySet()) {\n            LOG.info(\"  {}: {}\", entry.getKey(), entry.getValue());\n        }\n        LOG.info(\"---------------------------------------------------------------\");\n        this.conf = conf;\n        port = Integer.parseInt(conf.getProperty(KDC_PORT));\n        if (port == 0) {\n            ServerSocket ss = new ServerSocket(0, 1, InetAddress.getByName(conf.getProperty(KDC_BIND_ADDRESS)));\n            port = ss.getLocalPort();\n            ss.close();\n        }\n        String orgName = conf.getProperty(ORG_NAME);\n        String orgDomain = conf.getProperty(ORG_DOMAIN);\n        realm = orgName.toUpperCase(Locale.ENGLISH) + \".\"\n                + orgDomain.toUpperCase(Locale.ENGLISH);\n    }\n\n    /**\n     * Returns the port of the MiniKdc.\n     *\n     * @return the port of the MiniKdc.\n     */\n    public int getPort() {\n        return port;\n    }\n\n    /**\n     * Returns the host of the MiniKdc.\n     *\n     * @return the host of the MiniKdc.\n     */\n    public String getHost() {\n        return conf.getProperty(KDC_BIND_ADDRESS);\n    }\n\n    /**\n     * Returns the realm of the MiniKdc.\n     *\n     * @return the realm of the MiniKdc.\n     */\n    public String getRealm() {\n        return realm;\n    }\n\n    public File getKrb5conf() {\n        return krb5conf;\n    }\n\n    /**\n     * Starts the MiniKdc.\n     *\n     * @throws Exception thrown if the MiniKdc could not be started.\n     */\n    public synchronized void start() throws Exception {\n        if (kdc != null) {\n            throw new RuntimeException(\"Already started\");\n        }\n        initDirectoryService();\n        initKDCServer();\n    }\n\n    private void initDirectoryService() throws Exception {\n        ds = new DefaultDirectoryService();\n        ds.setInstanceLayout(new InstanceLayout(workDir));\n\n        CacheService cacheService = new CacheService();\n        ds.setCacheService(cacheService);\n\n        // first load the schema\n        InstanceLayout instanceLayout = ds.getInstanceLayout();\n        File schemaPartitionDirectory = new File(instanceLayout.getPartitionsDirectory(), \"schema\");\n        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(instanceLayout.getPartitionsDirectory());\n        extractor.extractOrCopy();\n\n        SchemaLoader loader = new LdifSchemaLoader(schemaPartitionDirectory);\n        SchemaManager schemaManager = new DefaultSchemaManager(loader);\n        schemaManager.loadAllEnabled();\n        ds.setSchemaManager(schemaManager);\n        // Init the LdifPartition with schema\n        LdifPartition schemaLdifPartition = new LdifPartition(schemaManager);\n        schemaLdifPartition.setPartitionPath(schemaPartitionDirectory.toURI());\n\n        // The schema partition\n        SchemaPartition schemaPartition = new SchemaPartition(schemaManager);\n        schemaPartition.setWrappedPartition(schemaLdifPartition);\n        ds.setSchemaPartition(schemaPartition);\n\n        JdbmPartition systemPartition = new JdbmPartition(ds.getSchemaManager());\n        systemPartition.setId(\"system\");\n        systemPartition.setPartitionPath(\n                new File(ds.getInstanceLayout().getPartitionsDirectory(), systemPartition.getId()).toURI());\n        systemPartition.setSuffixDn(new Dn(ServerDNConstants.SYSTEM_DN));\n        systemPartition.setSchemaManager(ds.getSchemaManager());\n        ds.setSystemPartition(systemPartition);\n\n        ds.getChangeLog().setEnabled(false);\n        ds.setDenormalizeOpAttrsEnabled(true);\n        ds.addLast(new KeyDerivationInterceptor());\n\n        // create one partition\n        String orgName = conf.getProperty(ORG_NAME).toLowerCase(Locale.ENGLISH);\n        String orgDomain = conf.getProperty(ORG_DOMAIN).toLowerCase(Locale.ENGLISH);\n\n        JdbmPartition partition = new JdbmPartition(ds.getSchemaManager());\n        partition.setId(orgName);\n        partition.setPartitionPath(new File(ds.getInstanceLayout().getPartitionsDirectory(), orgName).toURI());\n        partition.setSuffixDn(new Dn(\"dc=\" + orgName + \",dc=\" + orgDomain));\n        ds.addPartition(partition);\n        // indexes\n        Set<Index<?, ?, String>> indexedAttributes = new HashSet<Index<?, ?, String>>();\n        indexedAttributes.add(new JdbmIndex<String, Entry>(\"objectClass\", false));\n        indexedAttributes.add(new JdbmIndex<String, Entry>(\"dc\", false));\n        indexedAttributes.add(new JdbmIndex<String, Entry>(\"ou\", false));\n        partition.setIndexedAttributes(indexedAttributes);\n\n        // And start the ds\n        ds.setInstanceId(conf.getProperty(INSTANCE));\n        ds.startup();\n        // context entry, after ds.startup()\n        Dn dn = new Dn(\"dc=\" + orgName + \",dc=\" + orgDomain);\n        Entry entry = ds.newEntry(dn);\n        entry.add(\"objectClass\", \"top\", \"domain\");\n        entry.add(\"dc\", orgName);\n        ds.getAdminSession().add(entry);\n    }\n\n    private void initKDCServer() throws Exception {\n        String orgName = conf.getProperty(ORG_NAME);\n        String orgDomain = conf.getProperty(ORG_DOMAIN);\n        String bindAddress = conf.getProperty(KDC_BIND_ADDRESS);\n        final Map<String, String> map = new HashMap<String, String>();\n        map.put(\"0\", orgName.toLowerCase(Locale.ENGLISH));\n        map.put(\"1\", orgDomain.toLowerCase(Locale.ENGLISH));\n        map.put(\"2\", orgName.toUpperCase(Locale.ENGLISH));\n        map.put(\"3\", orgDomain.toUpperCase(Locale.ENGLISH));\n        map.put(\"4\", bindAddress);\n\n        InputStream is1 = getMinikdcResourceAsStream(\"minikdc.ldiff\");\n\n        SchemaManager schemaManager = ds.getSchemaManager();\n        LdifReader reader = null;\n\n        try {\n            final String content = StrSubstitutor.replace(IOUtils.toString(is1), map);\n            reader = new LdifReader(new StringReader(content));\n\n            for (LdifEntry ldifEntry : reader) {\n                ds.getAdminSession().add(new DefaultEntry(schemaManager, ldifEntry.getEntry()));\n            }\n        } finally {\n            IOUtils.closeQuietly(reader);\n            IOUtils.closeQuietly(is1);\n        }\n\n        KerberosConfig kerberosConfig = new KerberosConfig();\n        kerberosConfig.setMaximumRenewableLifetime(Long.parseLong(conf.getProperty(MAX_RENEWABLE_LIFETIME)));\n        kerberosConfig.setMaximumTicketLifetime(Long.parseLong(conf.getProperty(MAX_TICKET_LIFETIME)));\n        kerberosConfig.setSearchBaseDn(String.format(\"dc=%s,dc=%s\", orgName, orgDomain));\n        kerberosConfig.setPaEncTimestampRequired(false);\n        kdc = new KdcServer(kerberosConfig);\n        kdc.setDirectoryService(ds);\n\n        // transport\n        String transport = conf.getProperty(TRANSPORT);\n        if (transport.trim().equals(\"TCP\")) {\n            kdc.addTransports(new TcpTransport(bindAddress, port, 3, 50));\n        } else if (transport.trim().equals(\"UDP\")) {\n            kdc.addTransports(new UdpTransport(port));\n        } else {\n            throw new IllegalArgumentException(\"Invalid transport: \" + transport);\n        }\n        kdc.setServiceName(conf.getProperty(INSTANCE));\n        kdc.start();\n\n        StringBuilder sb = new StringBuilder();\n        InputStream is2 = getMinikdcResourceAsStream(\"minikdc-krb5.conf\");\n\n        BufferedReader r = null;\n\n        try {\n            r = new BufferedReader(new InputStreamReader(is2, Charsets.UTF_8));\n            String line = r.readLine();\n\n            while (line != null) {\n                sb.append(line).append(\"{3}\");\n                line = r.readLine();\n            }\n        } finally {\n            IOUtils.closeQuietly(r);\n            IOUtils.closeQuietly(is2);\n        }\n\n        krb5conf = new File(workDir, \"krb5.conf\").getAbsoluteFile();\n        FileUtils.writeStringToFile(krb5conf, MessageFormat.format(sb.toString(), getRealm(), getHost(),\n                Integer.toString(getPort()), System.getProperty(\"line.separator\")));\n        System.setProperty(JAVA_SECURITY_KRB5_CONF, krb5conf.getAbsolutePath());\n\n        System.setProperty(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG, \"false\"));\n\n        // refresh the config\n        Class<?> classRef;\n        if (System.getProperty(\"java.vendor\").contains(\"IBM\")) {\n            classRef = Class.forName(\"com.ibm.security.krb5.internal.Config\");\n        } else {\n            classRef = Class.forName(\"sun.security.krb5.Config\");\n        }\n        Method refreshMethod = classRef.getMethod(\"refresh\", new Class[0]);\n        refreshMethod.invoke(classRef, new Object[0]);\n\n        LOG.info(\"MiniKdc listening at port: {}\", getPort());\n        LOG.info(\"MiniKdc setting JVM krb5.conf to: {}\", krb5conf.getAbsolutePath());\n    }\n\n    private InputStream getMinikdcResourceAsStream(String resourceName)\n            throws FileNotFoundException {\n        File kdcResourceFile = new File(testData, \"/kerberos/\" + resourceName);\n        return new FileInputStream(kdcResourceFile);\n    }\n\n    /**\n     * Stops the MiniKdc\n     */\n    public synchronized void stop() {\n        if (kdc != null) {\n            System.getProperties().remove(JAVA_SECURITY_KRB5_CONF);\n            System.getProperties().remove(SUN_SECURITY_KRB5_DEBUG);\n            kdc.stop();\n            try {\n                ds.shutdown();\n            } catch (Exception ex) {\n                LOG.error(\"Could not shutdown ApacheDS properly: {}\", ex.toString(), ex);\n            }\n        }\n        delete(workDir);\n    }\n\n    private void delete(File f) {\n        if (f.isFile()) {\n            if (! f.delete()) {\n                LOG.warn(\"WARNING: cannot delete file \" + f.getAbsolutePath());\n            }\n        } else {\n            for (File c: f.listFiles()) {\n                delete(c);\n            }\n            if (! f.delete()) {\n                LOG.warn(\"WARNING: cannot delete directory \" + f.getAbsolutePath());\n            }\n        }\n    }\n\n    /**\n     * Creates a principal in the KDC with the specified user and password.\n     *\n     * @param principal principal name, do not include the domain.\n     * @param password password.\n     * @throws Exception thrown if the principal could not be created.\n     */\n    public synchronized void createPrincipal(String principal, String password) throws Exception {\n        String orgName = conf.getProperty(ORG_NAME);\n        String orgDomain = conf.getProperty(ORG_DOMAIN);\n        String baseDn = \"ou=users,dc=\" + orgName.toLowerCase(Locale.ENGLISH) + \",dc=\"\n                + orgDomain.toLowerCase(Locale.ENGLISH);\n        String content = \"dn: uid=\" + principal + \",\" + baseDn + \"\\n\" + \"objectClass: top\\n\" + \"objectClass: person\\n\"\n                + \"objectClass: inetOrgPerson\\n\" + \"objectClass: krb5principal\\n\" + \"objectClass: krb5kdcentry\\n\"\n                + \"cn: \" + principal + \"\\n\" + \"sn: \" + principal + \"\\n\" + \"uid: \" + principal + \"\\n\" + \"userPassword: \"\n                + password + \"\\n\" + \"krb5PrincipalName: \" + principal + \"@\" + getRealm() + \"\\n\"\n                + \"krb5KeyVersionNumber: 0\";\n\n        for (LdifEntry ldifEntry : new LdifReader(new StringReader(content))) {\n            ds.getAdminSession().add(new DefaultEntry(ds.getSchemaManager(), ldifEntry.getEntry()));\n        }\n    }\n\n    /**\n     * Creates multiple principals in the KDC and adds them to a keytab file.\n     *\n     * @param keytabFile keytab file to add the created principals.\n     * @param principals principals to add to the KDC, do not include the domain.\n     * @throws Exception thrown if the principals or the keytab file could not be\n     * created.\n     */\n    public synchronized void createPrincipal(File keytabFile,\n                                             String ... principals)\n            throws Exception {\n        String generatedPassword = UUID.randomUUID().toString();\n        Keytab keytab = new Keytab();\n        List<KeytabEntry> entries = new ArrayList<KeytabEntry>();\n        for (String principal : principals) {\n            createPrincipal(principal, generatedPassword);\n            principal = principal + \"@\" + getRealm();\n            KerberosTime timestamp = new KerberosTime();\n            for (Map.Entry<EncryptionType, EncryptionKey> entry : KerberosKeyFactory\n                    .getKerberosKeys(principal, generatedPassword).entrySet()) {\n                EncryptionKey ekey = entry.getValue();\n                byte keyVersion = (byte) ekey.getKeyVersion();\n                entries.add(new KeytabEntry(principal, 1L, timestamp, keyVersion, ekey));\n            }\n        }\n        keytab.setEntries(entries);\n        keytab.write(keytabFile);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport org.apache.directory.server.kerberos.shared.keytab.Keytab;\nimport org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport javax.security.auth.Subject;\nimport javax.security.auth.kerberos.KerberosPrincipal;\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport javax.security.auth.login.LoginContext;\nimport java.io.File;\nimport java.security.Principal;\nimport java.util.Set;\nimport java.util.Map;\nimport java.util.HashSet;\nimport java.util.HashMap;\nimport java.util.Arrays;\n\n/*\n * This code is originally from HDFS, see the file name TestMiniKdc there\n * in case of bug fixing, history, etc.\n *\n * Branch : trunk\n * Github Revision: 916140604ffef59466ba30832478311d3e6249bd\n */\npublic class MiniKdcTest extends KerberosSecurityTestcase {\n    private static final boolean IBM_JAVA = System.getProperty(\"java.vendor\")\n            .contains(\"IBM\");\n\n    @Test(timeout = 60000)\n    public void testMiniKdcStart() {\n        MiniKdc kdc = getKdc();\n        Assert.assertNotSame(0, kdc.getPort());\n    }\n\n    @Test(timeout = 60000)\n    public void testKeytabGen() throws Exception {\n        MiniKdc kdc = getKdc();\n        File workDir = getWorkDir();\n\n        kdc.createPrincipal(new File(workDir, \"keytab\"), \"foo/bar\", \"bar/foo\");\n        Keytab kt = Keytab.read(new File(workDir, \"keytab\"));\n\n        Set<String> principals = new HashSet<String>();\n        for (KeytabEntry entry : kt.getEntries()) {\n            principals.add(entry.getPrincipalName());\n        }\n        //here principals use \\ instead of /\n        //because org.apache.directory.server.kerberos.shared.keytab.KeytabDecoder\n        // .getPrincipalName(IoBuffer buffer) use \\\\ when generates principal\n        Assert.assertEquals(new HashSet<String>(Arrays.asList(\n                \"foo\\\\bar@\" + kdc.getRealm(), \"bar\\\\foo@\" + kdc.getRealm())),\n                principals);\n      }\n\n    private static class KerberosConfiguration extends Configuration {\n        private String principal;\n        private String keytab;\n        private boolean isInitiator;\n\n        private KerberosConfiguration(String principal, File keytab,\n                boolean client) {\n            this.principal = principal;\n            this.keytab = keytab.getAbsolutePath();\n            this.isInitiator = client;\n        }\n\n        public static Configuration createClientConfig(String principal,\n                File keytab) {\n            return new KerberosConfiguration(principal, keytab, true);\n        }\n\n        public static Configuration createServerConfig(String principal,\n                File keytab) {\n            return new KerberosConfiguration(principal, keytab, false);\n        }\n\n        private static String getKrb5LoginModuleName() {\n            return System.getProperty(\"java.vendor\").contains(\"IBM\")\n                    ? \"com.ibm.security.auth.module.Krb5LoginModule\"\n                    : \"com.sun.security.auth.module.Krb5LoginModule\";\n        }\n\n        @Override\n        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {\n            Map<String, String> options = new HashMap<String, String>();\n            options.put(\"principal\", principal);\n            options.put(\"refreshKrb5Config\", \"true\");\n            if (IBM_JAVA) {\n                options.put(\"useKeytab\", keytab);\n                options.put(\"credsType\", \"both\");\n            } else {\n                options.put(\"keyTab\", keytab);\n                options.put(\"useKeyTab\", \"true\");\n                options.put(\"storeKey\", \"true\");\n                options.put(\"doNotPrompt\", \"true\");\n                options.put(\"useTicketCache\", \"true\");\n                options.put(\"renewTGT\", \"true\");\n                options.put(\"isInitiator\", Boolean.toString(isInitiator));\n            }\n            String ticketCache = System.getenv(\"KRB5CCNAME\");\n            if (ticketCache != null) {\n                options.put(\"ticketCache\", ticketCache);\n            }\n            options.put(\"debug\", \"true\");\n\n            return new AppConfigurationEntry[] {\n                    new AppConfigurationEntry(getKrb5LoginModuleName(),\n                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,\n                            options) };\n        }\n    }\n\n    @Test(timeout = 60000)\n    public void testKerberosLogin() throws Exception {\n        MiniKdc kdc = getKdc();\n        File workDir = getWorkDir();\n        LoginContext loginContext = null;\n        try {\n            String principal = \"foo\";\n            File keytab = new File(workDir, \"foo.keytab\");\n            kdc.createPrincipal(keytab, principal);\n\n            Set<Principal> principals = new HashSet<Principal>();\n            principals.add(new KerberosPrincipal(principal));\n\n            // client login\n            Subject subject = new Subject(false, principals,\n                    new HashSet<Object>(), new HashSet<Object>());\n            loginContext = new LoginContext(\"\", subject, null,\n                    KerberosConfiguration.createClientConfig(principal,\n                            keytab));\n            loginContext.login();\n            subject = loginContext.getSubject();\n            Assert.assertEquals(1, subject.getPrincipals().size());\n            Assert.assertEquals(KerberosPrincipal.class,\n                    subject.getPrincipals().iterator().next().getClass());\n            Assert.assertEquals(principal + \"@\" + kdc.getRealm(),\n                    subject.getPrincipals().iterator().next().getName());\n            loginContext.logout();\n\n            // server login\n            subject = new Subject(false, principals, new HashSet<Object>(),\n                    new HashSet<Object>());\n            loginContext = new LoginContext(\"\", subject, null,\n                    KerberosConfiguration.createServerConfig(principal,\n                            keytab));\n            loginContext.login();\n            subject = loginContext.getSubject();\n            Assert.assertEquals(1, subject.getPrincipals().size());\n            Assert.assertEquals(KerberosPrincipal.class,\n                    subject.getPrincipals().iterator().next().getClass());\n            Assert.assertEquals(principal + \"@\" + kdc.getRealm(),\n                    subject.getPrincipals().iterator().next().getName());\n            loginContext.logout();\n\n        } finally {\n            if (loginContext != null && loginContext.getSubject() != null\n                    && !loginContext.getSubject().getPrincipals().isEmpty()) {\n                loginContext.logout();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.Assert;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * QuorumAuthTestBase provides a base class for testing quorum peer mutual\n * authentication using SASL mechanisms.\n */\npublic class QuorumAuthTestBase extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(QuorumAuthTestBase.class);\n    protected List<MainThread> mt = new ArrayList<MainThread>();\n    protected static File jaasConfigDir;\n\n    public static void setupJaasConfig(String jaasEntries) {\n        try {\n            jaasConfigDir = ClientBase.createTmpDir();\n            File saslConfFile = new File(jaasConfigDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n            fwriter.write(jaasEntries);\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",\n                    saslConfFile.getAbsolutePath());\n        } catch (IOException ioe) {\n            LOG.error(\"Failed to create tmp directory to hold JAAS conf file\", ioe);\n            // could not create tmp directory to hold JAAS conf file : test will\n            // fail now.\n        }\n    }\n\n    public static void cleanupJaasConfig() {\n        if (jaasConfigDir != null) {\n            FileUtils.deleteQuietly(jaasConfigDir);\n        }\n    }\n\n    protected String startQuorum(final int serverCount,\n            Map<String, String> authConfigs, int authServerCount,\n            boolean delayedServerStartup) throws IOException {\n        StringBuilder connectStr = new StringBuilder();\n        final int[] clientPorts = startQuorum(serverCount, 0, connectStr,\n                authConfigs, authServerCount, delayedServerStartup);\n        for (int i = 0; i < serverCount; i++) {\n            Assert.assertTrue(\"waiting for server \" + i + \" being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + clientPorts[i],\n                            ClientBase.CONNECTION_TIMEOUT));\n        }\n        return connectStr.toString();\n    }\n\n    /**\n     * Starts the given number of quorum servers and will wait for the quorum\n     * formation.\n     *\n     * @param serverCount\n     *            total server count includes participants + observers\n     * @param observerCount\n     *            number of observers\n     * @param authConfigs\n     *            configuration parameters for authentication\n     * @param authServerCount\n     *            number of auth enabled servers\n     * @return client port for the respective servers\n     * @throws IOException\n     */\n    protected String startQuorum(final int serverCount, int observerCount,\n            Map<String, String> authConfigs, int authServerCount)\n                    throws IOException {\n        StringBuilder connectStr = new StringBuilder();\n        final int[] clientPorts = startQuorum(serverCount, observerCount,\n                connectStr, authConfigs, authServerCount, false);\n        for (int i = 0; i < serverCount; i++) {\n            Assert.assertTrue(\"waiting for server \" + i + \" being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + clientPorts[i],\n                            ClientBase.CONNECTION_TIMEOUT));\n        }\n        return connectStr.toString();\n    }\n\n    /**\n     * Starts the given number of quorum servers and won't wait for the quorum\n     * formation.\n     *\n     * @param serverCount\n     *            total server count includes participants + observers\n     * @param observerCount\n     *            number of observers\n     * @param connectStr\n     *            connection string where clients can used for connection\n     *            establishment\n     * @param authConfigs\n     *            configuration parameters for authentication\n     * @param authServerCount\n     *            number of auth enabled servers\n     * @param delayedServerStartup\n     *            true flag value to add delay between server's startup, false otherwise.\n     * @return client port for the respective servers\n     * @throws IOException\n     */\n    protected int[] startQuorum(final int serverCount, int observerCount,\n            StringBuilder connectStr, Map<String, String> authConfigs,\n            int authServerCount, boolean delayedServerStartup)\n                    throws IOException {\n        final int clientPorts[] = new int[serverCount];\n        StringBuilder sb = new StringBuilder();\n\n        // If there are any Observers then the Observer server details will be\n        // placed first in the configuration section.\n        for (int i = 0; i < serverCount; i++) {\n            clientPorts[i] = PortAssignment.unique();\n            String server = \"\";\n            if (observerCount > 0 && i < observerCount) {\n                // add observer learner type\n                server = String.format(\"server.%d=localhost:%d:%d:observer\",\n                        i, PortAssignment.unique(), PortAssignment.unique());\n            } else {\n                // add participant learner type\n                server = String.format(\"server.%d=localhost:%d:%d:participant\",\n                        i, PortAssignment.unique(), PortAssignment.unique());\n            }\n            sb.append(server + \"\\n\");\n            connectStr.append(\"127.0.0.1:\" + clientPorts[i]);\n            if (i < serverCount - 1) {\n                connectStr.append(\",\");\n            }\n        }\n        String quorumCfg = sb.toString();\n        // servers with authentication interfaces configured\n        int i = 0;\n        for (; i < authServerCount; i++) {\n            if (observerCount > 0 && i < observerCount) {\n                String obsCfgSection = quorumCfg + \"\\npeerType=observer\";\n                quorumCfg = obsCfgSection;\n            }\n            startServer(authConfigs, clientPorts[i], quorumCfg, i, delayedServerStartup);\n        }\n        // servers without any authentication configured\n        for (int j = 0; j < serverCount - authServerCount; j++, i++) {\n            if (observerCount > 0 && i < observerCount) {\n                String obsCfgSection = quorumCfg + \"\\npeerType=observer\";\n                quorumCfg = obsCfgSection;\n            }\n            startServer(null, clientPorts[i], quorumCfg, i, delayedServerStartup);\n        }\n        return clientPorts;\n    }\n\n    private void startServer(Map<String, String> authConfigs,\n            final int clientPort, String quorumCfg, int i,\n            boolean delayedServerStartup) throws IOException {\n        MainThread mthread;\n        if (authConfigs != null) {\n            mthread = new MainThread(i, clientPort, quorumCfg, authConfigs);\n        } else {\n            mthread = new MainThread(i, clientPort, quorumCfg);\n        }\n        mt.add(mthread);\n        mthread.start();\n\n        if (delayedServerStartup) {\n            addDelayBeforeStartingNextServer(mthread);\n        }\n    }\n\n    private void addDelayBeforeStartingNextServer(MainThread mThread) {\n        // Refer https://issues.apache.org/jira/browse/ZOOKEEPER-2712\n        LOG.info(\"Waiting to finish login context init(Krb login), \"\n                + \"as there are potential concurrency issues in ApacheDS \"\n                + \"if multiple servers starts together!\");\n        int retries = 60; // 15secs delay\n        while (retries > 0) {\n            if (mThread.getQuorumPeer() != null\n                    && mThread.getQuorumPeer().hasAuthInitialized()) {\n                try {\n                    Thread.sleep(1000); // adding 1sec grace period.\n                } catch (InterruptedException e) {\n                    LOG.info(\"Ignore InterruptedException\");\n                }\n                break;\n            }\n            // moving to next retry cycle\n            retries--;\n            try {\n                Thread.sleep(250);\n            } catch (InterruptedException e) {\n                LOG.info(\"Ignore InterruptedException\");\n            }\n        }\n    }\n\n    protected void startServer(MainThread restartPeer,\n            Map<String, String> authConfigs) throws IOException {\n        MainThread mthread = new MainThread(restartPeer.getMyid(),\n                restartPeer.getClientPort(), restartPeer.getQuorumCfgSection(),\n                authConfigs);\n        mt.add(mthread);\n        mthread.start();\n    }\n\n    void shutdownAll() {\n        for (int i = 0; i < mt.size(); i++) {\n            shutdown(i);\n        }\n    }\n\n    MainThread shutdown(int index) {\n        MainThread mainThread = mt.get(index);\n        try {\n            mainThread.shutdown();\n        } catch (InterruptedException e) {\n        } finally {\n            mt.remove(index);\n        }\n        mainThread.deleteBaseDir();\n        return mainThread;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthUpgradeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientTest;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Rolling upgrade should do in three steps:\n *\n * step-1) Stop the server and set the flags and restart the server.\n * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false and quorum.auth.serverRequireSasl=false\n * Ensure that all the servers should complete this step. Now, move to next step.\n *\n * step-2) Stop the server one by one and change the flags and restart the server.\n * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=false\n * Ensure that all the servers should complete this step. Now, move to next step.\n *\n * step-3) Stop the server one by one and change the flags and restart the server.\n * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=true\n * Now, all the servers are fully upgraded and running in secured mode.\n */\npublic class QuorumAuthUpgradeTest extends QuorumAuthTestBase {\n    static {\n        String jaasEntries = new String(\"\" + \"QuorumServer {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       user_test=\\\"mypassword\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearner {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       username=\\\"test\\\"\\n\"\n                + \"       password=\\\"mypassword\\\";\\n\" + \"};\\n\");\n        setupJaasConfig(jaasEntries);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        shutdownAll();\n    }\n\n    @AfterClass\n    public static void cleanup() {\n        cleanupJaasConfig();\n    }\n\n    /**\n     * Test to verify that servers are able to start without any authentication.\n     * peer0 -> quorum.auth.enableSasl=false\n     * peer1 -> quorum.auth.enableSasl=false\n     */\n    @Test(timeout = 30000)\n    public void testNullAuthLearnerServer() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"false\");\n\n        String connectStr = startQuorum(2, authConfigs, 0, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.close();\n    }\n\n    /**\n     * Test to verify that servers are able to form quorum.\n     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n     * peer1 -> quorum.auth.enableSasl=false, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerAgainstNullAuthServer() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n\n        String connectStr = startQuorum(2, authConfigs, 1, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.close();\n    }\n\n    /**\n     * Test to verify that servers are able to form quorum.\n     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n     * peer1 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerAgainstNoAuthRequiredServer() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n\n        String connectStr = startQuorum(2, authConfigs, 2, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.close();\n    }\n\n    /**\n     * Test to verify that servers are able to form quorum.\n     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true\n     * peer1 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true\n     */\n    @Test(timeout = 30000)\n    public void testAuthLearnerServer() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n\n        String connectStr = startQuorum(2, authConfigs, 2, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.close();\n    }\n\n    /**\n     * Rolling upgrade should do in three steps:\n     *\n     * step-1) Stop the server and set the flags and restart the server.\n     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false and quorum.auth.serverRequireSasl=false\n     * Ensure that all the servers should complete this step. Now, move to next step.\n     *\n     * step-2) Stop the server one by one and change the flags and restart the server.\n     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=false\n     * Ensure that all the servers should complete this step. Now, move to next step.\n     *\n     * step-3) Stop the server one by one and change the flags and restart the server.\n     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=true\n     * Now, all the servers are fully upgraded and running in secured mode.\n     */\n    @Test(timeout = 90000)\n    public void testRollingUpgrade() throws Exception {\n        // Start peer0,1,2 servers with quorum.auth.enableSasl=false and\n        // quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n        // Assume this is an existing cluster.\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"false\");\n\n        String connectStr = startQuorum(3, authConfigs, 0, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n\n        //1. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and\n        // quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"false\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"false\");\n        restartServer(authConfigs, 0, zk, watcher);\n        restartServer(authConfigs, 1, zk, watcher);\n        restartServer(authConfigs, 2, zk, watcher);\n\n        //2. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and\n        // quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=false\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"false\");\n        restartServer(authConfigs, 0, zk, watcher);\n        restartServer(authConfigs, 1, zk, watcher);\n        restartServer(authConfigs, 2, zk, watcher);\n\n        //3. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and\n        // quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        restartServer(authConfigs, 0, zk, watcher);\n        restartServer(authConfigs, 1, zk, watcher);\n        restartServer(authConfigs, 2, zk, watcher);\n\n        //4. Restart peer2 with quorum.auth.learnerEnableSasl=false and\n        // quorum.auth.serverRequireSasl=false. It should fail to join the\n        // quorum as this needs auth.\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"false\");\n        MainThread m = shutdown(2);\n        startServer(m, authConfigs);\n        Assert.assertFalse(\"waiting for server 2 being up\", ClientBase\n                .waitForServerUp(\"127.0.0.1:\" + m.getClientPort(), 5000));\n    }\n\n    private void restartServer(Map<String, String> authConfigs, int index,\n            ZooKeeper zk, CountdownWatcher watcher) throws IOException,\n                    KeeperException, InterruptedException, TimeoutException {\n        LOG.info(\"Restarting server myid=\" + index);\n        MainThread m = shutdown(index);\n        startServer(m, authConfigs);\n        Assert.assertTrue(\"waiting for server\" + index + \"being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + m.getClientPort(),\n                        ClientBase.CONNECTION_TIMEOUT));\n        watcher.waitForConnected(ClientTest.CONNECTION_TIMEOUT);\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport static org.junit.Assert.assertNotNull;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeerMain;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class QuorumDigestAuthTest extends QuorumAuthTestBase {\n\n    private ZooKeeper zk;\n    static {\n        String jaasEntries = new String(\"\"\n                + \"QuorumServer {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       user_test=\\\"mypassword\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearner {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       username=\\\"test\\\"\\n\"\n                + \"       password=\\\"mypassword\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearnerInvalid {\\n\"\n                + \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\"\n                + \"       username=\\\"test\\\"\\n\"\n                + \"       password=\\\"invalid\\\";\\n\" + \"};\" + \"\\n\");\n        setupJaasConfig(jaasEntries);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for (MainThread mainThread : mt) {\n            mainThread.shutdown();\n            mainThread.deleteBaseDir();\n        }\n        if (zk != null) {\n            zk.close();\n        }\n    }\n\n    @AfterClass\n    public static void cleanup(){\n        cleanupJaasConfig();\n    }\n\n    /**\n     * Test to verify that server is able to start with valid credentials\n     */\n    @Test(timeout = 30000)\n    public void testValidCredentials() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n\n        String connectStr = startQuorum(3, authConfigs, 3, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        for (int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n    }\n\n    /**\n     * Test to verify that server is able to start with invalid credentials if\n     * the configuration is set to quorum.auth.serverRequireSasl=false.\n     * Quorum will talk each other even if the authentication is not succeeded\n     */\n    @Test(timeout = 30000)\n    public void testSaslNotRequiredWithInvalidCredentials() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT, \"QuorumLearnerInvalid\");\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"false\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"false\");\n        String connectStr = startQuorum(3, authConfigs, 3, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        for (int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n    }\n\n    /**\n     * Test to verify that server shouldn't start with invalid credentials\n     * if the configuration is set to quorum.auth.serverRequireSasl=true,\n     * quorum.auth.learnerRequireSasl=true\n     */\n    @Test(timeout = 30000)\n    public void testSaslRequiredInvalidCredentials() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT, \"QuorumLearnerInvalid\");\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        int serverCount = 2;\n        final int[] clientPorts = startQuorum(serverCount, 0,\n                new StringBuilder(), authConfigs, serverCount, false);\n        for (int i = 0; i < serverCount; i++) {\n            boolean waitForServerUp = ClientBase.waitForServerUp(\n                    \"127.0.0.1:\" + clientPorts[i], QuorumPeerTestBase.TIMEOUT);\n            Assert.assertFalse(\"Shouldn't start server with invalid credentials\",\n                    waitForServerUp);\n        }\n    }\n\n    /**\n     * If quorumpeer learner is not auth enabled then self won't be able to join\n     * quorum. So this test is ensuring that the quorumpeer learner is also auth\n     * enabled while enabling quorum server require sasl.\n     */\n    @Test(timeout = 10000)\n    public void testEnableQuorumServerRequireSaslWithoutQuorumLearnerRequireSasl()\n            throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,\n                \"QuorumLearner\");\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"false\");\n        MainThread mthread = new MainThread(1, PortAssignment.unique(), \"\",\n                authConfigs);\n        String args[] = new String[1];\n        args[0] = mthread.getConfFile().toString();\n        try {\n            new QuorumPeerMain() {\n                @Override\n                protected void initializeAndRun(String[] args)\n                        throws ConfigException, IOException {\n                    super.initializeAndRun(args);\n                }\n            }.initializeAndRun(args);\n            Assert.fail(\"Must throw exception as quorumpeer learner is not enabled!\");\n        } catch (ConfigException e) {\n            // expected\n        }\n    }\n\n\n    /**\n     * If quorumpeer learner is not auth enabled then self won't be able to join\n     * quorum. So this test is ensuring that the quorumpeer learner is also auth\n     * enabled while enabling quorum server require sasl.\n     */\n    @Test(timeout = 10000)\n    public void testEnableQuorumAuthenticationConfigurations()\n            throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,\n                \"QuorumLearner\");\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"false\");\n\n        // case-1) 'quorum.auth.enableSasl' is off. Tries to enable server sasl.\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"false\");\n        MainThread mthread = new MainThread(1, PortAssignment.unique(), \"\",\n                authConfigs);\n        String args[] = new String[1];\n        args[0] = mthread.getConfFile().toString();\n        try {\n            new QuorumPeerMain() {\n                @Override\n                protected void initializeAndRun(String[] args)\n                        throws ConfigException, IOException {\n                    super.initializeAndRun(args);\n                }\n            }.initializeAndRun(args);\n            Assert.fail(\"Must throw exception as quorum sasl is not enabled!\");\n        } catch (ConfigException e) {\n            // expected\n        }\n\n        // case-1) 'quorum.auth.enableSasl' is off. Tries to enable learner sasl.\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"false\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        try {\n            new QuorumPeerMain() {\n                @Override\n                protected void initializeAndRun(String[] args)\n                        throws ConfigException, IOException {\n                    super.initializeAndRun(args);\n                }\n            }.initializeAndRun(args);\n            Assert.fail(\"Must throw exception as quorum sasl is not enabled!\");\n        } catch (ConfigException e) {\n            // expected\n        }\n    }\n\n    /**\n     * Test to verify that Observer server is able to join quorum.\n     */\n    @Test(timeout = 30000)\n    public void testObserverWithValidCredentials() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n\n        // Starting auth enabled 5-node cluster. 3-Participants and 2-Observers.\n        int totalServerCount = 5;\n        int observerCount = 2;\n        String connectStr = startQuorum(totalServerCount, observerCount,\n                authConfigs, totalServerCount);\n        CountdownWatcher watcher = new CountdownWatcher();\n        zk = new ZooKeeper(connectStr.toString(), ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/myTestRoot\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n    }\n\n    /**\n     * Test to verify that non-auth enabled Observer server should be rejected\n     * by the auth enabled quorum servers.\n     */\n    @Test(timeout = 30000)\n    public void testNonAuthEnabledObserverJoiningAuthEnabledQuorum()\n            throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n\n        // Starting auth enabled 3-node cluster.\n        int totalServerCount = 3;\n        String connectStr = startQuorum(totalServerCount, authConfigs,\n                totalServerCount, false);\n\n        CountdownWatcher watcher = new CountdownWatcher();\n        zk = new ZooKeeper(connectStr.toString(), ClientBase.CONNECTION_TIMEOUT,\n                watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/myTestRoot\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n\n        // Adding a non-auth enabled Observer to the 3-node auth cluster.\n        String quorumCfgSection = mt.get(0).getQuorumCfgSection();\n        int observerMyid = totalServerCount + 1;\n        StringBuilder newObsCfgSection = new StringBuilder(quorumCfgSection);\n        newObsCfgSection.append(\"\\n\");\n        newObsCfgSection.append(String.format(\n                \"server.%d=localhost:%d:%d:observer\", observerMyid,\n                PortAssignment.unique(), PortAssignment.unique()));\n        newObsCfgSection.append(\"\\npeerType=observer\");\n        newObsCfgSection.append(\"\\n\");\n        int clientPort = PortAssignment.unique();\n        newObsCfgSection.append(\"127.0.0.1:\" + clientPort);\n        MainThread mthread = new MainThread(observerMyid, clientPort,\n                newObsCfgSection.toString());\n        mt.add(mthread);\n        mthread.start();\n\n        boolean waitForServerUp = ClientBase.waitForServerUp(\n                \"127.0.0.1:\" + clientPort, QuorumPeerTestBase.TIMEOUT);\n        Assert.assertFalse(\n                \"Non-auth enabled Observer shouldn't be able join auth-enabled quorum\",\n                waitForServerUp);\n\n        // quorum shouldn't be disturbed due to rejection.\n        zk.create(\"/myTestRoot\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n    }\n\n    /**\n     * Test to verify that server is able to reform quorum if the Leader goes\n     * down.\n     */\n    @Test(timeout = 30000)\n    public void testRelectionWithValidCredentials() throws Exception {\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n\n        String connectStr = startQuorum(3, authConfigs, 3, false);\n        CountdownWatcher watcher = new CountdownWatcher();\n        zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/myTestRoot\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n        watcher.reset();\n\n        // Shutdown Leader to trigger re-election\n        QuorumPeer leaderQP = getLeaderQuorumPeer(mt);\n        LOG.info(\"Shutdown Leader sid:{} to trigger quorum leader-election\",\n                leaderQP.getId());\n        shutdownQP(leaderQP);\n\n        // Wait for quorum formation\n        QuorumPeer newLeaderQP = waitForLeader();\n        assertNotNull(\"New leader must have been elected by now\", newLeaderQP);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        zk.create(\"/myTestRoot\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n    }\n\n    private QuorumPeer waitForLeader() throws InterruptedException {\n        int retryCnt = 0;\n        QuorumPeer newLeaderQP = null;\n        while (retryCnt < 30) {\n            newLeaderQP = getLeaderQuorumPeer(mt);\n            if (newLeaderQP != null) {\n                LOG.info(\"Number of retries:{} to findout new Leader\",\n                        retryCnt);\n                break;\n            }\n            retryCnt--;\n            Thread.sleep(500);\n        }\n        return newLeaderQP;\n    }\n\n    private void shutdownQP(QuorumPeer qp) throws InterruptedException {\n        assertNotNull(\"QuorumPeer doesn't exist!\", qp);\n        qp.shutdown();\n\n        int retryCnt = 30;\n        while (retryCnt > 0) {\n            if (qp.getPeerState() == ServerState.LOOKING) {\n                LOG.info(\"Number of retries:{} to change the server state to {}\",\n                        retryCnt, ServerState.LOOKING);\n                break;\n            }\n            Thread.sleep(500);\n            retryCnt--;\n        }\n        Assert.assertEquals(\n                \"After shutdown, QuorumPeer should change its state to LOOKING\",\n                ServerState.LOOKING, qp.getPeerState());\n    }\n\n    private QuorumPeer getLeaderQuorumPeer(List<MainThread> mtList) {\n        for (MainThread mt : mtList) {\n            QuorumPeer quorumPeer = mt.getQuorumPeer();\n            if (null != quorumPeer\n                    && ServerState.LEADING == quorumPeer.getPeerState()) {\n                return quorumPeer;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.FilenameUtils;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class QuorumKerberosAuthTest extends KerberosSecurityTestcase {\n    private static File keytabFile;\n    static {\n        String keytabFilePath = FilenameUtils.normalize(KerberosTestUtils.getKeytabFile(), true);\n        String jaasEntries = new String(\"\"\n                + \"QuorumServer {\\n\"\n                + \"       com.sun.security.auth.module.Krb5LoginModule required\\n\"\n                + \"       useKeyTab=true\\n\"\n                + \"       keyTab=\\\"\" + keytabFilePath + \"\\\"\\n\"\n                + \"       storeKey=true\\n\"\n                + \"       useTicketCache=false\\n\"\n                + \"       debug=true\\n\"\n                + \"       doNotPrompt=true\\n\"\n                + \"       refreshKrb5Config=true\\n\"\n                + \"       principal=\\\"\" + KerberosTestUtils.getServerPrincipal() + \"\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearner {\\n\"\n                + \"       com.sun.security.auth.module.Krb5LoginModule required\\n\"\n                + \"       useKeyTab=true\\n\"\n                + \"       keyTab=\\\"\" + keytabFilePath + \"\\\"\\n\"\n                + \"       storeKey=true\\n\"\n                + \"       useTicketCache=false\\n\"\n                + \"       debug=true\\n\"\n                + \"       doNotPrompt=true\\n\"\n                + \"       refreshKrb5Config=true\\n\"\n                + \"       isInitiator=true\\n\"\n                + \"       principal=\\\"\" + KerberosTestUtils.getLearnerPrincipal() + \"\\\";\\n\" + \"};\\n\");\n        setupJaasConfig(jaasEntries);\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        // create keytab\n        keytabFile = new File(KerberosTestUtils.getKeytabFile());\n        String learnerPrincipal = KerberosTestUtils.getLearnerPrincipal();\n        String serverPrincipal = KerberosTestUtils.getServerPrincipal();\n        learnerPrincipal = learnerPrincipal.substring(0, learnerPrincipal.lastIndexOf(\"@\"));\n        serverPrincipal = serverPrincipal.substring(0, serverPrincipal.lastIndexOf(\"@\"));\n        getKdc().createPrincipal(keytabFile, learnerPrincipal, serverPrincipal);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for (MainThread mainThread : mt) {\n            mainThread.shutdown();\n            mainThread.deleteBaseDir();\n        }\n    }\n\n    @AfterClass\n    public static void cleanup() {\n        if(keytabFile != null){\n            FileUtils.deleteQuietly(keytabFile);\n        }\n        cleanupJaasConfig();\n    }\n\n    /**\n     * Test to verify that server is able to start with valid credentials\n     */\n    @Test(timeout = 120000)\n    public void testValidCredentials() throws Exception {\n        String serverPrincipal = KerberosTestUtils.getServerPrincipal();\n        serverPrincipal = serverPrincipal.substring(0, serverPrincipal.lastIndexOf(\"@\"));\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);\n        String connectStr = startQuorum(3, authConfigs, 3, true);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        for (int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.server.quorum.auth;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.FilenameUtils;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport junit.framework.Assert;\n\npublic class QuorumKerberosHostBasedAuthTest extends KerberosSecurityTestcase {\n    private static File keytabFile;\n    private static String hostServerPrincipal = KerberosTestUtils.getHostServerPrincipal();\n    private static String hostLearnerPrincipal = KerberosTestUtils.getHostLearnerPrincipal();\n    private static String hostNamedLearnerPrincipal = KerberosTestUtils.getHostNamedLearnerPrincipal(\"myhost\");\n    static {\n        setupJaasConfigEntries(hostServerPrincipal, hostLearnerPrincipal, hostNamedLearnerPrincipal);\n    }\n\n    private static void setupJaasConfigEntries(String hostServerPrincipal,\n            String hostLearnerPrincipal, String hostNamedLearnerPrincipal) {\n        String keytabFilePath = FilenameUtils.normalize(KerberosTestUtils.getKeytabFile(), true);\n        String jaasEntries = new String(\"\"\n                + \"QuorumServer {\\n\"\n                + \"       com.sun.security.auth.module.Krb5LoginModule required\\n\"\n                + \"       useKeyTab=true\\n\"\n                + \"       keyTab=\\\"\" + keytabFilePath + \"\\\"\\n\"\n                + \"       storeKey=true\\n\"\n                + \"       useTicketCache=false\\n\"\n                + \"       debug=true\\n\"\n                + \"       doNotPrompt=true\\n\"\n                + \"       refreshKrb5Config=true\\n\"\n                + \"       principal=\\\"\" + KerberosTestUtils.replaceHostPattern(hostServerPrincipal) + \"\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearner {\\n\"\n                + \"       com.sun.security.auth.module.Krb5LoginModule required\\n\"\n                + \"       useKeyTab=true\\n\"\n                + \"       keyTab=\\\"\" + keytabFilePath + \"\\\"\\n\"\n                + \"       storeKey=true\\n\"\n                + \"       useTicketCache=false\\n\"\n                + \"       debug=true\\n\"\n                + \"       doNotPrompt=true\\n\"\n                + \"       refreshKrb5Config=true\\n\"\n                + \"       isInitiator=true\\n\"\n                + \"       principal=\\\"\" + KerberosTestUtils.replaceHostPattern(hostLearnerPrincipal) + \"\\\";\\n\" + \"};\\n\"\n                + \"QuorumLearnerMyHost {\\n\"\n                + \"       com.sun.security.auth.module.Krb5LoginModule required\\n\"\n                + \"       useKeyTab=true\\n\"\n                + \"       keyTab=\\\"\" + keytabFilePath + \"\\\"\\n\"\n                + \"       storeKey=true\\n\"\n                + \"       useTicketCache=false\\n\"\n                + \"       debug=true\\n\"\n                + \"       doNotPrompt=true\\n\"\n                + \"       refreshKrb5Config=true\\n\"\n                + \"       isInitiator=true\\n\"\n                + \"       principal=\\\"\" + hostNamedLearnerPrincipal + \"\\\";\\n\" + \"};\\n\");\n        setupJaasConfig(jaasEntries);\n    }\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        // create keytab\n        keytabFile = new File(KerberosTestUtils.getKeytabFile());\n\n        // Creates principals in the KDC and adds them to a keytab file.\n        String learnerPrincipal = hostLearnerPrincipal.substring(0, hostLearnerPrincipal.lastIndexOf(\"@\"));\n        learnerPrincipal = KerberosTestUtils.replaceHostPattern(learnerPrincipal);\n        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf(\"@\"));\n        serverPrincipal = KerberosTestUtils.replaceHostPattern(serverPrincipal);\n\n        // learner with ipaddress in principal\n        String learnerPrincipal2 = hostNamedLearnerPrincipal.substring(0, hostNamedLearnerPrincipal.lastIndexOf(\"@\"));\n        getKdc().createPrincipal(keytabFile, learnerPrincipal, learnerPrincipal2, serverPrincipal);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for (MainThread mainThread : mt) {\n            mainThread.shutdown();\n            mainThread.deleteBaseDir();\n        }\n    }\n\n    @AfterClass\n    public static void cleanup() {\n        if(keytabFile != null){\n            FileUtils.deleteQuietly(keytabFile);\n        }\n        cleanupJaasConfig();\n    }\n\n    /**\n     * Test to verify that server is able to start with valid credentials\n     */\n    @Test(timeout = 120000)\n    public void testValidCredentials() throws Exception {\n        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf(\"@\"));\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);\n        String connectStr = startQuorum(3, authConfigs, 3, true);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        for (int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n    }\n\n    /**\n     * Test to verify that the bad server connection to the quorum should be rejected.\n     */\n    @Test(timeout = 120000)\n    public void testConnectBadServer() throws Exception {\n        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf(\"@\"));\n        Map<String, String> authConfigs = new HashMap<String, String>();\n        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, \"true\");\n        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);\n        String connectStr = startQuorum(3, authConfigs, 3, true);\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        for (int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n\n        String quorumCfgSection = mt.get(0).getQuorumCfgSection();\n        StringBuilder sb = new StringBuilder();\n        sb.append(quorumCfgSection);\n\n        int myid = mt.size() + 1;\n        final int clientPort = PortAssignment.unique();\n        String server = String.format(\"server.%d=localhost:%d:%d:participant\",\n                myid, PortAssignment.unique(), PortAssignment.unique());\n        sb.append(server + \"\\n\");\n        quorumCfgSection = sb.toString();\n        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,\n                \"QuorumLearnerMyHost\");\n        MainThread badServer = new MainThread(myid, clientPort, quorumCfgSection,\n                authConfigs);\n        badServer.start();\n        watcher = new CountdownWatcher();\n        connectStr = \"127.0.0.1:\" + clientPort;\n        zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);\n        try{\n            watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT/3);\n            Assert.fail(\"Must throw exception as the myHost is not an authorized one!\");\n        } catch (TimeoutException e){\n            // expected\n        } finally {\n            zk.close();\n            badServer.shutdown();\n            badServer.deleteBaseDir();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/server/util/PortForwarder.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * \n */\npackage org.apache.zookeeper.server.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.ConnectException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.net.SocketTimeoutException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A utility that does bi-directional forwarding between two ports.\n * Useful, for example, to simulate network failures.\n * Example:\n * \n *   Server 1 config file:\n *           \n *      server.1=127.0.0.1:7301:7401;8201\n *      server.2=127.0.0.1:7302:7402;8202\n *      server.3=127.0.0.1:7303:7403;8203\n *   \n *   Server 2 and 3 config files:\n *           \n *      server.1=127.0.0.1:8301:8401;8201\n *      server.2=127.0.0.1:8302:8402;8202\n *      server.3=127.0.0.1:8303:8403;8203\n *\n *   Initially forward traffic between 730x and 830x and between 740x and 830x\n *   This way server 1 can communicate with servers 2 and 3\n *  ....\n *   \n *   List<PortForwarder> pfs = startForwarding();\n *  ....\n *   // simulate a network interruption for server 1\n *   stopForwarding(pfs);\n *  ....\n *   // restore connection \n *   pfs = startForwarding();\n *\n *\n *  private List<PortForwarder> startForwarding() throws IOException {\n *      List<PortForwarder> res = new ArrayList<PortForwarder>();\n *      res.add(new PortForwarder(8301, 7301));\n *      res.add(new PortForwarder(8401, 7401));\n *      res.add(new PortForwarder(7302, 8302));\n *      res.add(new PortForwarder(7402, 8402));\n *      res.add(new PortForwarder(7303, 8303));\n *      res.add(new PortForwarder(7403, 8403));\n *      return res;\n *  }\n *  \n *  private void stopForwarding(List<PortForwarder> pfs) throws Exception {\n *       for (PortForwarder pf : pfs) {\n *           pf.shutdown();\n *       }\n *  }\n *  \n *\n */\npublic class PortForwarder extends Thread {\n    private static final Logger LOG = LoggerFactory\n            .getLogger(PortForwarder.class);\n\n    private static class PortForwardWorker implements Runnable {\n\n        private final InputStream in;\n        private final OutputStream out;\n        private final Socket toClose;\n        private final Socket toClose2;\n\n        PortForwardWorker(Socket toClose, Socket toClose2, InputStream in,\n                OutputStream out) throws IOException {\n            this.toClose = toClose;\n            this.toClose2 = toClose2;\n            this.in = in;\n            this.out = out;\n            // LOG.info(\"starting forward for \"+toClose);\n        }\n\n        public void run() {\n            Thread.currentThread().setName(toClose.toString() + \"-->\"\n                    + toClose2.toString());\n            byte[] buf = new byte[1024];\n            try {\n                while (true) {\n                    try {\n                        int read = this.in.read(buf);\n                        if (read > 0) {\n                            try {\n                                this.out.write(buf, 0, read);\n                            } catch (IOException e) {\n                                LOG.warn(\"exception during write\", e);\n                                try {\n                                    toClose.close();\n                                } catch (IOException ex) {\n                                    // ignore\n                                }\n                                try {\n                                    toClose2.close();\n                                } catch (IOException ex) {\n                                    // ignore\n                                }\n                                break;\n                            }\n                        }\n                    } catch (SocketTimeoutException e) {\n                        LOG.error(\"socket timeout\", e);\n                    }\n                    Thread.sleep(1);\n                }\n            } catch (InterruptedException e) {\n                LOG.warn(\"Interrupted\", e);\n                try {\n                    toClose.close();\n                } catch (IOException ex) {\n                    // ignore\n                }\n                try {\n                    toClose2.close();\n                } catch (IOException ex) {\n                    // ignore silently\n                }\n            } catch (SocketException e) {\n                if (!\"Socket closed\".equals(e.getMessage())) {\n                    LOG.error(\"Unexpected exception\", e);\n                }\n            } catch (IOException e) {\n                LOG.error(\"Unexpected exception\", e);\n            }\n            LOG.info(\"Shutting down forward for \" + toClose);\n        }\n\n    }\n\n    private volatile boolean stopped = false;\n    private ExecutorService workers = Executors.newCachedThreadPool();\n    private ServerSocket serverSocket;\n    private final int to;\n\n    public PortForwarder(int from, int to) throws IOException {\n        this.to = to;\n        serverSocket = new ServerSocket(from);\n        serverSocket.setSoTimeout(30000);\n        this.start();\n    }\n\n    @Override\n    public void run() {\n        try {\n            while (!stopped) {\n                Socket sock = null;\n                try {\n                    LOG.info(\"accepting socket local:\"\n                            + serverSocket.getLocalPort() + \" to:\" + to);\n                    sock = serverSocket.accept();\n                    LOG.info(\"accepted: local:\" + sock.getLocalPort()\n                            + \" from:\" + sock.getPort()\n                            + \" to:\" + to);\n                    Socket target = null;\n                    int retry = 10;\n                    while(sock.isConnected()) {\n                        try {\n                            target = new Socket(\"localhost\", to);\n                            break;\n                        } catch (IOException e) {\n                            if (retry == 0) {\n                               throw e;\n                            }\n                            LOG.warn(\"connection failed, retrying(\" + retry\n                                    + \"): local:\" + sock.getLocalPort()\n                                    + \" from:\" + sock.getPort()\n                                    + \" to:\" + to, e);\n                        }\n                        Thread.sleep(TimeUnit.SECONDS.toMillis(1));\n                        retry--;\n                    }\n                    LOG.info(\"connected: local:\" + sock.getLocalPort()\n                            + \" from:\" + sock.getPort()\n                            + \" to:\" + to);\n                    sock.setSoTimeout(30000);\n                    target.setSoTimeout(30000);\n                    this.workers.execute(new PortForwardWorker(sock, target,\n                            sock.getInputStream(), target.getOutputStream()));\n                    this.workers.execute(new PortForwardWorker(target, sock,\n                            target.getInputStream(), sock.getOutputStream()));\n                } catch (SocketTimeoutException e) {               \t\n                    LOG.warn(\"socket timed out local:\" \n                            + (sock != null ? sock.getLocalPort(): \"\")\n                            + \" from:\" + (sock != null ? sock.getPort(): \"\")\n                            + \" to:\" + to, e);\n                } catch (ConnectException e) {\n                    LOG.warn(\"connection exception local:\"\n                            + (sock != null ? sock.getLocalPort(): \"\")\n                            + \" from:\" + (sock != null ? sock.getPort(): \"\")\n                            + \" to:\" + to, e);\n                    sock.close();\n                } catch (IOException e) {\n                    if (!\"Socket closed\".equals(e.getMessage())) {\n                        LOG.warn(\"unexpected exception local:\" \n                        \t\t+ (sock != null ? sock.getLocalPort(): \"\")\n                                + \" from:\" + (sock != null ? sock.getPort(): \"\")\n                                + \" to:\" + to, e);\n                        throw e;\n                    }\n                }\n            }\n        } catch (IOException e) {\n            LOG.error(\"Unexpected exception to:\" + to, e);\n        } catch (InterruptedException e) {\n            LOG.error(\"Interrupted to:\" + to, e);\n        }\n    }\n\n    public void shutdown() throws Exception {\n        this.stopped = true;\n        this.serverSocket.close();\n        this.workers.shutdownNow();\n        try {\n            if (!this.workers.awaitTermination(5, TimeUnit.SECONDS)) {\n                throw new Exception(\n                        \"Failed to stop forwarding within 5 seconds\");\n            }\n        } catch (InterruptedException e) {\n            throw new Exception(\"Failed to stop forwarding\");\n        }\n        this.join();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ACLCountTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ACLCountTest extends ZKTestCase implements Watcher {\n    private static final Logger LOG = LoggerFactory.getLogger(ACLTest.class);\n    private static final String HOSTPORT =\n        \"127.0.0.1:\" + PortAssignment.unique();\n    private volatile CountDownLatch startSignal;\n\n    /**\n     *\n     * Create a node and add 4 ACL values to it, but there are only 2 unique ACL values,\n     * and each is repeated once:\n     *\n     *   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);\n     *   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);\n     *   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);\n     *   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);\n     *\n     * Even though we've added 4 ACL values, there should only be 2 ACLs for that node,\n     * since there are only 2 *unique* ACL values.\n     */\n    @Test\n    public void testAclCount() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(1000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        ZooKeeper zk;\n\n        final ArrayList<ACL> CREATOR_ALL_AND_WORLD_READABLE =\n          new ArrayList<ACL>() { {\n            add(new ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE));\n            add(new ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS));\n            add(new ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE));\n            add(new ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS));\n        }};\n\n        try {\n            LOG.info(\"starting up the zookeeper server .. waiting\");\n            Assert.assertTrue(\"waiting for server being up\",\n                    ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n            zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n\n            zk.addAuthInfo(\"digest\", \"pat:test\".getBytes());\n            zk.setACL(\"/\", Ids.CREATOR_ALL_ACL, -1);\n\n            String path = \"/path\";\n\n            try {\n              Assert.assertEquals(4,CREATOR_ALL_AND_WORLD_READABLE.size());\n            }\n            catch (Exception e) {\n              LOG.error(\"Something is fundamentally wrong with ArrayList's add() method. add()ing four times to an empty ArrayList should result in an ArrayList with 4 members.\");\n              throw e;\n            }\n\n            zk.create(path,path.getBytes(),CREATOR_ALL_AND_WORLD_READABLE,CreateMode.PERSISTENT);\n            List<ACL> acls = zk.getACL(\"/path\", new Stat());\n            Assert.assertEquals(2,acls.size());\n        }\n        catch (Exception e) {\n          // test failed somehow.\n          Assert.assertTrue(false);\n        }\n\n        f.shutdown();\n        zks.shutdown();\n    }\n\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \"\n                 + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected) {\n            if (startSignal != null && startSignal.getCount() > 0) {\n                LOG.info(\"startsignal.countDown()\");\n                startSignal.countDown();\n            } else {\n                LOG.warn(\"startsignal \" + startSignal);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ACLRootTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ACLRootTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory.getLogger(ACLRootTest.class);\n\n    @Test\n    public void testRootAcl() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            // set auth using digest\n            zk.addAuthInfo(\"digest\", \"pat:test\".getBytes());\n            zk.setACL(\"/\", Ids.CREATOR_ALL_ACL, -1);\n            zk.getData(\"/\", false, null);\n            zk.close();\n            // verify no access\n            zk = createClient();\n            try {\n                zk.getData(\"/\", false, null);\n                Assert.fail(\"validate auth\");\n            } catch (KeeperException.NoAuthException e) {\n                // expected\n            }\n            try {\n                zk.create(\"/apps\", null, Ids.CREATOR_ALL_ACL,\n                        CreateMode.PERSISTENT);\n                Assert.fail(\"validate auth\");\n            } catch (KeeperException.InvalidACLException e) {\n                // expected\n            }\n            zk.addAuthInfo(\"digest\", \"world:anyone\".getBytes());\n            try {\n                zk.create(\"/apps\", null, Ids.CREATOR_ALL_ACL,\n                        CreateMode.PERSISTENT);\n                Assert.fail(\"validate auth\");\n            } catch (KeeperException.NoAuthException e) {\n                // expected\n            }\n            zk.close();\n            // verify access using original auth\n            zk = createClient();\n            zk.addAuthInfo(\"digest\", \"pat:test\".getBytes());\n            zk.getData(\"/\", false, null);\n            zk.create(\"/apps\", null, Ids.CREATOR_ALL_ACL,\n                    CreateMode.PERSISTENT);\n            zk.delete(\"/apps\", -1);\n            // reset acl (back to open) and verify accessible again\n            zk.setACL(\"/\", Ids.OPEN_ACL_UNSAFE, -1);\n            zk.close();\n            zk = createClient();\n            zk.getData(\"/\", false, null);\n            zk.create(\"/apps\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            try {\n                zk.create(\"/apps\", null, Ids.CREATOR_ALL_ACL,\n                        CreateMode.PERSISTENT);\n                Assert.fail(\"validate auth\");\n            } catch (KeeperException.InvalidACLException e) {\n                // expected\n            }\n            zk.delete(\"/apps\", -1);\n            zk.addAuthInfo(\"digest\", \"world:anyone\".getBytes());\n            zk.create(\"/apps\", null, Ids.CREATOR_ALL_ACL,\n                    CreateMode.PERSISTENT);\n            zk.close();\n            zk = createClient();\n            zk.delete(\"/apps\", -1);\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ACLTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ACLTest extends ZKTestCase implements Watcher {\n    private static final Logger LOG = LoggerFactory.getLogger(ACLTest.class);\n    private static final String HOSTPORT =\n        \"127.0.0.1:\" + PortAssignment.unique();\n    private volatile CountDownLatch startSignal;\n\n    @Test\n    public void testDisconnectedAddAuth() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(1000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        try {\n            LOG.info(\"starting up the zookeeper server .. waiting\");\n            Assert.assertTrue(\"waiting for server being up\",\n                    ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n            ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n            try {\n                zk.addAuthInfo(\"digest\", \"pat:test\".getBytes());\n                zk.setACL(\"/\", Ids.CREATOR_ALL_ACL, -1);\n            } finally {\n                zk.close();\n            }\n        } finally {\n            f.shutdown();\n            zks.shutdown();\n            Assert.assertTrue(\"waiting for server down\",\n                    ClientBase.waitForServerDown(HOSTPORT,\n                            ClientBase.CONNECTION_TIMEOUT));\n        }\n    }\n\n    /**\n     * Verify that acl optimization of storing just\n     * a few acls and there references in the data\n     * node is actually working.\n     */\n    @Test\n    public void testAcls() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(1000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        ZooKeeper zk;\n        String path;\n        try {\n            LOG.info(\"starting up the zookeeper server .. waiting\");\n            Assert.assertTrue(\"waiting for server being up\",\n                    ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n            zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n            LOG.info(\"starting creating acls\");\n            for (int i = 0; i < 100; i++) {\n                path = \"/\" + i;\n                zk.create(path, path.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n            Assert.assertTrue(\"size of the acl map \", (1 == zks.getZKDatabase().getAclSize()));\n            for (int j = 100; j < 200; j++) {\n                path = \"/\" + j;\n                ACL acl = new ACL();\n                acl.setPerms(0);\n                Id id = new Id();\n                id.setId(\"1.1.1.\"+j);\n                id.setScheme(\"ip\");\n                acl.setId(id);\n                ArrayList<ACL> list = new ArrayList<ACL>();\n                list.add(acl);\n                zk.create(path, path.getBytes(), list, CreateMode.PERSISTENT);\n            }\n            Assert.assertTrue(\"size of the acl map \", (101 == zks.getZKDatabase().getAclSize()));\n        } finally {\n            // now shutdown the server and restart it\n            f.shutdown();\n            zks.shutdown();\n            Assert.assertTrue(\"waiting for server down\",\n                    ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));\n        }\n        startSignal = new CountDownLatch(1);\n\n        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        f = ServerCnxnFactory.createFactory(PORT, -1);\n\n        f.startup(zks);\n        try {\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n    \n            startSignal.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n            Assert.assertTrue(\"count == 0\", startSignal.getCount() == 0);\n    \n            Assert.assertTrue(\"acl map \", (101 == zks.getZKDatabase().getAclSize()));\n            for (int j = 200; j < 205; j++) {\n                path = \"/\" + j;\n                ACL acl = new ACL();\n                acl.setPerms(0);\n                Id id = new Id();\n                id.setId(\"1.1.1.\"+j);\n                id.setScheme(\"ip\");\n                acl.setId(id);\n                ArrayList<ACL> list = new ArrayList<ACL>();\n                list.add(acl);\n                zk.create(path, path.getBytes(), list, CreateMode.PERSISTENT);\n            }\n            Assert.assertTrue(\"acl map \", (106 == zks.getZKDatabase().getAclSize()));\n    \n            zk.close();\n        } finally {\n            f.shutdown();\n            zks.shutdown();\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(HOSTPORT,\n                               ClientBase.CONNECTION_TIMEOUT));\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \"\n                 + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected) {\n            if (startSignal != null && startSignal.getCount() > 0) {\n                LOG.info(\"startsignal.countDown()\");\n                startSignal.countDown();\n            } else {\n                LOG.warn(\"startsignal \" + startSignal);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AsyncHammerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\nimport static org.apache.zookeeper.test.ClientBase.verifyThreadTerminated;\n\nimport java.util.LinkedList;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class AsyncHammerTest extends ZKTestCase\n    implements StringCallback, VoidCallback, DataCallback\n{\n    private static final Logger LOG = LoggerFactory.getLogger(AsyncHammerTest.class);\n\n    private QuorumBase qb = new QuorumBase();\n\n    private volatile boolean bang;\n\n    public void setUp(boolean withObservers) throws Exception {\n        qb.setUp(withObservers);\n    }\n\n    protected void restart() throws Exception {\n        LOG.info(\"RESTARTING \" + getTestName());\n        qb.tearDown();\n\n        // don't call setup - we don't want to reassign ports/dirs, etc...\n        JMXEnv.setUp();\n        qb.startServers();\n    }\n\n    public void tearDown() throws Exception {\n        LOG.info(\"Test clients shutting down\");\n        qb.tearDown();\n    }\n\n    /**\n     * Create /test- sequence nodes asynchronously, max 30 outstanding\n     */\n    class HammerThread extends Thread implements StringCallback, VoidCallback {\n        private static final int MAX_OUTSTANDING = 30;\n\n        private TestableZooKeeper zk;\n        private int outstanding;\n\n        private volatile boolean failed = false;\n\n        public HammerThread(String name) {\n            super(name);\n        }\n\n        public void run() {\n            try {\n                CountdownWatcher watcher = new CountdownWatcher();\n                zk = new TestableZooKeeper(qb.hostPort, CONNECTION_TIMEOUT,\n                        watcher);\n                watcher.waitForConnected(CONNECTION_TIMEOUT);\n                while(bang) {\n                    incOutstanding(); // before create otw race\n                    zk.create(\"/test-\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                            CreateMode.PERSISTENT_SEQUENTIAL, this, null);\n                }\n            } catch (InterruptedException e) {\n                if (bang) {\n                    LOG.error(\"sanity check Assert.failed!!!\"); // sanity check\n                    return;\n                }\n            } catch (Exception e) {\n                LOG.error(\"Client create operation Assert.failed\", e);\n                return;\n            } finally {\n                if (zk != null) {\n                    try {\n                        zk.close();\n                        if (!zk.testableWaitForShutdown(CONNECTION_TIMEOUT)) {\n                            failed = true;\n                            LOG.error(\"Client did not shutdown\");\n                        }\n                    } catch (InterruptedException e) {\n                        LOG.info(\"Interrupted\", e);\n                    }\n                }\n            }\n        }\n\n        private synchronized void incOutstanding() throws InterruptedException {\n            outstanding++;\n            while(outstanding > MAX_OUTSTANDING) {\n                wait();\n            }\n        }\n\n        private synchronized void decOutstanding() {\n            outstanding--;\n            Assert.assertTrue(\"outstanding >= 0\", outstanding >= 0);\n            notifyAll();\n        }\n\n        public void process(WatchedEvent event) {\n            // ignore for purposes of this test\n        }\n\n        public void processResult(int rc, String path, Object ctx, String name) {\n            if (rc != KeeperException.Code.OK.intValue()) {\n                if (bang) {\n                    failed = true;\n                    LOG.error(\"Create Assert.failed for 0x\"\n                            + Long.toHexString(zk.getSessionId())\n                            + \"with rc:\" + rc + \" path:\" + path);\n                }\n                decOutstanding();\n                return;\n            }\n            try {\n                decOutstanding();\n                zk.delete(name, -1, this, null);\n            } catch (Exception e) {\n                if (bang) {\n                    failed = true;\n                    LOG.error(\"Client delete Assert.failed\", e);\n                }\n            }\n        }\n\n        public void processResult(int rc, String path, Object ctx) {\n            if (rc != KeeperException.Code.OK.intValue()) {\n                if (bang) {\n                    failed = true;\n                    LOG.error(\"Delete Assert.failed for 0x\"\n                            + Long.toHexString(zk.getSessionId())\n                            + \"with rc:\" + rc + \" path:\" + path);\n                }\n            }\n        }\n    }\n\n    @Test\n    public void testHammer() throws Exception {\n        setUp(false);\n        bang = true;\n        LOG.info(\"Starting hammers\");\n        HammerThread[] hammers = new HammerThread[100];\n        for (int i = 0; i < hammers.length; i++) {\n            hammers[i] = new HammerThread(\"HammerThread-\" + i);\n            hammers[i].start();\n        }\n        LOG.info(\"Started hammers\");\n        Thread.sleep(5000); // allow the clients to run for max 5sec\n        bang = false;\n        LOG.info(\"Stopping hammers\");\n        for (int i = 0; i < hammers.length; i++) {\n            hammers[i].interrupt();\n            verifyThreadTerminated(hammers[i], 60000);\n            Assert.assertFalse(hammers[i].failed);\n        }\n\n        // before restart\n        LOG.info(\"Hammers stopped, verifying consistency\");\n        qb.verifyRootOfAllServersMatch(qb.hostPort);\n\n        restart();\n\n        // after restart\n        LOG.info(\"Verifying hammers 2\");\n        qb.verifyRootOfAllServersMatch(qb.hostPort);\n        tearDown();\n    }\n\n    @Test\n    public void testObserversHammer() throws Exception {\n        setUp(true);\n        bang = true;\n        Thread[] hammers = new Thread[100];\n        for (int i = 0; i < hammers.length; i++) {\n            hammers[i] = new HammerThread(\"HammerThread-\" + i);\n            hammers[i].start();\n        }\n        Thread.sleep(5000); // allow the clients to run for max 5sec\n        bang = false;\n        for (int i = 0; i < hammers.length; i++) {\n            hammers[i].interrupt();\n            verifyThreadTerminated(hammers[i], 60000);\n        }\n        // before restart\n        qb.verifyRootOfAllServersMatch(qb.hostPort);\n        tearDown();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx, String name) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx, byte[] data,\n            Stat stat) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AsyncOps.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.ACLCallback;\nimport org.apache.zookeeper.AsyncCallback.Children2Callback;\nimport org.apache.zookeeper.AsyncCallback.ChildrenCallback;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\n\npublic class AsyncOps {\n    /**\n     * This is the base class for all of the async callback classes. It will\n     * verify the expected value against the actual value.\n     * \n     * Basic operation is that the subclasses will generate an \"expected\" value\n     * which is defined by the \"toString\" method of the subclass. This is\n     * passed through to the verify clause by specifying it as the ctx object\n     * of each async call (processResult methods get the ctx as part of\n     * the callback). Additionally the callback will also overwrite any\n     * instance fields with matching parameter arguments to the processResult\n     * method. The cb instance can then compare the expected to the\n     * actual value by again calling toString and comparing the two.\n     * \n     * The format of each expected value differs (is defined) by subclass.\n     * Generally the expected value starts with the result code (rc) and path\n     * of the node being operated on, followed by the fields specific to\n     * each operation type (cb subclass). For example ChildrenCB specifies\n     * a list of the expected children suffixed onto the rc and path. See\n     * the toString() method of each subclass for details of it's format. \n     */\n    public static abstract class AsyncCB {\n        protected final ZooKeeper zk;\n        protected long defaultTimeoutMillis = 30000;\n        \n        /** the latch is used to await the results from the server */\n        CountDownLatch latch;\n\n        Code rc = Code.OK;\n        String path = \"/foo\";\n        String expected;\n        \n        public AsyncCB(ZooKeeper zk, CountDownLatch latch) {\n            this.zk = zk;\n            this.latch = latch;\n        }\n        \n        public void setRC(Code rc) {\n            this.rc = rc;\n        }\n        \n        public void setPath(String path) {\n            this.path = path;\n        }\n        \n        public void processResult(Code rc, String path, Object ctx)\n        {\n            this.rc = rc;\n            this.path = path;\n            this.expected = (String)ctx;\n            latch.countDown();\n        }\n        \n        /** String format is rc:path:<suffix> where <suffix> is defined by each\n         * subclass individually. */\n        @Override\n        public String toString() {\n            return rc + \":\" + path + \":\"; \n        }\n\n        protected void verify() {\n            try {\n                latch.await(defaultTimeoutMillis, TimeUnit.MILLISECONDS);\n            } catch (InterruptedException e) {\n                Assert.fail(\"unexpected interrupt\");\n            }\n            // on the lookout for timeout\n            Assert.assertSame(0L, latch.getCount());\n            \n            String actual = toString();\n            \n            Assert.assertEquals(expected, actual);\n        }\n    }\n    \n    public static class StringCB extends AsyncCB implements StringCallback {\n        byte[] data = new byte[10];\n        List<ACL> acl = Ids.CREATOR_ALL_ACL;\n        CreateMode flags = CreateMode.PERSISTENT;\n        String name = path;\n        \n        StringCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n        \n        StringCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n        }\n        \n        public void setPath(String path) {\n            super.setPath(path);\n            this.name = path;\n        }\n        \n        public String nodeName() {\n            return path.substring(path.lastIndexOf('/') + 1);\n        }\n        \n        public void processResult(int rc, String path, Object ctx, String name)\n        {\n            this.name = name;\n            super.processResult(Code.get(rc), path, ctx);\n        }\n\n        public AsyncCB create() {\n            zk.create(path, data, acl, flags, this, toString());\n            return this;\n        }\n\n        public AsyncCB createEphemeral() {\n            zk.create(path, data, acl, CreateMode.EPHEMERAL, this, toString());\n            return this;\n        }\n        \n        public void verifyCreate() {\n            create();\n            verify();\n        }\n\n        public void verifyCreateEphemeral() {\n            createEphemeral();\n            verify();\n        }\n        \n        public void verifyCreateFailure_NodeExists() {\n            new StringCB(zk).verifyCreate();\n            \n            rc = Code.NODEEXISTS;\n            name = null;\n            zk.create(path, data, acl, flags, this, toString());\n            verify();\n        }\n\n        public void verifyCreateFailure_NoNode() {\n\n            rc = Code.NONODE;\n            name = null;\n            path = path + \"/bar\";\n            zk.create(path, data, acl, flags, this, toString());\n\n            verify();\n        }\n\n        public void verifyCreateFailure_NoChildForEphemeral() {\n            new StringCB(zk).verifyCreateEphemeral();\n\n            rc = Code.NOCHILDRENFOREPHEMERALS;\n            name = null;\n            path = path + \"/bar\";\n            zk.create(path, data, acl, flags, this, toString());\n\n            verify();\n        }\n\n        @Override\n        public String toString() {\n            return super.toString() + name; \n        }\n    }\n\n    public static class ACLCB extends AsyncCB implements ACLCallback {\n        List<ACL> acl = Ids.CREATOR_ALL_ACL;\n        int version = 0;\n        Stat stat = new Stat();\n        byte[] data = \"testing\".getBytes();\n        \n        ACLCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n\n        ACLCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n            stat.setAversion(0);\n            stat.setCversion(0);\n            stat.setEphemeralOwner(0);\n            stat.setVersion(0);\n        }\n\n        public void processResult(int rc, String path, Object ctx,\n                List<ACL> acl, Stat stat)\n        {\n            this.acl = acl;\n            this.stat = stat;\n            super.processResult(Code.get(rc), path, ctx);\n        }\n        \n        public void verifyGetACL() {\n            new StringCB(zk).verifyCreate();\n\n            zk.getACL(path, stat, this, toString());\n            verify();\n        }\n\n        public void verifyGetACLFailure_NoNode(){\n            rc = Code.NONODE;\n            stat = null;\n            acl = null;\n            zk.getACL(path, stat, this, toString());\n\n            verify();\n        }\n        \n        public String toString(List<ACL> acls) {\n            if (acls == null) {\n                return \"\";\n            }\n\n            StringBuilder result = new StringBuilder();\n            for(ACL acl : acls) {\n                result.append(acl.getPerms() + \"::\");\n            }\n            return result.toString();\n        }\n        \n        @Override\n        public String toString() {\n            return super.toString() + toString(acl) + \":\" \n                + \":\" + version + \":\" + new String(data)\n                + \":\" + (stat == null ? \"null\" : stat.getAversion() + \":\" \n                        + stat.getCversion() + \":\" + stat.getEphemeralOwner()\n                        + \":\" + stat.getVersion()); \n        }\n    }\n\n    public static class ChildrenCB extends AsyncCB implements ChildrenCallback {\n        List<String> children = new ArrayList<String>();\n        \n        ChildrenCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n\n        ChildrenCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n        }\n        \n        public void processResult(int rc, String path, Object ctx,\n                List<String> children)\n        {\n            this.children =\n                (children == null ? new ArrayList<String>() : children);\n            Collections.sort(this.children);\n            super.processResult(Code.get(rc), path, ctx);\n        }\n        \n        public StringCB createNode() {\n            StringCB parent = new StringCB(zk);\n            parent.verifyCreate();\n\n            return parent;\n        }\n        \n        public StringCB createNode(StringCB parent) {\n            String childName = \"bar\";\n\n            return createNode(parent, childName);\n        }\n\n        public StringCB createNode(StringCB parent, String childName) {\n            StringCB child = new StringCB(zk);\n            child.setPath(parent.path + \"/\" + childName);\n            child.verifyCreate();\n            \n            return child;\n        }\n        \n        public void verifyGetChildrenEmpty() {\n            StringCB parent = createNode();\n            path = parent.path;\n            verify();\n        }\n\n        public void verifyGetChildrenSingle() {\n            StringCB parent = createNode();\n            StringCB child = createNode(parent);\n\n            path = parent.path;\n            children.add(child.nodeName());\n            \n            verify();\n        }\n        \n        public void verifyGetChildrenTwo() {\n            StringCB parent = createNode();\n            StringCB child1 = createNode(parent, \"child1\");\n            StringCB child2 = createNode(parent, \"child2\");\n        \n            path = parent.path;\n            children.add(child1.nodeName());\n            children.add(child2.nodeName());\n            \n            verify();\n        }\n        \n        public void verifyGetChildrenFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            verify();\n        }\n        \n        @Override\n        public void verify() {\n            zk.getChildren(path, false, this, toString());\n            super.verify();\n        }\n\n        @Override\n        public String toString() {\n            return super.toString() + children.toString();\n        }\n    }\n\n    public static class Children2CB extends AsyncCB implements Children2Callback {\n        List<String> children = new ArrayList<String>();\n\n        Children2CB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n\n        Children2CB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n        }\n\n        public void processResult(int rc, String path, Object ctx,\n                List<String> children, Stat stat)\n        {\n            this.children =\n                (children == null ? new ArrayList<String>() : children);\n            Collections.sort(this.children);\n            super.processResult(Code.get(rc), path, ctx);\n        }\n        \n        public StringCB createNode() {\n            StringCB parent = new StringCB(zk);\n            parent.verifyCreate();\n\n            return parent;\n        }\n        \n        public StringCB createNode(StringCB parent) {\n            String childName = \"bar\";\n\n            return createNode(parent, childName);\n        }\n\n        public StringCB createNode(StringCB parent, String childName) {\n            StringCB child = new StringCB(zk);\n            child.setPath(parent.path + \"/\" + childName);\n            child.verifyCreate();\n            \n            return child;\n        }\n        \n        public void verifyGetChildrenEmpty() {\n            StringCB parent = createNode();\n            path = parent.path;\n            verify();\n        }\n\n        public void verifyGetChildrenSingle() {\n            StringCB parent = createNode();\n            StringCB child = createNode(parent);\n\n            path = parent.path;\n            children.add(child.nodeName());\n            \n            verify();\n        }\n        \n        public void verifyGetChildrenTwo() {\n            StringCB parent = createNode();\n            StringCB child1 = createNode(parent, \"child1\");\n            StringCB child2 = createNode(parent, \"child2\");\n        \n            path = parent.path;\n            children.add(child1.nodeName());\n            children.add(child2.nodeName());\n            \n            verify();\n        }\n        \n        public void verifyGetChildrenFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            verify();\n        }\n        \n        @Override\n        public void verify() {\n            zk.getChildren(path, false, this, toString());\n            super.verify();\n        }\n        \n        @Override\n        public String toString() {\n            return super.toString() + children.toString(); \n        }\n    }\n\n    public static class DataCB extends AsyncCB implements DataCallback {\n        byte[] data = new byte[10];\n        Stat stat = new Stat();\n        \n        DataCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n\n        DataCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n            stat.setAversion(0);\n            stat.setCversion(0);\n            stat.setEphemeralOwner(0);\n            stat.setVersion(0);\n        }\n        \n        public void processResult(int rc, String path, Object ctx, byte[] data,\n                Stat stat)\n        {\n            this.data = data;\n            this.stat = stat;\n            super.processResult(Code.get(rc), path, ctx);\n        }\n        \n        public void verifyGetData() {\n            new StringCB(zk).verifyCreate();\n\n            zk.getData(path, false, this, toString());\n            verify();\n        }\n        \n        public void verifyGetDataFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            data = null;\n            stat = null;\n            zk.getData(path, false, this, toString());\n            verify();\n        }\n        \n        @Override\n        public String toString() {\n            return super.toString()\n                + \":\" + (data == null ? \"null\" : new String(data))\n                + \":\" + (stat == null ? \"null\" : stat.getAversion() + \":\" \n                    + stat.getCversion() + \":\" + stat.getEphemeralOwner()\n                    + \":\" + stat.getVersion()); \n        }\n    }\n\n    public static class StatCB extends AsyncCB implements StatCallback {\n        List<ACL> acl = Ids.CREATOR_ALL_ACL;\n        int version = 0;\n        Stat stat = new Stat();\n        byte[] data = \"testing\".getBytes();\n        \n        StatCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n\n        StatCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n            stat.setAversion(0);\n            stat.setCversion(0);\n            stat.setEphemeralOwner(0);\n            stat.setVersion(0);\n        }\n        \n        public void processResult(int rc, String path, Object ctx, Stat stat) {\n            this.stat = stat;\n            super.processResult(Code.get(rc), path, ctx);\n        }\n        \n        public void verifySetACL() {\n            stat.setAversion(1);\n            new StringCB(zk).verifyCreate();\n\n            zk.setACL(path, acl, version, this, toString());\n            verify();\n        }\n        \n        public void verifySetACLFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            stat = null;\n            zk.setACL(path, acl, version, this, toString());\n            verify();\n        }\n\n        public void verifySetACLFailure_BadVersion() {\n            new StringCB(zk).verifyCreate();\n\n            rc = Code.BADVERSION;\n            stat = null;\n            zk.setACL(path, acl, version + 1, this, toString());\n\n            verify();\n        }\n        \n        public void setData() {\n            zk.setData(path, data, version, this, toString());\n        }\n        \n        public void verifySetData() {\n            stat.setVersion(1);\n            new StringCB(zk).verifyCreate();\n\n            setData();\n            verify();\n        }\n        \n        public void verifySetDataFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            stat = null;\n            zk.setData(path, data, version, this, toString());\n            verify();\n        }\n\n        public void verifySetDataFailure_BadVersion() {\n            new StringCB(zk).verifyCreate();\n\n            rc = Code.BADVERSION;\n            stat = null;\n            zk.setData(path, data, version + 1, this, toString());\n\n            verify();\n        }\n        \n        public void verifyExists() {\n            new StringCB(zk).verifyCreate();\n\n            zk.exists(path, false, this, toString());\n            verify();\n        }\n        \n        public void verifyExistsFailure_NoNode() {\n            rc = KeeperException.Code.NONODE;\n            stat = null;\n            zk.exists(path, false, this, toString());\n            verify();\n        }\n        \n        @Override\n        public String toString() {\n            return super.toString() + version\n                + \":\" + new String(data)\n                + \":\" + (stat == null ? \"null\" : stat.getAversion() + \":\" \n                        + stat.getCversion() + \":\" + stat.getEphemeralOwner()\n                        + \":\" + stat.getVersion()); \n        }\n    }\n\n    public static class VoidCB extends AsyncCB implements VoidCallback {\n        int version = 0;\n        \n        VoidCB(ZooKeeper zk) {\n            this(zk, new CountDownLatch(1));\n        }\n        \n        VoidCB(ZooKeeper zk, CountDownLatch latch) {\n            super(zk, latch);\n        }\n        \n        public void processResult(int rc, String path, Object ctx) {\n            super.processResult(Code.get(rc), path, ctx);\n        }\n\n        public void delete() {\n            zk.delete(path, version, this, toString());\n        }\n        \n        public void verifyDelete() {\n            new StringCB(zk).verifyCreate();\n\n            delete();\n            verify();\n        }\n        \n        public void verifyDeleteFailure_NoNode() {\n            rc = Code.NONODE;\n            zk.delete(path, version, this, toString());\n            verify();\n        }\n\n        public void verifyDeleteFailure_BadVersion() {\n            new StringCB(zk).verifyCreate();\n            rc = Code.BADVERSION;\n            zk.delete(path, version + 1, this, toString());\n            verify();\n        }\n\n        public void verifyDeleteFailure_NotEmpty() {\n            StringCB scb = new StringCB(zk);\n            scb.create();\n            scb.setPath(path + \"/bar\");\n            scb.create();\n\n            rc = Code.NOTEMPTY;\n            zk.delete(path, version, this, toString());\n            verify();\n        }\n        \n        public void sync() {\n            zk.sync(path, this, toString());\n        }\n        \n        public void verifySync() {\n            sync();\n            verify();\n        }\n        \n        @Override\n        public String toString() {\n            return super.toString() + version; \n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AsyncOpsTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.AsyncOps.ACLCB;\nimport org.apache.zookeeper.test.AsyncOps.Children2CB;\nimport org.apache.zookeeper.test.AsyncOps.ChildrenCB;\nimport org.apache.zookeeper.test.AsyncOps.DataCB;\nimport org.apache.zookeeper.test.AsyncOps.StatCB;\nimport org.apache.zookeeper.test.AsyncOps.StringCB;\nimport org.apache.zookeeper.test.AsyncOps.VoidCB;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class AsyncOpsTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory.getLogger(AsyncOpsTest.class);\n\n    private ZooKeeper zk;\n\n    @Before\n    @Override\n    public void setUp() throws Exception {\n        super.setUp();\n\n        LOG.info(\"Creating client \" + getTestName());\n\n        zk = createClient();\n        zk.addAuthInfo(\"digest\", \"ben:passwd\".getBytes());\n    }\n\n    @After\n    @Override\n    public void tearDown() throws Exception {\n        zk.close();\n\n        super.tearDown();\n\n        LOG.info(\"Test clients shutting down\");\n    }\n\n    @Test\n    public void testAsyncCreate() {\n        new StringCB(zk).verifyCreate();\n    }\n\n    @Test\n    public void testAsyncCreateThree() {\n        CountDownLatch latch = new CountDownLatch(3);\n\n        StringCB op1 = new StringCB(zk, latch);\n        op1.setPath(\"/op1\");\n        StringCB op2 = new StringCB(zk, latch);\n        op2.setPath(\"/op2\");\n        StringCB op3 = new StringCB(zk, latch);\n        op3.setPath(\"/op3\");\n\n        op1.create();\n        op2.create();\n        op3.create();\n\n        op1.verify();\n        op2.verify();\n        op3.verify();\n    }\n\n    @Test\n    public void testAsyncCreateFailure_NodeExists() {\n        new StringCB(zk).verifyCreateFailure_NodeExists();\n    }\n\n    @Test\n    public void testAsyncCreateFailure_NoNode() {\n        new StringCB(zk).verifyCreateFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncCreateFailure_NoChildForEphemeral() {\n        new StringCB(zk).verifyCreateFailure_NoChildForEphemeral();\n    }\n\n    @Test\n    public void testAsyncDelete() {\n        new VoidCB(zk).verifyDelete();\n    }\n\n    @Test\n    public void testAsyncDeleteFailure_NoNode() {\n        new VoidCB(zk).verifyDeleteFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncDeleteFailure_BadVersion() {\n        new VoidCB(zk).verifyDeleteFailure_BadVersion();\n    }\n\n    @Test\n    public void testAsyncDeleteFailure_NotEmpty() {\n        new VoidCB(zk).verifyDeleteFailure_NotEmpty();\n    }\n\n    @Test\n    public void testAsyncSync() {\n        new VoidCB(zk).verifySync();\n    }\n\n    @Test\n    public void testAsyncSetACL() {\n        new StatCB(zk).verifySetACL();\n    }\n\n    @Test\n    public void testAsyncSetACLFailure_NoNode() {\n        new StatCB(zk).verifySetACLFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncSetACLFailure_BadVersion() {\n        new StatCB(zk).verifySetACLFailure_BadVersion();\n    }\n\n    @Test\n    public void testAsyncSetData() {\n        new StatCB(zk).verifySetData();\n    }\n\n    @Test\n    public void testAsyncSetDataFailure_NoNode() {\n        new StatCB(zk).verifySetDataFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncSetDataFailure_BadVersion() {\n        new StatCB(zk).verifySetDataFailure_BadVersion();\n    }\n\n    @Test\n    public void testAsyncExists() {\n        new StatCB(zk).verifyExists();\n    }\n\n    @Test\n    public void testAsyncExistsFailure_NoNode() {\n        new StatCB(zk).verifyExistsFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncGetACL() {\n        new ACLCB(zk).verifyGetACL();\n    }\n\n    @Test\n    public void testAsyncGetACLFailure_NoNode() {\n        new ACLCB(zk).verifyGetACLFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncGetChildrenEmpty() {\n        new ChildrenCB(zk).verifyGetChildrenEmpty();\n    }\n\n    @Test\n    public void testAsyncGetChildrenSingle() {\n        new ChildrenCB(zk).verifyGetChildrenSingle();\n    }\n\n    @Test\n    public void testAsyncGetChildrenTwo() {\n        new ChildrenCB(zk).verifyGetChildrenTwo();\n    }\n\n    @Test\n    public void testAsyncGetChildrenFailure_NoNode() {\n        new ChildrenCB(zk).verifyGetChildrenFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncGetChildren2Empty() {\n        new Children2CB(zk).verifyGetChildrenEmpty();\n    }\n\n    @Test\n    public void testAsyncGetChildren2Single() {\n        new Children2CB(zk).verifyGetChildrenSingle();\n    }\n\n    @Test\n    public void testAsyncGetChildren2Two() {\n        new Children2CB(zk).verifyGetChildrenTwo();\n    }\n\n    @Test\n    public void testAsyncGetChildren2Failure_NoNode() {\n        new Children2CB(zk).verifyGetChildrenFailure_NoNode();\n    }\n\n    @Test\n    public void testAsyncGetData() {\n        new DataCB(zk).verifyGetData();\n    }\n\n    @Test\n    public void testAsyncGetDataFailure_NoNode() {\n        new DataCB(zk).verifyGetDataFailure_NoNode();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AsyncTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.IOException;\nimport java.util.LinkedList;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class AsyncTest extends ZKTestCase\n    implements StringCallback, VoidCallback, DataCallback\n{\n    private static final Logger LOG = LoggerFactory.getLogger(AsyncTest.class);\n\n    private QuorumBase qb = new QuorumBase();\n\n    @Before\n    public void setUp() throws Exception {\n        qb.setUp();\n    }\n\n    public void restart() throws Exception {\n        JMXEnv.setUp();\n        qb.startServers();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        LOG.info(\"Test clients shutting down\");\n        qb.tearDown();\n    }\n\n    private static class CountdownWatcher implements Watcher {\n        volatile CountDownLatch clientConnected = new CountDownLatch(1);\n\n        public void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.SyncConnected) {\n                clientConnected.countDown();\n            }\n        }\n    }\n\n    private ZooKeeper createClient() throws IOException,InterruptedException {\n        return createClient(qb.hostPort);\n    }\n\n    private ZooKeeper createClient(String hp)\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(hp, CONNECTION_TIMEOUT, watcher);\n        if(!watcher.clientConnected.await(CONNECTION_TIMEOUT,\n                TimeUnit.MILLISECONDS))\n        {\n            Assert.fail(\"Unable to connect to server\");\n        }\n        return zk;\n    }\n\n    LinkedList<Integer> results = new LinkedList<Integer>();\n    @Test\n    public void testAsync()\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk = null;\n        zk = createClient();\n        try {\n            zk.addAuthInfo(\"digest\", \"ben:passwd\".getBytes());\n            zk.create(\"/ben\", new byte[0], Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT, this, results);\n            zk.create(\"/ben/2\", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT, this, results);\n            zk.delete(\"/ben\", -1, this, results);\n            zk.create(\"/ben2\", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT, this, results);\n            zk.getData(\"/ben2\", false, this, results);\n            synchronized (results) {\n                while (results.size() < 5) {\n                    results.wait();\n                }\n            }\n            Assert.assertEquals(0, (int) results.get(0));\n            Assert.assertEquals(Code.NOAUTH, Code.get(results.get(1)));\n            Assert.assertEquals(0, (int) results.get(2));\n            Assert.assertEquals(0, (int) results.get(3));\n            Assert.assertEquals(0, (int) results.get(4));\n        } finally {\n            zk.close();\n        }\n\n        zk = createClient();\n        try {\n            zk.addAuthInfo(\"digest\", \"ben:passwd2\".getBytes());\n            try {\n                zk.getData(\"/ben2\", false, new Stat());\n                Assert.fail(\"Should have received a permission error\");\n            } catch (KeeperException e) {\n                Assert.assertEquals(Code.NOAUTH, e.code());\n            }\n        } finally {\n            zk.close();\n        }\n\n        zk = createClient();\n        try {\n            zk.addAuthInfo(\"digest\", \"ben:passwd\".getBytes());\n            zk.getData(\"/ben2\", false, new Stat());\n        } finally {\n            zk.close();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx, String name) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx, byte[] data,\n            Stat stat) {\n        synchronized(ctx) {\n            ((LinkedList<Integer>)ctx).add(rc);\n            ctx.notifyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AtomicFileOutputStreamTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.common.AtomicFileOutputStream;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class AtomicFileOutputStreamTest extends ZKTestCase {\n    private static final String TEST_STRING = \"hello world\";\n    private static final String TEST_STRING_2 = \"goodbye world\";\n\n    private File testDir;\n    private File dstFile;\n\n    @Before\n    public void setupTestDir() throws IOException {\n        testDir = ClientBase.createEmptyTestDir();\n        dstFile = new File(testDir, \"test.txt\");\n    }\n    @After\n    public void cleanupTestDir() throws IOException {\n        ClientBase.recursiveDelete(testDir);\n    }\n\n    /**\n     * Test case where there is no existing file\n     */\n    @Test\n    public void testWriteNewFile() throws IOException {\n        OutputStream fos = new AtomicFileOutputStream(dstFile);\n        assertFalse(dstFile.exists());\n        fos.write(TEST_STRING.getBytes());\n        fos.flush();\n        assertFalse(dstFile.exists());\n        fos.close();\n        assertTrue(dstFile.exists());\n\n        String readBackData = ClientBase.readFile(dstFile);\n        assertEquals(TEST_STRING, readBackData);\n    }\n\n    /**\n     * Test case where there is no existing file\n     */\n    @Test\n    public void testOverwriteFile() throws IOException {\n        assertTrue(\"Creating empty dst file\", dstFile.createNewFile());\n\n        OutputStream fos = new AtomicFileOutputStream(dstFile);\n\n        assertTrue(\"Empty file still exists\", dstFile.exists());\n        fos.write(TEST_STRING.getBytes());\n        fos.flush();\n\n        // Original contents still in place\n        assertEquals(\"\", ClientBase.readFile(dstFile));\n\n        fos.close();\n\n        // New contents replace original file\n        String readBackData = ClientBase.readFile(dstFile);\n        assertEquals(TEST_STRING, readBackData);\n    }\n\n    /**\n     * Test case where the flush() fails at close time - make sure that we clean\n     * up after ourselves and don't touch any existing file at the destination\n     */\n    @Test\n    public void testFailToFlush() throws IOException {\n        // Create a file at destination\n        FileOutputStream fos = new FileOutputStream(dstFile);\n        fos.write(TEST_STRING_2.getBytes());\n        fos.close();\n\n        OutputStream failingStream = createFailingStream();\n        failingStream.write(TEST_STRING.getBytes());\n        try {\n            failingStream.close();\n            fail(\"Close didn't throw exception\");\n        } catch (IOException ioe) {\n            // expected\n        }\n\n        // Should not have touched original file\n        assertEquals(TEST_STRING_2, ClientBase.readFile(dstFile));\n\n        assertEquals(\"Temporary file should have been cleaned up\",\n                dstFile.getName(), ClientBase.join(\",\", testDir.list()));\n    }\n\n    /**\n     * Create a stream that fails to flush at close time\n     */\n    private OutputStream createFailingStream() throws FileNotFoundException {\n        return new AtomicFileOutputStream(dstFile) {\n            @Override\n            public void flush() throws IOException {\n                throw new IOException(\"injected failure\");\n            }\n        };\n    }\n\n    /**\n     * Ensure the tmp file is cleaned up and dstFile is not created when\n     * aborting a new file.\n     */\n    @Test\n    public void testAbortNewFile() throws IOException {\n        AtomicFileOutputStream fos = new AtomicFileOutputStream(dstFile);\n\n        fos.abort();\n\n        assertEquals(0, testDir.list().length);\n    }\n\n    /**\n     * Ensure the tmp file is cleaned up and dstFile is not created when\n     * aborting a new file.\n     */\n    @Test\n    public void testAbortNewFileAfterFlush() throws IOException {\n        AtomicFileOutputStream fos = new AtomicFileOutputStream(dstFile);\n        fos.write(TEST_STRING.getBytes());\n        fos.flush();\n\n        fos.abort();\n\n        assertEquals(0, testDir.list().length);\n    }\n\n    /**\n     * Ensure the tmp file is cleaned up and dstFile is untouched when\n     * aborting an existing file overwrite.\n     */\n    @Test\n    public void testAbortExistingFile() throws IOException {\n        FileOutputStream fos1 = new FileOutputStream(dstFile);\n        fos1.write(TEST_STRING.getBytes());\n        fos1.close();\n\n        AtomicFileOutputStream fos2 = new AtomicFileOutputStream(dstFile);\n\n        fos2.abort();\n\n        // Should not have touched original file\n        assertEquals(TEST_STRING, ClientBase.readFile(dstFile));\n        assertEquals(1, testDir.list().length);\n    }\n\n    /**\n     * Ensure the tmp file is cleaned up and dstFile is untouched when\n     * aborting an existing file overwrite.\n     */\n    @Test\n    public void testAbortExistingFileAfterFlush() throws IOException {\n        FileOutputStream fos1 = new FileOutputStream(dstFile);\n        fos1.write(TEST_STRING.getBytes());\n        fos1.close();\n\n        AtomicFileOutputStream fos2 = new AtomicFileOutputStream(dstFile);\n        fos2.write(TEST_STRING_2.getBytes());\n        fos2.flush();\n\n        fos2.abort();\n\n        // Should not have touched original file\n        assertEquals(TEST_STRING, ClientBase.readFile(dstFile));\n        assertEquals(1, testDir.list().length);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/AuthTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class AuthTest extends ClientBase {\n    static {\n        // password is test\n        System.setProperty(\"zookeeper.DigestAuthenticationProvider.superDigest\",\n                \"super:D/InIHSb7yEEbrWz8b9l71RjZJU=\");    \n        System.setProperty(\"zookeeper.authProvider.1\", \"org.apache.zookeeper.test.InvalidAuthProvider\");\n    }\n\n    private final CountDownLatch authFailed = new CountDownLatch(1);\n\n    @Override\n    protected TestableZooKeeper createClient(String hp)\n    throws IOException, InterruptedException\n    {\n        MyWatcher watcher = new MyWatcher();\n        return createClient(watcher, hp);\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                authFailed.countDown();\n            }\n            else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testBadAuthNotifiesWatch() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.addAuthInfo(\"FOO\", \"BAR\".getBytes());\n            zk.getData(\"/path1\", false, null);\n            Assert.fail(\"Should get auth state error\");\n        } catch(KeeperException.AuthFailedException e) {\n            if(!authFailed.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS))\n            {\n                Assert.fail(\"Should have called my watcher\");\n            }\n        }\n        finally {\n            zk.close();\n        }\n    }\n    \n    @Test\n    public void testBadAuthThenSendOtherCommands() throws Exception {\n        ZooKeeper zk = createClient();     \n        try {        \n            zk.addAuthInfo(\"INVALID\", \"BAR\".getBytes());\n            zk.exists(\"/foobar\", false);             \n            zk.getData(\"/path1\", false, null);\n            Assert.fail(\"Should get auth state error\");\n        } catch(KeeperException.AuthFailedException e) {\n            if(!authFailed.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS))\n            {\n                Assert.fail(\"Should have called my watcher\");\n            }\n        }\n        finally {\n            zk.close();          \n        }\n    }\n\n    \n    @Test\n    public void testSuper() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.addAuthInfo(\"digest\", \"pat:pass\".getBytes());\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL,\n                    CreateMode.PERSISTENT);\n            zk.close();\n            // verify no auth\n            zk = createClient();\n            try {\n                zk.getData(\"/path1\", false, null);\n                Assert.fail(\"auth verification\");\n            } catch (KeeperException.NoAuthException e) {\n                // expected\n            }\n            zk.close();\n            // verify bad pass Assert.fails\n            zk = createClient();\n            zk.addAuthInfo(\"digest\", \"pat:pass2\".getBytes());\n            try {\n                zk.getData(\"/path1\", false, null);\n                Assert.fail(\"auth verification\");\n            } catch (KeeperException.NoAuthException e) {\n                // expected\n            }\n            zk.close();\n            // verify super with bad pass Assert.fails\n            zk = createClient();\n            zk.addAuthInfo(\"digest\", \"super:test2\".getBytes());\n            try {\n                zk.getData(\"/path1\", false, null);\n                Assert.fail(\"auth verification\");\n            } catch (KeeperException.NoAuthException e) {\n                // expected\n            }\n            zk.close();\n            // verify super with correct pass success\n            zk = createClient();\n            zk.addAuthInfo(\"digest\", \"super:test\".getBytes());\n            zk.getData(\"/path1\", false, null);\n        } finally {\n            zk.close();\n        }\n    }\n    \n    @Test\n    public void testSuperACL() throws Exception {\n    \t ZooKeeper zk = createClient();\n         try {\n             zk.addAuthInfo(\"digest\", \"pat:pass\".getBytes());\n             zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL,\n                     CreateMode.PERSISTENT);\n             zk.close();\n             // verify super can do anything and ignores ACLs\n             zk = createClient();\n             zk.addAuthInfo(\"digest\", \"super:test\".getBytes());\n             zk.getData(\"/path1\", false, null);\n             \n             zk.setACL(\"/path1\", Ids.READ_ACL_UNSAFE, -1);\n             zk.create(\"/path1/foo\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n           \n             \n             zk.setACL(\"/path1\", Ids.OPEN_ACL_UNSAFE, -1);\n        \t \n         } finally {\n             zk.close();\n         }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/BufferSizeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class BufferSizeTest extends ClientBase {\n    public static final int TEST_MAXBUFFER = 100;\n    private static final File TEST_DATA = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"),\n            \"buffersize\");\n    \n    private ZooKeeper zk;\n\n    @Before\n    public void setMaxBuffer() throws IOException, InterruptedException {\n        System.setProperty(\"jute.maxbuffer\", \"\" + TEST_MAXBUFFER);\n        assertEquals(\"Can't set jute.maxbuffer!\", TEST_MAXBUFFER, BinaryInputArchive.maxBuffer);\n        zk = createClient();\n    }\n    \n    @Test\n    public void testCreatesReqs() throws Exception {\n        testRequests(new ClientOp() {\n            @Override\n            public void execute(byte[] data) throws Exception {\n                zk.create(\"/create_test\", data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            }\n        });\n    }\n    \n    @Test\n    public void testSetReqs() throws Exception {\n        final String path = \"/set_test\";\n        zk.create(path, new byte[1], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        testRequests(new ClientOp() {\n            @Override\n            public void execute(byte[] data) throws Exception {\n                zk.setData(path, data, -1);\n            }\n        });\n    }\n    \n    /** Issues requests containing data smaller, equal, and greater than TEST_MAXBUFFER. */\n    private void testRequests(ClientOp clientOp) throws Exception {\n        clientOp.execute(new byte[TEST_MAXBUFFER - 60]);\n        try {\n            // This should fail since the buffer size > the data size due to extra fields\n            clientOp.execute(new byte[TEST_MAXBUFFER]);\n            fail(\"Request exceeding jute.maxbuffer succeeded!\");\n        } catch (KeeperException.ConnectionLossException e) {}\n        try {\n            clientOp.execute(new byte[TEST_MAXBUFFER + 10]);\n            fail(\"Request exceeding jute.maxbuffer succeeded!\");\n        } catch (KeeperException.ConnectionLossException e) {}\n    }\n\n    private interface ClientOp {\n        void execute(byte[] data) throws Exception;\n    }\n\n    @Test\n    public void testStartup() throws Exception {\n        final String path = \"/test_node\";\n        zk.create(path, new byte[TEST_MAXBUFFER - 60], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.setData(path, new byte[TEST_MAXBUFFER - 50], -1);\n\n        stopServer();\n        startServer();\n    }\n    \n    @Test\n    public void testStartupFailureCreate() throws Exception {\n        // Empty snapshot and logfile containing a 5000-byte create\n        testStartupFailure(new File(TEST_DATA, \"create\"),\n                \"Server started despite create exceeding jute.maxbuffer!\");\n    }\n    \n    @Test\n    public void testStartupFailureSet() throws Exception {\n        // Empty snapshot and logfile containing a 1-byte create and 5000-byte set\n        testStartupFailure(new File(TEST_DATA, \"set\"),\n                \"Server started despite set exceeding jute.maxbuffer!\");\n    }\n    \n    @Test\n    public void testStartupFailureSnapshot() throws Exception {\n        // Snapshot containing 5000-byte znode and logfile containing create txn\n        testStartupFailure(new File(TEST_DATA, \"snapshot\"),\n                \"Server started despite znode exceeding jute.maxbuffer!\");\n    }\n    \n    private void testStartupFailure(File testDir, String failureMsg) throws Exception {\n        stopServer();\n        // Point server at testDir\n        tmpDir = testDir;\n        try {\n            startServer();\n            fail(failureMsg);\n        } catch (IOException e) {\n            LOG.info(\"Successfully caught IOException: \" + e);\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ChrootAsyncTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\n\npublic class ChrootAsyncTest extends AsyncOpsTest {\n    private static final Logger LOG = LoggerFactory.getLogger(ChrootAsyncTest.class);\n\n    @Override\n    public void setUp() throws Exception {\n        String hp = hostPort;\n        hostPort = hostPort + \"/chrootasynctest\";\n\n        super.setUp();\n\n        LOG.info(\"Creating client \" + getTestName());\n\n        ZooKeeper zk = createClient(hp);\n        try {\n            zk.create(\"/chrootasynctest\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ChrootClientTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Test;\n\npublic class ChrootClientTest extends ClientTest {\n    private static final Logger LOG = LoggerFactory.getLogger(ChrootClientTest.class);\n\n    @Override\n    public void setUp() throws Exception {\n        String hp = hostPort;\n        hostPort = hostPort + \"/chrootclienttest\";\n\n        System.out.println(hostPort);\n        super.setUp();\n\n        LOG.info(\"STARTING \" + getTestName());\n\n        ZooKeeper zk = createClient(hp);\n        try {\n            zk.create(\"/chrootclienttest\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        } finally {\n            zk.close();\n        }\n    }\n    \n    @Test\n    public void testPing() throws Exception {\n        // not necessary to repeat this, expensive and not chroot related\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ChrootTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ChrootTest extends ClientBase {\n    private class MyWatcher implements Watcher {\n        private final String path;\n        private String eventPath;\n        private CountDownLatch latch = new CountDownLatch(1);\n\n        public MyWatcher(String path) {\n            this.path = path;\n        }\n        public void process(WatchedEvent event) {\n            System.out.println(\"latch:\" + path + \" \" + event.getPath());\n            this.eventPath = event.getPath();\n            latch.countDown();\n        }\n        public boolean matches() throws InterruptedException {\n            if (!latch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)) {\n                Assert.fail(\"No watch received within timeout period \" + path);\n            }\n            return path.equals(eventPath);\n        }\n    }\n\n    @Test\n    public void testChrootSynchronous()\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk1 = createClient();\n        try {\n            zk1.create(\"/ch1\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        } finally {\n            if(zk1 != null)\n                zk1.close();\n        }\n        ZooKeeper zk2 = createClient(hostPort + \"/ch1\");\n        try {\n            Assert.assertEquals(\"/ch2\",\n                    zk2.create(\"/ch2\", null, Ids.OPEN_ACL_UNSAFE,\n                            CreateMode.PERSISTENT));\n        } finally {\n            if(zk2 != null)\n                zk2.close();\n        }\n\n        zk1 = createClient();\n        zk2 = createClient(hostPort + \"/ch1\");\n        try {\n            // check get\n            MyWatcher w1 = new MyWatcher(\"/ch1\");\n            Assert.assertNotNull(zk1.exists(\"/ch1\", w1));\n            MyWatcher w2 = new MyWatcher(\"/ch1/ch2\");\n            Assert.assertNotNull(zk1.exists(\"/ch1/ch2\", w2));\n\n            MyWatcher w3 = new MyWatcher(\"/ch2\");\n            Assert.assertNotNull(zk2.exists(\"/ch2\", w3));\n            \n            // set watches on child\n            MyWatcher w4 = new MyWatcher(\"/ch1\");\n            zk1.getChildren(\"/ch1\",w4);\n            MyWatcher w5 = new MyWatcher(\"/\");\n            zk2.getChildren(\"/\",w5);\n\n            // check set\n            zk1.setData(\"/ch1\", \"1\".getBytes(), -1);\n            zk2.setData(\"/ch2\", \"2\".getBytes(), -1);\n\n            // check watches\n            Assert.assertTrue(w1.matches());\n            Assert.assertTrue(w2.matches());\n            Assert.assertTrue(w3.matches());\n\n            // check exceptions\n            try {\n                zk2.setData(\"/ch3\", \"3\".getBytes(), -1);\n            } catch (KeeperException.NoNodeException e) {\n                Assert.assertEquals(\"/ch3\", e.getPath());\n            }\n\n            Assert.assertTrue(Arrays.equals(\"1\".getBytes(),\n                    zk1.getData(\"/ch1\", false, null)));\n            Assert.assertTrue(Arrays.equals(\"2\".getBytes(),\n                    zk1.getData(\"/ch1/ch2\", false, null)));\n            Assert.assertTrue(Arrays.equals(\"2\".getBytes(),\n                    zk2.getData(\"/ch2\", false, null)));\n\n            // check delete\n            zk2.delete(\"/ch2\", -1);\n            Assert.assertTrue(w4.matches());\n            Assert.assertTrue(w5.matches());\n            \n            zk1.delete(\"/ch1\", -1);\n            Assert.assertNull(zk1.exists(\"/ch1\", false));\n            Assert.assertNull(zk1.exists(\"/ch1/ch2\", false));\n            Assert.assertNull(zk2.exists(\"/ch2\", false));\n        } finally {\n            if(zk1 != null)\n                zk1.close();\n            if(zk2 != null)\n                zk2.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ClientBase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport javax.management.MBeanServerConnection;\nimport javax.management.ObjectName;\n\nimport junit.framework.TestCase;\n\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.common.IOUtils;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ServerCnxnFactoryAccessor;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.util.OSMXBean;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class ClientBase extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(ClientBase.class);\n\n    public static int CONNECTION_TIMEOUT = 30000;\n    static final File BASETEST =\n        new File(System.getProperty(\"build.test.dir\", \"build\"));\n\n    protected int port = PortAssignment.unique();\n    protected String hostPort = \"127.0.0.1:\" + port;\n    protected String ipv6HostPort = \"[0:0:0:0:0:0:0:1]:\" + port;\n    protected int maxCnxns = 0;\n    protected ServerCnxnFactory serverFactory = null;\n    protected File tmpDir = null;\n    \n    long initialFdCount;\n    \n    public ClientBase() {\n        super();\n    }\n\n    /**\n     * In general don't use this. Only use in the special case that you\n     * want to ignore results (for whatever reason) in your test. Don't\n     * use empty watchers in real code!\n     *\n     */\n    protected class NullWatcher implements Watcher {\n        public void process(WatchedEvent event) { /* nada */ }\n    }\n\n    public static class CountdownWatcher implements Watcher {\n        // XXX this doesn't need to be volatile! (Should probably be final)\n        volatile CountDownLatch clientConnected;\n        // Set to true when connected to a read-only server, or a read-write (quorum) server.\n        volatile boolean connected;\n        // Set to true when connected to a quorum server.\n        volatile boolean syncConnected;\n        // Set to true when connected to a quorum server in read-only mode\n        volatile boolean readOnlyConnected;\n\n        public CountdownWatcher() {\n            reset();\n        }\n        synchronized public void reset() {\n            clientConnected = new CountDownLatch(1);\n            connected = false;\n            syncConnected = false;\n            readOnlyConnected = false;\n        }\n        synchronized public void process(WatchedEvent event) {\n            KeeperState state = event.getState();\n            if (state == KeeperState.SyncConnected) {\n                connected = true;\n                syncConnected = true;\n                readOnlyConnected = false;\n            } else if (state == KeeperState.ConnectedReadOnly) {\n                connected = true;\n                syncConnected = false;\n                readOnlyConnected = true;\n            } else {\n                connected = false;\n                syncConnected = false;\n                readOnlyConnected = false;\n            }\n\n            notifyAll();\n            if (connected) {\n                clientConnected.countDown();\n            }\n        }\n        synchronized public boolean isConnected() {\n            return connected;\n        }\n        synchronized public void waitForConnected(long timeout)\n            throws InterruptedException, TimeoutException\n        {\n            long expire = Time.currentElapsedTime() + timeout;\n            long left = timeout;\n            while(!connected && left > 0) {\n                wait(left);\n                left = expire - Time.currentElapsedTime();\n            }\n            if (!connected) {\n                throw new TimeoutException(\"Did not connect\");\n\n            }\n        }\n        synchronized public void waitForSyncConnected(long timeout)\n                throws InterruptedException, TimeoutException\n        {\n            long expire = System.currentTimeMillis() + timeout;\n            long left = timeout;\n            while(!syncConnected && left > 0) {\n                wait(left);\n                left = expire - System.currentTimeMillis();\n            }\n            if (!syncConnected) {\n                throw new TimeoutException(\"Failed to connect to read-write ZooKeeper server.\");\n            }\n        }\n        synchronized public void waitForReadOnlyConnected(long timeout)\n                throws InterruptedException, TimeoutException\n        {\n            long expire = System.currentTimeMillis() + timeout;\n            long left = timeout;\n            while(!readOnlyConnected && left > 0) {\n                wait(left);\n                left = expire - System.currentTimeMillis();\n            }\n            if (!readOnlyConnected) {\n                throw new TimeoutException(\"Failed to connect in read-only mode to ZooKeeper server.\");\n            }\n        }\n        synchronized public void waitForDisconnected(long timeout)\n            throws InterruptedException, TimeoutException\n        {\n            long expire = Time.currentElapsedTime() + timeout;\n            long left = timeout;\n            while(connected && left > 0) {\n                wait(left);\n                left = expire - Time.currentElapsedTime();\n            }\n            if (connected) {\n                throw new TimeoutException(\"Did not disconnect\");\n\n            }\n        }\n    }\n\n    protected TestableZooKeeper createClient()\n        throws IOException, InterruptedException\n    {\n        return createClient(hostPort);\n    }\n\n    protected TestableZooKeeper createClient(String hp)\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createClient(watcher, hp);\n    }\n\n    protected TestableZooKeeper createClient(CountdownWatcher watcher)\n        throws IOException, InterruptedException\n    {\n        return createClient(watcher, hostPort);\n    }\n\n    private LinkedList<ZooKeeper> allClients;\n    private boolean allClientsSetup = false;\n\n    protected TestableZooKeeper createClient(CountdownWatcher watcher, String hp)\n        throws IOException, InterruptedException\n    {\n        return createClient(watcher, hp, CONNECTION_TIMEOUT);\n    }\n\n    protected TestableZooKeeper createClient(CountdownWatcher watcher,\n            String hp, int timeout)\n        throws IOException, InterruptedException\n    {\n        watcher.reset();\n        TestableZooKeeper zk = new TestableZooKeeper(hp, timeout, watcher);\n        if (!watcher.clientConnected.await(timeout, TimeUnit.MILLISECONDS))\n        {\n            Assert.fail(\"Unable to connect to server\");\n        }\n        synchronized(this) {\n            if (!allClientsSetup) {\n                LOG.error(\"allClients never setup\");\n                Assert.fail(\"allClients never setup\");\n            }\n            if (allClients != null) {\n                allClients.add(zk);\n                JMXEnv.ensureAll(getHexSessionId(zk.getSessionId()));\n            } else {\n                // test done - close the zk, not needed\n                zk.close();\n            }\n        }\n\n        return zk;\n    }\n\n    public static class HostPort {\n        String host;\n        int port;\n        public HostPort(String host, int port) {\n            this.host = host;\n            this.port = port;\n        }\n    }\n    public static List<HostPort> parseHostPortList(String hplist) {\n        ArrayList<HostPort> alist = new ArrayList<HostPort>();\n        for (String hp: hplist.split(\",\")) {\n            int idx = hp.lastIndexOf(':');\n            String host = hp.substring(0, idx);\n            int port;\n            try {\n                port = Integer.parseInt(hp.substring(idx + 1));\n            } catch(RuntimeException e) {\n                throw new RuntimeException(\"Problem parsing \" + hp + e.toString());\n            }\n            alist.add(new HostPort(host,port));\n        }\n        return alist;\n    }\n\n    public static boolean waitForServerUp(String hp, long timeout) {\n        long start = Time.currentElapsedTime();\n        while (true) {\n            try {\n                // if there are multiple hostports, just take the first one\n                HostPort hpobj = parseHostPortList(hp).get(0);\n                String result = send4LetterWord(hpobj.host, hpobj.port, \"stat\");\n                if (result.startsWith(\"Zookeeper version:\") &&\n                        !result.contains(\"READ-ONLY\")) {\n                    return true;\n                }\n            } catch (IOException e) {\n                // ignore as this is expected\n                LOG.info(\"server \" + hp + \" not up \" + e);\n            }\n\n            if (Time.currentElapsedTime() > start + timeout) {\n                break;\n            }\n            try {\n                Thread.sleep(250);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n        return false;\n    }\n    public static boolean waitForServerDown(String hp, long timeout) {\n        long start = Time.currentElapsedTime();\n        while (true) {\n            try {\n                HostPort hpobj = parseHostPortList(hp).get(0);\n                send4LetterWord(hpobj.host, hpobj.port, \"stat\");\n            } catch (IOException e) {\n                return true;\n            }\n\n            if (Time.currentElapsedTime() > start + timeout) {\n                break;\n            }\n            try {\n                Thread.sleep(250);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n        return false;\n    }\n\n    public static boolean waitForServerState(QuorumPeer qp, int timeout,\n            String serverState) {\n        long start = Time.currentElapsedTime();\n        while (true) {\n            try {\n                Thread.sleep(250);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n            if (qp.getServerState().equals(serverState))\n                return true;\n            if (Time.currentElapsedTime() > start + timeout) {\n                return false;\n            }\n        }\n    }\n\n    static void verifyThreadTerminated(Thread thread, long millis)\n        throws InterruptedException\n    {\n        thread.join(millis);\n        if (thread.isAlive()) {\n            LOG.error(\"Thread \" + thread.getName() + \" : \"\n                    + Arrays.toString(thread.getStackTrace()));\n            Assert.assertFalse(\"thread \" + thread.getName()\n                    + \" still alive after join\", true);\n        }\n    }\n\n    public static File createEmptyTestDir() throws IOException {\n        return createTmpDir(BASETEST, false);\n    }\n\n    public static File createTmpDir() throws IOException {\n        return createTmpDir(BASETEST, true);\n    }\n\n    static File createTmpDir(File parentDir, boolean createInitFile) throws IOException {\n        File tmpFile = File.createTempFile(\"test\", \".junit\", parentDir);\n        // don't delete tmpFile - this ensures we don't attempt to create\n        // a tmpDir with a duplicate name\n        File tmpDir = new File(tmpFile + \".dir\");\n        Assert.assertFalse(tmpDir.exists()); // never true if tmpfile does it's job\n        Assert.assertTrue(tmpDir.mkdirs());\n\n        // todo not every tmp directory needs this file\n        if (createInitFile) {\n            createInitializeFile(tmpDir);\n        }\n\n        return tmpDir;\n    }\n\n    public static void createInitializeFile(File dir) throws IOException {\n        File initFile = new File(dir, \"initialize\");\n        if (!initFile.exists()) {\n            Assert.assertTrue(initFile.createNewFile());\n        }\n    }\n\n    private static int getPort(String hostPort) {\n        String[] split = hostPort.split(\":\");\n        String portstr = split[split.length-1];\n        String[] pc = portstr.split(\"/\");\n        if (pc.length > 1) {\n            portstr = pc[0];\n        }\n        return Integer.parseInt(portstr);\n    }\n\n    /**\n     * Starting the given server instance\n     */\n    public static void startServerInstance(File dataDir,\n            ServerCnxnFactory factory, String hostPort) throws IOException,\n            InterruptedException {\n        final int port = getPort(hostPort);\n        LOG.info(\"STARTING server instance 127.0.0.1:{}\", port);\n        ZooKeeperServer zks = new ZooKeeperServer(dataDir, dataDir, 3000);\n        factory.startup(zks);\n        Assert.assertTrue(\"waiting for server up\", ClientBase.waitForServerUp(\n                \"127.0.0.1:\" + port, CONNECTION_TIMEOUT));\n    }\n\n    /**\n     * This method instantiates a new server. Starting of the server\n     * instance has been moved to a separate method\n     * {@link ClientBase#startServerInstance(File, ServerCnxnFactory, String)}.\n     * Because any exception on starting the server would leave the server\n     * running and the caller would not be able to shutdown the instance. This\n     * may affect other test cases.\n     * \n     * @return newly created server instance\n     * \n     * @see <a\n     *      href=\"https://issues.apache.org/jira/browse/ZOOKEEPER-1852\">ZOOKEEPER-1852</a>\n     *      for more information.\n     */\n    public static ServerCnxnFactory createNewServerInstance(\n            ServerCnxnFactory factory, String hostPort, int maxCnxns)\n            throws IOException, InterruptedException {\n        final int port = getPort(hostPort);\n        LOG.info(\"CREATING server instance 127.0.0.1:{}\", port);\n        if (factory == null) {\n            factory = ServerCnxnFactory.createFactory(port, maxCnxns);\n        }\n        return factory;\n    }\n\n    static void shutdownServerInstance(ServerCnxnFactory factory,\n            String hostPort)\n    {\n        if (factory != null) {\n            ZKDatabase zkDb = null;\n            {\n                ZooKeeperServer zs = getServer(factory);\n                if (zs != null) {\n                    zkDb = zs.getZKDatabase();\n                }\n            }\n            factory.shutdown();\n            try {\n                if (zkDb != null) {\n                    zkDb.close();\n                }\n            } catch (IOException ie) {\n                LOG.warn(\"Error closing logs \", ie);\n            }\n            final int PORT = getPort(hostPort);\n\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(\"127.0.0.1:\" + PORT,\n                                                    CONNECTION_TIMEOUT));\n        }\n    }\n\n    /**\n     * Test specific setup\n     */\n    public static void setupTestEnv() {\n        // during the tests we run with 100K prealloc in the logs.\n        // on windows systems prealloc of 64M was seen to take ~15seconds\n        // resulting in test Assert.failure (client timeout on first session).\n        // set env and directly in order to handle static init/gc issues\n        System.setProperty(\"zookeeper.preAllocSize\", \"100\");\n        FileTxnLog.setPreallocSize(100 * 1024);\n    }\n\n    protected void setUpAll() throws Exception {\n        allClients = new LinkedList<ZooKeeper>();\n        allClientsSetup = true;\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        /* some useful information - log the number of fds used before\n         * and after a test is run. Helps to verify we are freeing resources\n         * correctly. Unfortunately this only works on unix systems (the\n         * only place sun has implemented as part of the mgmt bean api.\n         */\n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == true) {\n            initialFdCount = osMbean.getOpenFileDescriptorCount();  \t\n            LOG.info(\"Initial fdcount is: \"\n                    + initialFdCount);\n        }\n\n        setupTestEnv();\n\n        JMXEnv.setUp();\n\n        setUpAll();\n\n        tmpDir = createTmpDir(BASETEST, true);\n\n        startServer();\n\n        LOG.info(\"Client test setup finished\");\n    }\n\n    protected void startServer() throws Exception {\n        LOG.info(\"STARTING server\");\n        serverFactory = createNewServerInstance(serverFactory, hostPort,\n                maxCnxns);\n        startServerInstance(tmpDir, serverFactory, hostPort);\n        // ensure that server and data bean are registered\n        Set<ObjectName> children = JMXEnv.ensureParent(\"InMemoryDataTree\",\n                \"StandaloneServer_port\");\n        // Remove beans which are related to zk client sessions. Strong\n        // assertions cannot be done for these client sessions because\n        // registeration of these beans with server will happen only on their\n        // respective reconnection interval\n        verifyUnexpectedBeans(children);\n    }\n\n    private void verifyUnexpectedBeans(Set<ObjectName> children) {\n        if (allClients != null) {\n            for (ZooKeeper zkc : allClients) {\n                Iterator<ObjectName> childItr = children.iterator();\n                while (childItr.hasNext()) {\n                    ObjectName clientBean = childItr.next();\n                    if (clientBean.toString().contains(\n                            getHexSessionId(zkc.getSessionId()))) {\n                        LOG.info(\"found name:\" + zkc.getSessionId()\n                                + \" client bean:\" + clientBean.toString());\n                        childItr.remove();\n                    }\n                }\n            }\n        }\n        for (ObjectName bean : children) {\n            LOG.info(\"unexpected:\" + bean.toString());\n        }\n        TestCase.assertEquals(\"Unexpected bean exists!\", 0, children.size());\n    }\n\n    /**\n     * Returns a string representation of the given long value session id\n     * \n     * @param sessionId\n     *            long value of session id\n     * @return string representation of session id\n     */\n    protected static String getHexSessionId(long sessionId) {\n        return \"0x\" + Long.toHexString(sessionId);\n    }\n\n    protected void stopServer() throws Exception {\n        LOG.info(\"STOPPING server\");\n        shutdownServerInstance(serverFactory, hostPort);\n        serverFactory = null;\n        // ensure no beans are leftover\n        JMXEnv.ensureOnly();\n    }\n\n\n    protected static ZooKeeperServer getServer(ServerCnxnFactory fac) {\n        ZooKeeperServer zs = ServerCnxnFactoryAccessor.getZkServer(fac);\n\n        return zs;\n    }\n\n    protected void tearDownAll() throws Exception {\n        synchronized (this) {\n            if (allClients != null) for (ZooKeeper zk : allClients) {\n                try {\n                    if (zk != null)\n                        zk.close();\n                } catch (InterruptedException e) {\n                    LOG.warn(\"ignoring interrupt\", e);\n                }\n            }\n            allClients = null;\n        }\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        LOG.info(\"tearDown starting\");\n\n        tearDownAll();\n\n        stopServer();\n\n        if (tmpDir != null) {\n            Assert.assertTrue(\"delete \" + tmpDir.toString(), recursiveDelete(tmpDir));\n        }\n\n        // This has to be set to null when the same instance of this class is reused between test cases\n        serverFactory = null;\n\n        JMXEnv.tearDown();\n\n        /* some useful information - log the number of fds used before\n         * and after a test is run. Helps to verify we are freeing resources\n         * correctly. Unfortunately this only works on unix systems (the\n         * only place sun has implemented as part of the mgmt bean api.\n         */\n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == true) {\n            long fdCount = osMbean.getOpenFileDescriptorCount();     \n            String message = \"fdcount after test is: \"\n                    + fdCount + \" at start it was \" + initialFdCount;\n            LOG.info(message);\n            if (fdCount > initialFdCount) {\n                LOG.info(\"sleeping for 20 secs\");\n                //Thread.sleep(60000);\n                //assertTrue(message, fdCount <= initialFdCount);\n            }\n        }\n    }\n\n    public static MBeanServerConnection jmxConn() throws IOException {\n        return JMXEnv.conn();\n    }\n\n    public static boolean recursiveDelete(File d) {\n        if (d.isDirectory()) {\n            File children[] = d.listFiles();\n            for (File f : children) {\n                Assert.assertTrue(\"delete \" + f.toString(), recursiveDelete(f));\n            }\n        }\n        return d.delete();\n    }\n\n    public static void logAllStackTraces() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Starting logAllStackTraces()\\n\");\n        Map<Thread, StackTraceElement[]> threads = Thread.getAllStackTraces();\n        for (Entry<Thread, StackTraceElement[]> e: threads.entrySet()) {\n            sb.append(\"Thread \" + e.getKey().getName() + \"\\n\");\n            for (StackTraceElement elem: e.getValue()) {\n                sb.append(\"\\tat \" + elem + \"\\n\");\n            }\n        }\n        sb.append(\"Ending logAllStackTraces()\\n\");\n        LOG.error(sb.toString());\n    }\n\n    /*\n     * Verify that all of the servers see the same number of nodes\n     * at the root\n     */\n    void verifyRootOfAllServersMatch(String hostPort)\n        throws InterruptedException, KeeperException, IOException\n    {\n        String parts[] = hostPort.split(\",\");\n\n        // run through till the counts no longer change on each server\n        // max 15 tries, with 2 second sleeps, so approx 30 seconds\n        int[] counts = new int[parts.length];\n        int failed = 0;\n        for (int j = 0; j < 100; j++) {\n            int newcounts[] = new int[parts.length];\n            int i = 0;\n            for (String hp : parts) {\n                try {\n                    ZooKeeper zk = createClient(hp);\n\n                    try {\n                        newcounts[i++] = zk.getChildren(\"/\", false).size();\n                    } finally {\n                        zk.close();\n                    }\n                } catch (Throwable t) {\n                    failed++;\n                    // if session creation Assert.fails dump the thread stack\n                    // and try the next server\n                    logAllStackTraces();\n                }\n            }\n\n            if (Arrays.equals(newcounts, counts)) {\n                LOG.info(\"Found match with array:\"\n                        + Arrays.toString(newcounts));\n                counts = newcounts;\n                break;\n            } else {\n                counts = newcounts;\n                Thread.sleep(10000);\n            }\n\n            // don't keep this up too long, will Assert.assert false below\n            if (failed > 10) {\n                break;\n            }\n        }\n\n        // verify all the servers reporting same number of nodes\n        String logmsg = \"node count not consistent{} {}\";\n        for (int i = 1; i < parts.length; i++) {\n            if (counts[i-1] != counts[i]) {            \t\n                LOG.error(logmsg, Integer.valueOf(counts[i-1]), Integer.valueOf(counts[i]));\n            } else {\n                LOG.info(logmsg, Integer.valueOf(counts[i-1]), Integer.valueOf(counts[i]));\n            }\n        }\n    }\n\n    public static String readFile(File file) throws IOException {\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));\n        try {\n            IOUtils.copyBytes(is, os, 1024, true);\n        } finally {\n            is.close();\n        }\n        return os.toString();\n    }\n\n    public static String join(String separator, Object[] parts) {\n        StringBuilder sb = new StringBuilder();\n        boolean first = true;\n        for (Object part : parts) {\n            if (!first) {\n                sb.append(separator);\n                first = false;\n            }\n            sb.append(part);\n        }\n        return sb.toString();\n    }\n\n    public static ZooKeeper createZKClient(String cxnString) throws Exception {\n        return createZKClient(cxnString, CONNECTION_TIMEOUT);\n    }\n\n    /**\n     * Returns ZooKeeper client after connecting to ZooKeeper Server. Session\n     * timeout is {@link #CONNECTION_TIMEOUT}\n     *\n     * @param cxnString\n     *            connection string in the form of host:port\n     * @param sessionTimeout\n     * @throws IOException\n     *             in cases of network failure\n     */\n    public static ZooKeeper createZKClient(String cxnString, int sessionTimeout) throws IOException {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(cxnString, sessionTimeout, watcher);\n        try {\n            watcher.waitForConnected(CONNECTION_TIMEOUT);\n        } catch (InterruptedException e) {\n            Assert.fail(\"ZooKeeper client can not connect to \" + cxnString);\n        }\n        catch (TimeoutException e) {\n            Assert.fail(\"ZooKeeper client can not connect to \" + cxnString);\n        }\n        return zk;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ClientHammerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.zookeeper.common.Time;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ClientHammerTest extends ClientBase {\n    protected static final Logger LOG = LoggerFactory.getLogger(ClientHammerTest.class);\n\n    private static final long HAMMERTHREAD_LATENCY = 5;\n\n    private static abstract class HammerThread extends Thread {\n        protected final int count;\n        protected volatile int current = 0;\n\n        HammerThread(String name, int count) {\n            super(name);\n            this.count = count;\n        }\n    }\n\n    private static class BasicHammerThread extends HammerThread {\n        private final ZooKeeper zk;\n        private final String prefix;\n\n        BasicHammerThread(String name, ZooKeeper zk, String prefix, int count) {\n            super(name, count);\n            this.zk = zk;\n            this.prefix = prefix;\n        }\n\n        public void run() {\n            byte b[] = new byte[256];\n            try {\n                for (; current < count; current++) {\n                    // Simulate a bit of network latency...\n                    Thread.sleep(HAMMERTHREAD_LATENCY);\n                    zk.create(prefix + current, b, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                }\n            } catch (Throwable t) {\n                LOG.error(\"Client create operation Assert.failed\", t);\n            } finally {\n                try {\n                    zk.close();\n                } catch (InterruptedException e) {\n                    LOG.warn(\"Unexpected\", e);\n                }\n            }\n        }\n    }\n\n    private static class SuperHammerThread extends HammerThread {\n        private final ClientHammerTest parent;\n        private final String prefix;\n\n        SuperHammerThread(String name, ClientHammerTest parent, String prefix,\n                int count)\n        {\n            super(name, count);\n            this.parent = parent;\n            this.prefix = prefix;\n        }\n\n        public void run() {\n            byte b[] = new byte[256];\n            try {\n                for (; current < count; current++) {\n                    ZooKeeper zk = parent.createClient();\n                    try {\n                        zk.create(prefix + current, b, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                    } finally {\n                        try {\n                            zk.close();\n                        } catch (InterruptedException e) {\n                            LOG.warn(\"Unexpected\", e);\n                        }\n                    }\n                }\n            } catch (Throwable t) {\n                LOG.error(\"Client create operation Assert.failed\", t);\n            }\n        }\n    }\n\n    /**\n     * Separate threads each creating a number of nodes. Each thread\n     * is using a non-shared (owned by thread) client for all node creations.\n     * @throws Throwable\n     */\n    @Test\n    public void testHammerBasic() throws Throwable {\n        runHammer(10, 1000);\n    }\n\n    public void runHammer(final int threadCount, final int childCount)\n        throws Throwable\n    {\n        try {\n            HammerThread[] threads = new HammerThread[threadCount];\n            long start = Time.currentElapsedTime();\n            for (int i = 0; i < threads.length; i++) {\n                ZooKeeper zk = createClient();\n                String prefix = \"/test-\" + i;\n                zk.create(prefix, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                prefix += \"/\";\n                HammerThread thread =\n                    new BasicHammerThread(\"BasicHammerThread-\" + i, zk, prefix,\n                            childCount);\n                thread.start();\n\n                threads[i] = thread;\n            }\n\n            verifyHammer(start, threads, childCount);\n        } catch (Throwable t) {\n            LOG.error(\"test Assert.failed\", t);\n            throw t;\n        }\n    }\n\n    /**\n     * Separate threads each creating a number of nodes. Each thread\n     * is creating a new client for each node creation.\n     * @throws Throwable\n     */\n    @Test\n    public void testHammerSuper() throws Throwable {\n        try {\n            final int threadCount = 5;\n            final int childCount = 10;\n\n            HammerThread[] threads = new HammerThread[threadCount];\n            long start = Time.currentElapsedTime();\n            for (int i = 0; i < threads.length; i++) {\n                String prefix = \"/test-\" + i;\n                {\n                    ZooKeeper zk = createClient();\n                    try {\n                        zk.create(prefix, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                    } finally {\n                        zk.close();\n                    }\n                }\n                prefix += \"/\";\n                HammerThread thread =\n                    new SuperHammerThread(\"SuperHammerThread-\" + i, this,\n                            prefix, childCount);\n                thread.start();\n\n                threads[i] = thread;\n            }\n\n            verifyHammer(start, threads, childCount);\n        } catch (Throwable t) {\n            LOG.error(\"test Assert.failed\", t);\n            throw t;\n        }\n    }\n\n    public void verifyHammer(long start, HammerThread[] threads, int childCount)\n        throws IOException, InterruptedException, KeeperException\n    {\n        // look for the clients to finish their create operations\n        LOG.info(\"Starting check for completed hammers\");\n        int workingCount = threads.length;\n        for (int i = 0; i < 120; i++) {\n            Thread.sleep(10000);\n            for (HammerThread h : threads) {\n                if (!h.isAlive() || h.current == h.count) {\n                    workingCount--;\n                }\n            }\n            if (workingCount == 0) {\n                break;\n            }\n            workingCount = threads.length;\n        }\n        if (workingCount > 0) {\n            for (HammerThread h : threads) {\n                LOG.warn(h.getName() + \" never finished creation, current:\"\n                        + h.current);\n            }\n        } else {\n            LOG.info(\"Hammer threads completed creation operations\");\n        }\n\n        for (HammerThread h : threads) {\n            final int safetyFactor = 3;\n            verifyThreadTerminated(h,\n                    threads.length * childCount\n                    * HAMMERTHREAD_LATENCY * safetyFactor);\n        }\n        LOG.info(new Date() + \" Total time \"\n                + (Time.currentElapsedTime() - start));\n\n        ZooKeeper zk = createClient();\n        try {\n            LOG.info(\"******************* Connected to ZooKeeper\" + new Date());\n            for (int i = 0; i < threads.length; i++) {\n                LOG.info(\"Doing thread: \" + i + \" \" + new Date());\n                List<String> children =\n                    zk.getChildren(\"/test-\" + i, false);\n                Assert.assertEquals(childCount, children.size());\n                children = zk.getChildren(\"/test-\" + i, false, null);\n                Assert.assertEquals(childCount, children.size());\n            }\n            for (int i = 0; i < threads.length; i++) {\n                List<String> children =\n                    zk.getChildren(\"/test-\" + i, false);\n                Assert.assertEquals(childCount, children.size());\n                children = zk.getChildren(\"/test-\" + i, false, null);\n                Assert.assertEquals(childCount, children.size());\n            }\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ClientPortBindTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ClientPortBindTest extends ZKTestCase implements Watcher {\n    protected static final Logger LOG = \n        LoggerFactory.getLogger(ClientPortBindTest.class);\n\n    private volatile CountDownLatch startSignal;\n\n    /**\n     * Verify that the server binds to the specified address\n     */\n    @Test\n    public void testBindByAddress() throws Exception {\n        String bindAddress = null;\n        Enumeration<NetworkInterface> intfs =\n            NetworkInterface.getNetworkInterfaces();\n        // if we have a loopback and it has an address use it\n        while(intfs.hasMoreElements()) {\n            NetworkInterface i = intfs.nextElement();\n            try {\n                if (i.isLoopback()) {\n                  Enumeration<InetAddress> addrs = i.getInetAddresses();\n                  while (addrs.hasMoreElements()) {\n                    InetAddress a = addrs.nextElement();\n                    if(a.isLoopbackAddress()) {\n                      bindAddress = a.getHostAddress();\n                      break;\n                    }\n                  }\n                }\n            } catch (SocketException se) {\n                LOG.warn(\"Couldn't find  loopback interface: \" + se.getMessage());\n            }\n        }\n        if (bindAddress == null) {\n            LOG.warn(\"Unable to determine loop back address, skipping test\");\n            return;\n        }\n        final int PORT = PortAssignment.unique();\n\n        LOG.info(\"Using \" + bindAddress + \" as the bind address\");\n        final String HOSTPORT = bindAddress + \":\" + PORT;\n        LOG.info(\"Using \" + HOSTPORT + \" as the host/port\");\n\n\n        File tmpDir = ClientBase.createTmpDir();\n\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(\n                new InetSocketAddress(bindAddress, PORT), -1);\n        f.startup(zks);\n        LOG.info(\"starting up the the server, waiting\");\n\n        Assert.assertTrue(\"waiting for server up\",\n                   ClientBase.waitForServerUp(HOSTPORT,\n                                   CONNECTION_TIMEOUT));\n\n        startSignal = new CountDownLatch(1);\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        try {\n            startSignal.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n            Assert.assertTrue(\"count == 0\", startSignal.getCount() == 0);\n            zk.close();\n        } finally {\n            f.shutdown();\n            zks.shutdown();\n\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(HOSTPORT,\n                                                    CONNECTION_TIMEOUT));\n        }\n    }\n\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \" + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected\n                && startSignal != null && startSignal.getCount() > 0)\n        {\n            startSignal.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ClientRetry.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ClientRetry extends ClientBase {\n\n    @Override\n    public void setUp() throws Exception {\n        maxCnxns = 1;\n        super.setUp();\n    }\n    /*\n     * This is a simple test - try to connect two clients to a server\n     * accepting a maximum of one connection from each address. Check that\n     * only one is accepted. Close that connection, and check that the other\n     * eventually connects.\n     *\n     * There is a possibility of a false positive here, as when zk2 is tested\n     * for having connected it might not have been given enough time, and finish\n     * connecting after the test is done. Since the\n     * server doesn't tell the client why it hasn't connected, there's no\n     * obvious way to detect the difference.\n     */\n    @Test\n    public void testClientRetry() throws IOException, InterruptedException, TimeoutException{\n        CountdownWatcher cdw1 = new CountdownWatcher();\n        CountdownWatcher cdw2 = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(hostPort, 10000, cdw1);\n        try {\n            cdw1.waitForConnected(CONNECTION_TIMEOUT);\n            ZooKeeper zk2 = new ZooKeeper(hostPort, 10000, cdw2);\n            try {\n                States s1 = zk.getState();\n                States s2 = zk2.getState();\n                Assert.assertSame(s1,States.CONNECTED);\n                Assert.assertSame(s2,States.CONNECTING);\n                cdw1.reset();\n                cdw1.waitForDisconnected(CONNECTION_TIMEOUT);\n                cdw2.waitForConnected(CONNECTION_TIMEOUT);\n                Assert.assertSame(zk2.getState(),States.CONNECTED);\n            } finally {\n                zk2.close();\n            }\n        } finally {\n            zk.close();\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ClientTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.KeeperException.InvalidACLException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooDefs.Perms;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Id;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.proto.ExistsRequest;\nimport org.apache.zookeeper.proto.ExistsResponse;\nimport org.apache.zookeeper.proto.ReplyHeader;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.apache.zookeeper.server.PrepRequestProcessor;\nimport org.apache.zookeeper.server.util.OSMXBean;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ClientTest extends ClientBase {\n    protected static final Logger LOG = LoggerFactory.getLogger(ClientTest.class);\n\n    /** Verify that pings are sent, keeping the \"idle\" client alive */\n    @Test\n    public void testPing() throws Exception {\n        ZooKeeper zkIdle = null;\n        ZooKeeper zkWatchCreator = null;\n        try {\n            CountdownWatcher watcher = new CountdownWatcher();\n            zkIdle = createClient(watcher, hostPort, 10000);\n\n            zkWatchCreator = createClient();\n\n            for (int i = 0; i < 10; i++) {\n                zkWatchCreator.create(\"/\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n            for (int i = 0; i < 10; i++) {\n                zkIdle.exists(\"/\" + i, true);\n            }\n            for (int i = 0; i < 10; i++) {\n                Thread.sleep(1000);\n                zkWatchCreator.delete(\"/\" + i, -1);\n            }\n            // The bug will manifest itself here because zkIdle will expire\n            zkIdle.exists(\"/0\", false);\n        } finally {\n            if (zkIdle != null) {\n                zkIdle.close();\n            }\n            if (zkWatchCreator != null) {\n                zkWatchCreator.close();\n            }\n        }\n    }\n\n    @Test\n    public void testClientwithoutWatcherObj() throws IOException,\n            InterruptedException, KeeperException\n    {\n        performClientTest(false, hostPort);\n    }\n\n    @Test\n    public void testClientWithWatcherObj() throws IOException,\n            InterruptedException, KeeperException\n    {\n        performClientTest(true, hostPort);\n    }\n\n    @Test\n    public void testClientWithIPv6Address() throws IOException,\n            InterruptedException, KeeperException\n    {\n        assumeIPv6Available();\n        performClientTest(true, ipv6HostPort);\n    }\n\n    /** Exercise the testable functions, verify tostring, etc... */\n    @Test\n    public void testTestability() throws Exception {\n        TestableZooKeeper zk = createClient();\n        try {\n            LOG.info(\"{}\",zk.testableLocalSocketAddress());\n            LOG.info(\"{}\",zk.testableRemoteSocketAddress());\n            LOG.info(\"{}\",zk.toString());\n        } finally {\n            zk.close();\n            zk.testableWaitForShutdown(CONNECTION_TIMEOUT);\n            LOG.info(\"{}\",zk.testableLocalSocketAddress());\n            LOG.info(\"{}\",zk.testableRemoteSocketAddress());\n            LOG.info(\"{}\",zk.toString());\n        }\n    }\n\n    @Test\n    public void testACLs() throws Exception {\n        ZooKeeper zk = null;\n        try {\n            zk = createClient();\n            try {\n                zk.create(\"/acltest\", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n                Assert.fail(\"Should have received an invalid acl error\");\n            } catch(InvalidACLException e) {\n                LOG.info(\"Test successful, invalid acl received : \"\n                        + e.getMessage());\n            }\n            try {\n                ArrayList<ACL> testACL = new ArrayList<ACL>();\n                testACL.add(new ACL(Perms.ALL | Perms.ADMIN, Ids.AUTH_IDS));\n                testACL.add(new ACL(Perms.ALL | Perms.ADMIN, new Id(\"ip\", \"127.0.0.1/8\")));\n                zk.create(\"/acltest\", new byte[0], testACL, CreateMode.PERSISTENT);\n                Assert.fail(\"Should have received an invalid acl error\");\n            } catch(InvalidACLException e) {\n                LOG.info(\"Test successful, invalid acl received : \"\n                        + e.getMessage());\n            }\n            zk.addAuthInfo(\"digest\", \"ben:passwd\".getBytes());\n            zk.create(\"/acltest\", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            zk.close();\n            zk = createClient();\n            zk.addAuthInfo(\"digest\", \"ben:passwd2\".getBytes());\n            try {\n                zk.getData(\"/acltest\", false, new Stat());\n                Assert.fail(\"Should have received a permission error\");\n            } catch (KeeperException e) {\n                Assert.assertEquals(Code.NOAUTH, e.code());\n            }\n            zk.addAuthInfo(\"digest\", \"ben:passwd\".getBytes());\n            zk.getData(\"/acltest\", false, new Stat());\n            zk.setACL(\"/acltest\", Ids.OPEN_ACL_UNSAFE, -1);\n            zk.close();\n            zk = createClient();\n            zk.getData(\"/acltest\", false, new Stat());\n            List<ACL> acls = zk.getACL(\"/acltest\", new Stat());\n            Assert.assertEquals(1, acls.size());\n            Assert.assertEquals(Ids.OPEN_ACL_UNSAFE, acls);\n\n            // The stat parameter should be optional.\n            acls = zk.getACL(\"/acltest\", null);\n            Assert.assertEquals(1, acls.size());\n            Assert.assertEquals(Ids.OPEN_ACL_UNSAFE, acls);\n\n            zk.close();\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        LinkedBlockingQueue<WatchedEvent> events =\n            new LinkedBlockingQueue<WatchedEvent>();\n\n        public void process(WatchedEvent event) {\n            super.process(event);\n            if (event.getType() != EventType.None) {\n                try {\n                    events.put(event);\n                } catch (InterruptedException e) {\n                    LOG.warn(\"ignoring interrupt during event.put\");\n                }\n            }\n        }\n    }\n\n    /**\n     * Register multiple watchers and verify that they all get notified and\n     * in the right order.\n     */\n    @Test\n    public void testMutipleWatcherObjs()\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk = createClient(new CountdownWatcher(), hostPort);\n        try {\n            MyWatcher watchers[] = new MyWatcher[100];\n            MyWatcher watchers2[] = new MyWatcher[watchers.length];\n            for (int i = 0; i < watchers.length; i++) {\n                watchers[i] = new MyWatcher();\n                watchers2[i] = new MyWatcher();\n                zk.create(\"/foo-\" + i, (\"foodata\" + i).getBytes(),\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            Stat stat = new Stat();\n\n            //\n            // test get/exists with single set of watchers\n            //   get all, then exists all\n            //\n            for (int i = 0; i < watchers.length; i++) {\n                Assert.assertNotNull(zk.getData(\"/foo-\" + i, watchers[i], stat));\n            }\n            for (int i = 0; i < watchers.length; i++) {\n                Assert.assertNotNull(zk.exists(\"/foo-\" + i, watchers[i]));\n            }\n            // trigger the watches\n            for (int i = 0; i < watchers.length; i++) {\n                zk.setData(\"/foo-\" + i, (\"foodata2-\" + i).getBytes(), -1);\n                zk.setData(\"/foo-\" + i, (\"foodata3-\" + i).getBytes(), -1);\n            }\n            for (int i = 0; i < watchers.length; i++) {\n                WatchedEvent event =\n                    watchers[i].events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(\"/foo-\" + i, event.getPath());\n                Assert.assertEquals(EventType.NodeDataChanged, event.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n\n                // small chance that an unexpected message was delivered\n                //  after this check, but we would catch that next time\n                //  we check events\n                Assert.assertEquals(0, watchers[i].events.size());\n            }\n\n            //\n            // test get/exists with single set of watchers\n            //  get/exists together\n            //\n            for (int i = 0; i < watchers.length; i++) {\n                Assert.assertNotNull(zk.getData(\"/foo-\" + i, watchers[i], stat));\n                Assert.assertNotNull(zk.exists(\"/foo-\" + i, watchers[i]));\n            }\n            // trigger the watches\n            for (int i = 0; i < watchers.length; i++) {\n                zk.setData(\"/foo-\" + i, (\"foodata4-\" + i).getBytes(), -1);\n                zk.setData(\"/foo-\" + i, (\"foodata5-\" + i).getBytes(), -1);\n            }\n            for (int i = 0; i < watchers.length; i++) {\n                WatchedEvent event =\n                    watchers[i].events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(\"/foo-\" + i, event.getPath());\n                Assert.assertEquals(EventType.NodeDataChanged, event.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n\n                // small chance that an unexpected message was delivered\n                //  after this check, but we would catch that next time\n                //  we check events\n                Assert.assertEquals(0, watchers[i].events.size());\n            }\n\n            //\n            // test get/exists with two sets of watchers\n            //\n            for (int i = 0; i < watchers.length; i++) {\n                Assert.assertNotNull(zk.getData(\"/foo-\" + i, watchers[i], stat));\n                Assert.assertNotNull(zk.exists(\"/foo-\" + i, watchers2[i]));\n            }\n            // trigger the watches\n            for (int i = 0; i < watchers.length; i++) {\n                zk.setData(\"/foo-\" + i, (\"foodata6-\" + i).getBytes(), -1);\n                zk.setData(\"/foo-\" + i, (\"foodata7-\" + i).getBytes(), -1);\n            }\n            for (int i = 0; i < watchers.length; i++) {\n                WatchedEvent event =\n                    watchers[i].events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(\"/foo-\" + i, event.getPath());\n                Assert.assertEquals(EventType.NodeDataChanged, event.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n\n                // small chance that an unexpected message was delivered\n                //  after this check, but we would catch that next time\n                //  we check events\n                Assert.assertEquals(0, watchers[i].events.size());\n\n                // watchers2\n                WatchedEvent event2 =\n                    watchers2[i].events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(\"/foo-\" + i, event2.getPath());\n                Assert.assertEquals(EventType.NodeDataChanged, event2.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event2.getState());\n\n                // small chance that an unexpected message was delivered\n                //  after this check, but we would catch that next time\n                //  we check events\n                Assert.assertEquals(0, watchers2[i].events.size());\n            }\n\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n    }\n\n    private void performClientTest(boolean withWatcherObj, String hostPort)\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk = null;\n        try {\n            MyWatcher watcher = new MyWatcher();\n            zk = createClient(watcher, hostPort);\n            LOG.info(\"Before create /benwashere\");\n            zk.create(\"/benwashere\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            LOG.info(\"After create /benwashere\");\n            try {\n                zk.setData(\"/benwashere\", \"hi\".getBytes(), 57);\n                Assert.fail(\"Should have gotten BadVersion exception\");\n            } catch(KeeperException.BadVersionException e) {\n                // expected that\n            } catch (KeeperException e) {\n                Assert.fail(\"Should have gotten BadVersion exception\");\n            }\n            LOG.info(\"Before delete /benwashere\");\n            zk.delete(\"/benwashere\", 0);\n            LOG.info(\"After delete /benwashere\");\n            zk.close();\n            //LOG.info(\"Closed client: \" + zk.describeCNXN());\n            Thread.sleep(2000);\n\n            zk = createClient(watcher, hostPort);\n            //LOG.info(\"Created a new client: \" + zk.describeCNXN());\n            LOG.info(\"Before delete /\");\n\n            try {\n                zk.delete(\"/\", -1);\n                Assert.fail(\"deleted root!\");\n            } catch(KeeperException.BadArgumentsException e) {\n                // good, expected that\n            }\n            Stat stat = new Stat();\n            // Test basic create, ls, and getData\n            zk.create(\"/pat\", \"Pat was here\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            LOG.info(\"Before create /ben\");\n            zk.create(\"/pat/ben\", \"Ben was here\".getBytes(),\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            LOG.info(\"Before getChildren /pat\");\n            List<String> children = zk.getChildren(\"/pat\", false);\n            Assert.assertEquals(1, children.size());\n            Assert.assertEquals(\"ben\", children.get(0));\n            List<String> children2 = zk.getChildren(\"/pat\", false, null);\n            Assert.assertEquals(children, children2);\n            String value = new String(zk.getData(\"/pat/ben\", false, stat));\n            Assert.assertEquals(\"Ben was here\", value);\n            // Test stat and watch of non existent node\n\n            try {\n                if (withWatcherObj) {\n                    Assert.assertEquals(null, zk.exists(\"/frog\", watcher));\n                } else {\n                    Assert.assertEquals(null, zk.exists(\"/frog\", true));\n                }\n                LOG.info(\"Comment: asseting passed for frog setting /\");\n            } catch (KeeperException.NoNodeException e) {\n                // OK, expected that\n            }\n            zk.create(\"/frog\", \"hi\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            // the first poll is just a session delivery\n            LOG.info(\"Comment: checking for events length \"\n                     + watcher.events.size());\n            WatchedEvent event = watcher.events.poll(10, TimeUnit.SECONDS);\n            Assert.assertEquals(\"/frog\", event.getPath());\n            Assert.assertEquals(EventType.NodeCreated, event.getType());\n            Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n            // Test child watch and create with sequence\n            zk.getChildren(\"/pat/ben\", true);\n            for (int i = 0; i < 10; i++) {\n                zk.create(\"/pat/ben/\" + i + \"-\", Integer.toString(i).getBytes(),\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            }\n            children = zk.getChildren(\"/pat/ben\", false);\n            Collections.sort(children);\n            Assert.assertEquals(10, children.size());\n            for (int i = 0; i < 10; i++) {\n                final String name = children.get(i);\n                Assert.assertTrue(\"starts with -\", name.startsWith(i + \"-\"));\n                byte b[];\n                if (withWatcherObj) {\n                    b = zk.getData(\"/pat/ben/\" + name, watcher, stat);\n                } else {\n                    b = zk.getData(\"/pat/ben/\" + name, true, stat);\n                }\n                Assert.assertEquals(Integer.toString(i), new String(b));\n                zk.setData(\"/pat/ben/\" + name, \"new\".getBytes(),\n                        stat.getVersion());\n                if (withWatcherObj) {\n                    stat = zk.exists(\"/pat/ben/\" + name, watcher);\n                } else {\n                stat = zk.exists(\"/pat/ben/\" + name, true);\n                }\n                zk.delete(\"/pat/ben/\" + name, stat.getVersion());\n            }\n            event = watcher.events.poll(10, TimeUnit.SECONDS);\n            Assert.assertEquals(\"/pat/ben\", event.getPath());\n            Assert.assertEquals(EventType.NodeChildrenChanged, event.getType());\n            Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n            for (int i = 0; i < 10; i++) {\n                event = watcher.events.poll(10, TimeUnit.SECONDS);\n                final String name = children.get(i);\n                Assert.assertEquals(\"/pat/ben/\" + name, event.getPath());\n                Assert.assertEquals(EventType.NodeDataChanged, event.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n                event = watcher.events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(\"/pat/ben/\" + name, event.getPath());\n                Assert.assertEquals(EventType.NodeDeleted, event.getType());\n                Assert.assertEquals(KeeperState.SyncConnected, event.getState());\n            }\n            zk.create(\"/good\\u0040path\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n\n            zk.create(\"/duplicate\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            try {\n                zk.create(\"/duplicate\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n                Assert.fail(\"duplicate create allowed\");\n            } catch(KeeperException.NodeExistsException e) {\n                // OK, expected that\n            }\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n    }\n    \n    // Test that sequential filenames are being created correctly,\n    // with 0-padding in the filename\n    @Test\n    public void testSequentialNodeNames()\n        throws IOException, InterruptedException, KeeperException\n    {\n        String path = \"/SEQUENCE\";\n        String file = \"TEST\";\n        String filepath = path + \"/\" + file;\n\n        ZooKeeper zk = null;\n        try {\n            zk = createClient();\n            zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            zk.create(filepath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            List<String> children = zk.getChildren(path, false);\n            Assert.assertEquals(1, children.size());\n            Assert.assertEquals(file + \"0000000000\", children.get(0));\n\n            zk.create(filepath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            children = zk.getChildren(path, false);\n            Assert.assertEquals(2, children.size());\n            Assert.assertTrue(\"contains child 1\",  children.contains(file + \"0000000001\"));\n\n            zk.create(filepath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            children = zk.getChildren(path, false);\n            Assert.assertEquals(3, children.size());\n            Assert.assertTrue(\"contains child 2\",\n                       children.contains(file + \"0000000002\"));\n\n            // The pattern is holding so far.  Let's run the counter a bit\n            // to be sure it continues to spit out the correct answer\n            for(int i = children.size(); i < 105; i++)\n               zk.create(filepath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n\n            children = zk.getChildren(path, false);\n            Assert.assertTrue(\"contains child 104\",\n                       children.contains(file + \"0000000104\"));\n\n        }\n        finally {\n            if(zk != null)\n                zk.close();\n        }\n    }\n    \n    // Test that data provided when \n    // creating sequential nodes is stored properly\n    @Test\n    public void testSequentialNodeData() throws Exception {\n        ZooKeeper zk= null;\n        String queue_handle = \"/queue\";\n        try {\n            zk = createClient();\n\n            zk.create(queue_handle, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            zk.create(queue_handle + \"/element\", \"0\".getBytes(),\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            zk.create(queue_handle + \"/element\", \"1\".getBytes(),\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            List<String> children = zk.getChildren(queue_handle, true);\n            Assert.assertEquals(children.size(), 2);\n            String child1 = children.get(0);\n            String child2 = children.get(1);\n            int compareResult = child1.compareTo(child2);\n            Assert.assertNotSame(compareResult, 0);\n            if (compareResult < 0) {\n            } else {\n                String temp = child1;\n                child1 = child2;\n                child2 = temp;\n            }\n            String child1data = new String(zk.getData(queue_handle\n                    + \"/\" + child1, false, null));\n            String child2data = new String(zk.getData(queue_handle\n                    + \"/\" + child2, false, null));\n            Assert.assertEquals(child1data, \"0\");\n            Assert.assertEquals(child2data, \"1\");\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n\n    }\n\n    @Test\n    public void testLargeNodeData() throws Exception {\n        ZooKeeper zk= null;\n        String queue_handle = \"/large\";\n        try {\n            zk = createClient();\n\n            zk.create(queue_handle, new byte[500000], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n\n    }\n\n    private void verifyCreateFails(String path, ZooKeeper zk) throws Exception {\n        try {\n            zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        } catch (IllegalArgumentException e) {\n            // this is good\n            return;\n        }\n        Assert.fail(\"bad path \\\"\" + path + \"\\\" not caught\");\n    }\n\n    // Test that the path string is validated\n    @Test\n    public void testPathValidation() throws Exception {\n        ZooKeeper zk = createClient();\n\n        verifyCreateFails(null, zk);\n        verifyCreateFails(\"\", zk);\n        verifyCreateFails(\"//\", zk);\n        verifyCreateFails(\"///\", zk);\n        verifyCreateFails(\"////\", zk);\n        verifyCreateFails(\"/.\", zk);\n        verifyCreateFails(\"/..\", zk);\n        verifyCreateFails(\"/./\", zk);\n        verifyCreateFails(\"/../\", zk);\n        verifyCreateFails(\"/foo/./\", zk);\n        verifyCreateFails(\"/foo/../\", zk);\n        verifyCreateFails(\"/foo/.\", zk);\n        verifyCreateFails(\"/foo/..\", zk);\n        verifyCreateFails(\"/./.\", zk);\n        verifyCreateFails(\"/../..\", zk);\n        verifyCreateFails(\"/\\u0001foo\", zk);\n        verifyCreateFails(\"/foo/bar/\", zk);\n        verifyCreateFails(\"/foo//bar\", zk);\n        verifyCreateFails(\"/foo/bar//\", zk);\n\n        verifyCreateFails(\"foo\", zk);\n        verifyCreateFails(\"a\", zk);\n\n        zk.create(\"/createseqpar\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        // next two steps - related to sequential processing\n        // 1) verify that empty child name Assert.fails if not sequential\n        try {\n            zk.create(\"/createseqpar/\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            Assert.assertTrue(false);\n        } catch(IllegalArgumentException be) {\n            // catch this.\n        }\n\n        // 2) verify that empty child name success if sequential \n        zk.create(\"/createseqpar/\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n        zk.create(\"/createseqpar/.\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n        zk.create(\"/createseqpar/..\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT_SEQUENTIAL);\n        try {\n            zk.create(\"/createseqpar//\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT_SEQUENTIAL);\n            Assert.assertTrue(false);\n        } catch(IllegalArgumentException be) {\n            // catch this.\n        }\n        try {\n            zk.create(\"/createseqpar/./\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT_SEQUENTIAL);\n            Assert.assertTrue(false);\n        } catch(IllegalArgumentException be) {\n            // catch this.\n        }\n        try {\n            zk.create(\"/createseqpar/../\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT_SEQUENTIAL);\n            Assert.assertTrue(false);\n        } catch(IllegalArgumentException be) {\n            // catch this.\n        }\n\n        \n        //check for the code path that throws at server\n        PrepRequestProcessor.setFailCreate(true);\n        try {\n            zk.create(\"/m\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            Assert.assertTrue(false);\n        } catch(KeeperException.BadArgumentsException be) {\n            // catch this.\n        }\n        PrepRequestProcessor.setFailCreate(false);\n        zk.create(\"/.foo\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/.f.\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/..f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/..f..\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f.c\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f\\u0040f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/.f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/f.\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/..f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/f..\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/.f/f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/f/f./f\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n    }\n\n//    private void notestConnections()\n//        throws IOException, InterruptedException, KeeperException\n//    {\n//        ZooKeeper zk;\n//        for(int i = 0; i < 2000; i++) {\n//            if (i % 100 == 0) {\n//                LOG.info(\"Testing \" + i + \" connections\");\n//            }\n//            // We want to make sure socket descriptors are going away\n//            zk = new ZooKeeper(hostPort, 30000, this);\n//            zk.getData(\"/\", false, new Stat());\n//            zk.close();\n//        }\n//    }\n\n    @Test\n    public void testDeleteWithChildren() throws Exception {\n        ZooKeeper zk = createClient();\n        zk.create(\"/parent\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/parent/child\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        try {\n            zk.delete(\"/parent\", -1);\n            Assert.fail(\"Should have received a not equals message\");\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NOTEMPTY, e.code());\n        }\n        zk.delete(\"/parent/child\", -1);\n        zk.delete(\"/parent\", -1);\n        zk.close();\n    }\n\n    private class VerifyClientCleanup extends Thread {\n        int count;\n        int current = 0;\n\n        VerifyClientCleanup(String name, int count) {\n            super(name);\n            this.count = count;\n        }\n\n        public void run() {\n            try {\n                for (; current < count; current++) {\n                    TestableZooKeeper zk = createClient();\n                    zk.close();\n                    // we've asked to close, wait for it to finish closing\n                    // all the sub-threads otw the selector may not be\n                    // closed when we check (false positive on test Assert.failure\n                    zk.testableWaitForShutdown(CONNECTION_TIMEOUT);\n                }\n            } catch (Throwable t) {\n                LOG.error(\"test Assert.failed\", t);\n            }\n        }\n    }\n\n    /**\n     * Verify that the client is cleaning up properly. Open/close a large\n     * number of sessions. Essentially looking to see if sockets/selectors\n     * are being cleaned up properly during close.\n     *\n     * @throws Throwable\n     */\n    @Test\n    public void testClientCleanup() throws Throwable {\n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == false) {\n            LOG.warn(\"skipping testClientCleanup, only available on Unix\");\n            return;\n        }\n\n        final int threadCount = 3;\n        final int clientCount = 10;\n\n        /* Log the number of fds used before and after a test is run. Verifies\n         * we are freeing resources correctly. Unfortunately this only works\n         * on unix systems (the only place sun has implemented as part of the\n         * mgmt bean api).\n         */\n        long initialFdCount = osMbean.getOpenFileDescriptorCount();\n\n        VerifyClientCleanup threads[] = new VerifyClientCleanup[threadCount];\n\n        for (int i = 0; i < threads.length; i++) {\n            threads[i] = new VerifyClientCleanup(\"VCC\" + i, clientCount);\n            threads[i].start();\n        }\n\n        for (int i = 0; i < threads.length; i++) {\n            threads[i].join(CONNECTION_TIMEOUT);\n            Assert.assertTrue(threads[i].current == threads[i].count);\n        }\n\n        // if this Assert.fails it means we are not cleaning up after the closed\n        // sessions.\n        long currentCount = osMbean.getOpenFileDescriptorCount();\n        final String logmsg = \"open fds after test ({}) are not significantly higher than before ({})\";\n        \n        if (currentCount > initialFdCount + 10) {\n            // consider as error\n        \tLOG.error(logmsg,Long.valueOf(currentCount),Long.valueOf(initialFdCount));\n        } else {\n        \tLOG.info(logmsg,Long.valueOf(currentCount),Long.valueOf(initialFdCount));\n        }\n    }\n\n\n    /**\n     * We create a perfectly valid 'exists' request, except that the opcode is wrong.\n     * @return\n     * @throws Exception\n     */\n    @Test\n    public void testNonExistingOpCode() throws Exception  {\n        final CountDownLatch clientDisconnected = new CountDownLatch(1);\n        Watcher watcher = new Watcher() {\n            @Override\n            public synchronized void process(WatchedEvent event) {\n                if (event.getState() == KeeperState.Disconnected) {\n                    clientDisconnected.countDown();\n                }\n            }\n        };\n        TestableZooKeeper zk = new TestableZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);\n\n        final String path = \"/m1\";\n\n        RequestHeader h = new RequestHeader();\n        h.setType(888);  // This code does not exists\n        ExistsRequest request = new ExistsRequest();\n        request.setPath(path);\n        request.setWatch(false);\n        ExistsResponse response = new ExistsResponse();\n\n        ReplyHeader r = zk.submitRequest(h, request, response, null);\n\n        Assert.assertEquals(r.getErr(), Code.UNIMPLEMENTED.intValue());\n\n        // Sending a nonexisting opcode should cause the server to disconnect\n        Assert.assertTrue(\"failed to disconnect\",\n                clientDisconnected.await(5000, TimeUnit.MILLISECONDS));\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ConnectStringParserTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.client.ConnectStringParser;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ConnectStringParserTest extends ZKTestCase{\n\n    @Test\n    public void testSingleServerChrootPath(){\n        String chrootPath = \"/hallo/welt\";\n        String servers = \"10.10.10.1\";\n        assertChrootPath(chrootPath,\n                new ConnectStringParser(servers+chrootPath));\n    }\n\n    @Test\n    public void testMultipleServersChrootPath(){\n        String chrootPath = \"/hallo/welt\";\n        String servers = \"10.10.10.1,10.10.10.2\";\n        assertChrootPath(chrootPath,\n                new ConnectStringParser(servers+chrootPath));\n    }\n\n    @Test\n    public void testParseServersWithoutPort(){\n        String servers = \"10.10.10.1,10.10.10.2\";\n        ConnectStringParser parser = new ConnectStringParser(servers);\n\n        Assert.assertEquals(\"10.10.10.1\", parser.getServerAddresses().get(0).getHostName());\n        Assert.assertEquals(\"10.10.10.2\", parser.getServerAddresses().get(1).getHostName());\n    }\n\n    @Test\n    public void testParseServersWithPort(){\n        String servers = \"10.10.10.1:112,10.10.10.2:110\";\n        ConnectStringParser parser = new ConnectStringParser(servers);\n\n        Assert.assertEquals(\"10.10.10.1\", parser.getServerAddresses().get(0).getHostName());\n        Assert.assertEquals(\"10.10.10.2\", parser.getServerAddresses().get(1).getHostName());\n\n        Assert.assertEquals(112, parser.getServerAddresses().get(0).getPort());\n        Assert.assertEquals(110, parser.getServerAddresses().get(1).getPort());\n    }\n\n    private void assertChrootPath(String expected, ConnectStringParser parser){\n        Assert.assertEquals(expected, parser.getChrootPath());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/CreateModeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.EnumSet;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class CreateModeTest extends ZKTestCase {\n    \n    @Test\n    public void testBasicCreateMode() {\n        CreateMode cm = CreateMode.PERSISTENT;\n        Assert.assertEquals(cm.toFlag(), 0);\n        Assert.assertFalse(cm.isEphemeral());\n        Assert.assertFalse(cm.isSequential());\n        \n        cm = CreateMode.EPHEMERAL;\n        Assert.assertEquals(cm.toFlag(), 1);\n        Assert.assertTrue(cm.isEphemeral());\n        Assert.assertFalse(cm.isSequential());\n        \n        cm = CreateMode.PERSISTENT_SEQUENTIAL;\n        Assert.assertEquals(cm.toFlag(), 2);\n        Assert.assertFalse(cm.isEphemeral());\n        Assert.assertTrue(cm.isSequential());\n        \n        cm = CreateMode.EPHEMERAL_SEQUENTIAL;\n        Assert.assertEquals(cm.toFlag(), 3);\n        Assert.assertTrue(cm.isEphemeral());\n        Assert.assertTrue(cm.isSequential());\n    }\n    \n    @Test\n    public void testFlagConversion() throws KeeperException {\n        // Ensure we get the same value back after round trip conversion\n        EnumSet<CreateMode> allModes = EnumSet.allOf(CreateMode.class);\n\n        for(CreateMode cm : allModes) {\n            Assert.assertEquals(cm, CreateMode.fromFlag( cm.toFlag() ) );\n        }\n    }\n\n    @Test\n    public void testInvalidFlagConversion() throws KeeperException {\n        try {\n            CreateMode cm = CreateMode.fromFlag(99);\n            Assert.fail(\"Shouldn't be able to convert 99 to a CreateMode.\");\n        } catch(KeeperException ke) {\n            Assert.assertEquals(Code.BADARGUMENTS, ke.code());\n        }\n\n        try {\n            CreateMode cm = CreateMode.fromFlag(-1);\n            Assert.fail(\"Shouldn't be able to convert -1 to a CreateMode.\");\n        } catch(KeeperException ke) {\n            Assert.assertEquals(Code.BADARGUMENTS, ke.code());\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/DisconnectableZooKeeper.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\n\npublic class DisconnectableZooKeeper extends ZooKeeper {\n    public DisconnectableZooKeeper(String host, int sessionTimeout, Watcher watcher)\n        throws IOException\n    {\n        super(host, sessionTimeout, watcher);\n    }\n    \n    public DisconnectableZooKeeper(String host, int sessionTimeout, Watcher watcher,\n        long sessionId, byte[] sessionPasswd)\n        throws IOException\n    {\n        super(host, sessionTimeout, watcher, sessionId, sessionPasswd);\n    }\n\n    /** Testing only!!! Really!!!! This is only here to test when the client\n     * disconnects from the server w/o sending a session disconnect (ie\n     * ending the session cleanly). The server will eventually notice the\n     * client is no longer pinging and will timeout the session.\n     */\n    public void disconnect() throws IOException {\n        cnxn.disconnect();\n    }\n\n    /**\n     * Prevent the client from automatically reconnecting if the connection to the\n     * server is lost\n     */\n    public void dontReconnect() throws Exception {\n        java.lang.reflect.Field f = cnxn.getClass().getDeclaredField(\"closing\");\n        f.setAccessible(true);\n        f.setBoolean(cnxn, true);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/DisconnectedWatcherTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DisconnectedWatcherTest extends ClientBase {\n    protected static final Logger LOG = LoggerFactory.getLogger(DisconnectedWatcherTest.class);\n    final int TIMEOUT = 5000;\n\n    private class MyWatcher extends CountdownWatcher {\n        LinkedBlockingQueue<WatchedEvent> events =\n            new LinkedBlockingQueue<WatchedEvent>();\n\n        public void process(WatchedEvent event) {\n            super.process(event);\n            if (event.getType() != Event.EventType.None) {\n                try {\n                    events.put(event);\n                } catch (InterruptedException e) {\n                    LOG.warn(\"ignoring interrupt during event.put\");\n                }\n            }\n        }\n    }\n\n    // @see jira issue ZOOKEEPER-961\n    \n    @Test\n    public void testChildWatcherAutoResetWithChroot() throws Exception {\n        ZooKeeper zk1 = createClient();\n\n        zk1.create(\"/ch1\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n\n        MyWatcher watcher = new MyWatcher();\n        ZooKeeper zk2 = createClient(watcher, hostPort + \"/ch1\");\n        zk2.getChildren(\"/\", true );\n\n        // this call shouldn't trigger any error or watch\n        zk1.create(\"/youdontmatter1\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/youshouldmatter1\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        WatchedEvent e = watcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/\", e.getPath());\n\n        MyWatcher childWatcher = new MyWatcher();\n        zk2.getChildren(\"/\", childWatcher);\n        \n        stopServer();\n        watcher.waitForDisconnected(3000);\n        startServer();\n        watcher.waitForConnected(3000);\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/youshouldmatter2\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        e = childWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/\", e.getPath());\n    }\n    \n    @Test\n    public void testDefaultWatcherAutoResetWithChroot() throws Exception {\n        ZooKeeper zk1 = createClient();\n\n        zk1.create(\"/ch1\", null, Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n\n        MyWatcher watcher = new MyWatcher();\n        ZooKeeper zk2 = createClient(watcher, hostPort + \"/ch1\");\n        zk2.getChildren(\"/\", true );\n\n        // this call shouldn't trigger any error or watch\n        zk1.create(\"/youdontmatter1\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/youshouldmatter1\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        WatchedEvent e = watcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/\", e.getPath());\n\n        zk2.getChildren(\"/\", true );\n\n        stopServer();\n        watcher.waitForDisconnected(3000);\n        startServer();\n        watcher.waitForConnected(3000);\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/youshouldmatter2\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        e = watcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/\", e.getPath());\n    }\n    \n    @Test\n    public void testDeepChildWatcherAutoResetWithChroot() throws Exception {\n        ZooKeeper zk1 = createClient();\n\n        zk1.create(\"/ch1\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.create(\"/ch1/here\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.create(\"/ch1/here/we\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.create(\"/ch1/here/we/are\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        MyWatcher watcher = new MyWatcher();\n        ZooKeeper zk2 = createClient(watcher, hostPort + \"/ch1/here/we\");\n        zk2.getChildren(\"/are\", true );\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/here/we/are/now\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        WatchedEvent e = watcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/are\", e.getPath());\n\n        MyWatcher childWatcher = new MyWatcher();\n        zk2.getChildren(\"/are\", childWatcher);\n        \n        stopServer();\n        watcher.waitForDisconnected(3000);\n        startServer();\n        watcher.waitForConnected(3000);\n\n        // this should trigger the watch\n        zk1.create(\"/ch1/here/we/are/again\", null, Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        e = childWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertNotNull(e);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/are\", e.getPath());\n    }\n\n    // @see jira issue ZOOKEEPER-706. Test auto reset of a large number of\n    // watches which require multiple SetWatches calls.\n    @Test\n    public void testManyChildWatchersAutoReset() throws Exception {\n        ZooKeeper zk1 = createClient();\n\n        MyWatcher watcher = new MyWatcher();\n        ZooKeeper zk2 = createClient(watcher);\n\n        // 110 character base path\n        String pathBase = \"/long-path-000000000-111111111-222222222-333333333-444444444-\"\n                          + \"555555555-666666666-777777777-888888888-999999999\";\n\n        zk1.create(pathBase, null, Ids.OPEN_ACL_UNSAFE,\n                   CreateMode.PERSISTENT);\n\n        // Create 10,000 nodes. This should ensure the length of our\n        // watches set below exceeds 1MB.\n        List<String> paths = new ArrayList<String>();\n        for (int i = 0; i < 10000; i++) {\n            String path = zk1.create(pathBase + \"/ch-\", null, Ids.OPEN_ACL_UNSAFE,\n                                     CreateMode.PERSISTENT_SEQUENTIAL);\n            paths.add(path);\n        }\n\n        MyWatcher childWatcher = new MyWatcher();\n\n        // Set a combination of child/exists/data watches\n        int i = 0;\n        for (String path : paths) {\n            if (i % 3 == 0) {\n                zk2.getChildren(path, childWatcher);\n            } else if (i % 3 == 1) {\n                zk2.exists(path + \"/foo\", childWatcher);\n            } else if (i % 3 == 2) {\n                zk2.getData(path, childWatcher, null);\n            }\n\n            i++;\n        }\n\n        stopServer();\n        watcher.waitForDisconnected(30000);\n        startServer();\n        watcher.waitForConnected(30000);\n\n        // Trigger the watches and ensure they properly propagate to the client\n        i = 0;\n        for (String path : paths) {\n            if (i % 3 == 0) {\n                zk1.create(path + \"/ch\", null, Ids.OPEN_ACL_UNSAFE,\n                           CreateMode.PERSISTENT);\n\n                WatchedEvent e = childWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n                Assert.assertNotNull(e);\n                Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n                Assert.assertEquals(path, e.getPath());\n            } else if (i % 3 == 1) {\n                zk1.create(path + \"/foo\", null, Ids.OPEN_ACL_UNSAFE,\n                           CreateMode.PERSISTENT);\n\n                WatchedEvent e = childWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n                Assert.assertNotNull(e);\n                Assert.assertEquals(EventType.NodeCreated, e.getType());\n                Assert.assertEquals(path + \"/foo\", e.getPath());\n            } else if (i % 3 == 2) {\n                zk1.setData(path, new byte[]{1, 2, 3}, -1);\n\n                WatchedEvent e = childWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n                Assert.assertNotNull(e);\n                Assert.assertEquals(EventType.NodeDataChanged, e.getType());\n                Assert.assertEquals(path, e.getPath());\n            }\n\n            i++;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/EventTypeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.EnumSet;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class EventTypeTest extends ZKTestCase {\n    \n    @Test\n    public void testIntConversion() {\n        // Ensure that we can convert all valid integers to EventTypes\n        EnumSet<EventType> allTypes = EnumSet.allOf(EventType.class);\n\n        for(EventType et : allTypes) {\n            Assert.assertEquals(et, EventType.fromInt( et.getIntValue() ) );\n        }\n    }\n\n    @Test\n    public void testInvalidIntConversion() {\n        try {\n            EventType et = EventType.fromInt(324242);\n            Assert.fail(\"Was able to create an invalid EventType via an integer\");\n        } catch(RuntimeException re) {\n            // we're good.\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FLENewEpochTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.concurrent.Semaphore;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class FLENewEpochTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLENewEpochTest.class);\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    ArrayList<LEThread> threads;\n    File tmpdir[];\n    int port[];\n    volatile int [] round;\n\n    Semaphore start0;\n    Semaphore finish3, finish0;\n\n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        threads = new ArrayList<LEThread>(count);\n        tmpdir = new File[count];\n        port = new int[count];\n\n        round = new int[3];\n        round[0] = 0;\n        round[1] = 0;\n        round[2] = 0;\n\n        start0 = new Semaphore(0);\n        finish0 = new Semaphore(0);\n        finish3 = new Semaphore(0);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for(int i = 0; i < threads.size(); i++) {\n            ((FastLeaderElection) threads.get(i).peer.getElectionAlg()).shutdown();\n        }\n    }\n\n\n    class LEThread extends Thread {\n        int i;\n        QuorumPeer peer;\n\n        LEThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n\n        }\n\n        public void run(){\n            boolean flag = true;\n            try{\n                while(flag){\n                    Vote v = null;\n                    peer.setPeerState(ServerState.LOOKING);\n                    LOG.info(\"Going to call leader election again: \" + i);\n                    v = peer.getElectionAlg().lookForLeader();\n\n                    if (v == null){\n                        Assert.fail(\"Thread \" + i + \" got a null vote\");\n                    }\n\n                    /*\n                     * A real zookeeper would take care of setting the current vote. Here\n                     * we do it manually.\n                     */\n                    peer.setCurrentVote(v);\n\n                    LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n                    //votes[i] = v;\n\n                    switch (i) {\n                    case 0:\n                        LOG.info(\"First peer, do nothing, just join\");\n                        if(finish0.tryAcquire(1000, java.util.concurrent.TimeUnit.MILLISECONDS)){\n                        //if(threads.get(0).peer.getPeerState() == ServerState.LEADING ){\n                            LOG.info(\"Setting flag to false\");\n                            flag = false;\n                        }\n                        break;\n                    case 1:\n                        LOG.info(\"Second entering case\");\n                        if(round[1] != 0){\n                            finish0.release();\n                            flag = false;\n                        } else {\n                            finish3.acquire();\n                            start0.release();\n                        }\n                        LOG.info(\"Second is going to start second round\");\n                        round[1]++;\n                        break;\n                    case 2:\n                        LOG.info(\"Third peer, shutting it down\");\n                        QuorumBase.shutdown(peer);\n                        flag = false;\n                        round[2] = 1;\n                        finish3.release();\n                        LOG.info(\"Third leaving\");\n                        break;\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n\n      @Test\n      public void testLENewEpoch() throws Exception {\n\n          FastLeaderElection le[] = new FastLeaderElection[count];\n\n          LOG.info(\"TestLE: \" + getTestName()+ \", \" + count);\n          for(int i = 0; i < count; i++) {\n              peers.put(Long.valueOf(i),\n                        new QuorumServer(i, \"0.0.0.0\", PortAssignment.unique(),\n                                         PortAssignment.unique(), null));\n              tmpdir[i] = ClientBase.createTmpDir();\n              port[i] = PortAssignment.unique();\n          }\n\n          for(int i = 1; i < le.length; i++) {\n              QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i], port[i], 3, i, 1000, 2, 2);\n              peer.startLeaderElection();\n              LEThread thread = new LEThread(peer, i);\n              thread.start();\n              threads.add(thread);\n          }\n          if(!start0.tryAcquire(4000, java.util.concurrent.TimeUnit.MILLISECONDS))\n              Assert.fail(\"First leader election failed\");\n\n          QuorumPeer peer = new QuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 3, 0, 1000, 2, 2);\n          peer.startLeaderElection();\n          LEThread thread = new LEThread(peer, 0);\n          thread.start();\n          threads.add(thread);\n\n          LOG.info(\"Started threads \" + getTestName());\n\n          for(int i = 0; i < threads.size(); i++) {\n              threads.get(i).join(10000);\n              if (threads.get(i).isAlive()) {\n                  Assert.fail(\"Threads didn't join\");\n              }\n\n          }\n      }\n  }\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\n\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumCnxManager;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class FLEPredicateTest extends ZKTestCase {\n    \n    protected static final Logger LOG = LoggerFactory.getLogger(FLEPredicateTest.class);\n    \n    class MockFLE extends FastLeaderElection {\n        MockFLE(QuorumPeer peer){\n            super(peer, peer.createCnxnManager());\n        }\n        \n        boolean predicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch){\n            return this.totalOrderPredicate(newId, newZxid, newEpoch, curId, curZxid, curEpoch);\n        }\n    }\n    \n    \n    HashMap<Long,QuorumServer> peers;\n    \n    @Test\n    public void testPredicate() throws IOException {\n        \n        peers = new HashMap<Long,QuorumServer>(3);\n        \n        /*\n         * Creates list of peers.\n         */\n        for(int i = 0; i < 3; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n        }\n\n        /*\n         * Creating peer.\n         */\n        try{\n            File tmpDir = ClientBase.createTmpDir();\n            QuorumPeer peer = new QuorumPeer(peers, tmpDir, tmpDir,\n                                        PortAssignment.unique(), 3, 0, 1000, 2, 2);\n        \n            MockFLE mock = new MockFLE(peer);\n            \n            /*\n             * Lower epoch must return false\n             */\n            \n            Assert.assertFalse (mock.predicate(4L, 0L, 0L, 3L, 0L, 2L));\n            \n            /*\n             * Later epoch\n             */\n            Assert.assertTrue (mock.predicate(0L, 0L, 1L, 1L, 0L, 0L));\n        \n            /*\n             * Higher zxid\n             */\n            Assert.assertTrue(mock.predicate(0L, 1L, 0L, 1L, 0L, 0L));\n        \n            /*\n             * Higher id\n             */\n            Assert.assertTrue(mock.predicate(1L, 1L, 0L, 0L, 1L, 0L));\n        } catch (IOException e) {\n            LOG.error(\"Exception while creating quorum peer\", e);\n            Assert.fail(\"Exception while creating quorum peer\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FLERestartTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.util.concurrent.Semaphore;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class FLERestartTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLETest.class);\n\n    static class TestVote {\n        TestVote(int id, long leader) {\n            this.leader = leader;\n        }\n\n        long leader;\n    }\n\n    int countVotes(HashSet<TestVote> hs, long id) {\n        int counter = 0;\n        for(TestVote v : hs){\n            if(v.leader == id) counter++;\n        }\n\n        return counter;\n    }\n\n    int count;\n    //    int baseport;\n    //    int baseLEport;\n    HashMap<Long,QuorumServer> peers;\n    ArrayList<FLERestartThread> restartThreads;\n    HashMap<Integer, HashSet<TestVote> > voteMap;\n    File tmpdir[];\n    int port[];\n    int successCount;\n    Semaphore finish;\n\n    volatile Vote votes[];\n    volatile boolean leaderDies;\n    volatile long leader = -1;\n    //volatile int round = 1;\n    Random rand = new Random();\n\n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        restartThreads = new ArrayList<FLERestartThread>(count);\n        voteMap = new HashMap<Integer, HashSet<TestVote> >();\n        votes = new Vote[count];\n        tmpdir = new File[count];\n        port = new int[count];\n        successCount = 0;\n        finish = new Semaphore(0);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for(int i = 0; i < restartThreads.size(); i++) {\n            ((FastLeaderElection) restartThreads.get(i).peer.getElectionAlg()).shutdown();\n        }\n    }\n\n    class FLERestartThread extends Thread {\n        int i;\n        QuorumPeer peer;\n        int peerRound = 0;\n\n        FLERestartThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n        }\n        public void run() {\n            try {\n                Vote v = null;\n                while(true) {\n                    peer.setPeerState(ServerState.LOOKING);\n                    LOG.info(\"Going to call leader election again.\");\n                    v = peer.getElectionAlg().lookForLeader();\n                    if(v == null){\n                        LOG.info(\"Thread \" + i + \" got a null vote\");\n                        break;\n                    }\n\n                    /*\n                     * A real zookeeper would take care of setting the current vote. Here\n                     * we do it manually.\n                     */\n                    peer.setCurrentVote(v);\n\n                    LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n                    //votes[i] = v;\n\n                    switch(i){\n                    case 0:\n                        if(peerRound == 0){\n                            LOG.info(\"First peer, shutting it down\");\n                            QuorumBase.shutdown(peer);\n                            ((FastLeaderElection) restartThreads.get(i).peer.getElectionAlg()).shutdown();\n\n                            peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i], port[i], 3, i, 1000, 2, 2);\n                            peer.startLeaderElection();\n                            peerRound++;\n                        } else {\n                            finish.release(2);\n                            return;\n                        }\n\n                        break;\n                    case 1:\n                        LOG.info(\"Second entering case\");\n                        finish.acquire();\n                        //if(threads.get(0).peer.getPeerState() == ServerState.LEADING ){\n                        LOG.info(\"Release\");\n\n                        return;\n                    case 2:\n                        LOG.info(\"First peer, do nothing, just join\");\n                        finish.acquire();\n                        //if(threads.get(0).peer.getPeerState() == ServerState.LEADING ){\n                        LOG.info(\"Release\");\n\n                        return;\n                    }\n                }\n            } catch (Exception e){\n                e.printStackTrace();\n            }\n        }\n    }\n\n\n    @Test\n    public void testLERestart() throws Exception {\n\n        FastLeaderElection le[] = new FastLeaderElection[count];\n        leaderDies = true;\n        boolean allowOneBadLeader = leaderDies;\n\n        LOG.info(\"TestLE: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = PortAssignment.unique();\n        }\n\n        for(int i = 0; i < count; i++) {\n            QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i], port[i], 3, i, 1000, 2, 2);\n            peer.startLeaderElection();\n            FLERestartThread thread = new FLERestartThread(peer, i);\n            thread.start();\n            restartThreads.add(thread);\n        }\n        LOG.info(\"Started threads \" + getTestName());\n        for(int i = 0; i < restartThreads.size(); i++) {\n            restartThreads.get(i).join(10000);\n            if (restartThreads.get(i).isAlive()) {\n                Assert.fail(\"Threads didn't join\");\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FLETest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class FLETest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(FLETest.class);\n    private FLETest.LEThread leThread;\n\n    static class TestVote {\n        TestVote(int id, long leader) {\n            this.leader = leader;\n        }\n\n        long leader;\n    }\n\n    int countVotes(HashSet<TestVote> hs, long id) {\n        int counter = 0;\n        for(TestVote v : hs){\n            if(v.leader == id) counter++;\n        }\n\n        return counter;\n    }\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    ArrayList<LEThread> threads;\n    HashMap<Integer, HashSet<TestVote> > voteMap;\n    File tmpdir[];\n    int port[];\n    int successCount;\n    Object finalObj;\n\n    volatile Vote votes[];\n    volatile boolean leaderDies;\n    volatile long leader = -1;\n    //volatile int round = 1;\n    Random rand = new Random();\n    Set<Long> joinedThreads;\n\n    @Before\n    public void setUp() throws Exception {\n        count = 7;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        threads = new ArrayList<LEThread>(count);\n        voteMap = new HashMap<Integer, HashSet<TestVote> >();\n        votes = new Vote[count];\n        tmpdir = new File[count];\n        port = new int[count];\n        successCount = 0;\n        finalObj = new Object();\n        joinedThreads = new HashSet<Long>();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for (int i = 0; i < threads.size(); i++) {\n            leThread = threads.get(i);\n            QuorumBase.shutdown(leThread.peer);\n        }\n    }\n\n    class LEThread extends Thread {\n        int i;\n        QuorumPeer peer;\n        //int peerRound = 1;\n\n        LEThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n        }\n        public void run() {\n            try {\n                Vote v = null;\n                while(true) {\n                    peer.setPeerState(ServerState.LOOKING);\n                    LOG.info(\"Going to call leader election again.\");\n                    v = peer.getElectionAlg().lookForLeader();\n                    if(v == null){\n                        LOG.info(\"Thread \" + i + \" got a null vote\");\n                        break;\n                    }\n\n                    /*\n                     * A real zookeeper would take care of setting the current vote. Here\n                     * we do it manually.\n                     */\n                    peer.setCurrentVote(v);\n\n                    LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n                    votes[i] = v;\n\n                    /*\n                     * Get the current value of the logical clock for this peer.\n                     */\n                    int lc = (int) ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock();\n\n                    if (v.getId() == i) {\n                        /*\n                         * A leader executes this part of the code. If it is the first leader to be\n                         * elected, then it Assert.fails right after. Otherwise, it waits until it has enough\n                         * followers supporting it.\n                         */\n                        LOG.info(\"I'm the leader: \" + i);\n                        synchronized(FLETest.this) {\n                            if (leaderDies) {\n                                LOG.info(\"Leader \" + i + \" dying\");\n                                leaderDies = false;\n                                ((FastLeaderElection) peer.getElectionAlg()).shutdown();\n                                leader = -1;\n                                LOG.info(\"Leader \" + i + \" dead\");\n\n                                //round++;\n                                FLETest.this.notifyAll();\n\n                                break;\n\n                            } else {\n                                synchronized(voteMap){\n                                    if(voteMap.get(lc) == null)\n                                        voteMap.put(lc, new HashSet<TestVote>());\n                                    HashSet<TestVote> hs = voteMap.get(lc);\n                                    hs.add(new TestVote(i, v.getId()));\n\n                                    if(countVotes(hs, v.getId()) > (count/2)){\n                                        leader = i;\n                                        LOG.info(\"Got majority: \" + i);\n                                    } else {\n                                        voteMap.wait(3000);\n                                        LOG.info(\"Notified or expired: \" + i);\n                                        hs = voteMap.get(lc);\n                                        if(countVotes(hs, v.getId()) > (count/2)){\n                                            leader = i;\n                                            LOG.info(\"Got majority: \" + i);\n                                        } else {\n                                            //round++;\n                                        }\n                                    }\n                                }\n                                FLETest.this.notifyAll();\n\n                                if(leader == i){\n                                    synchronized(finalObj){\n                                        successCount++;\n                                        joinedThreads.add((long)i);\n                                        if(successCount > (count/2)) finalObj.notify();\n                                    }\n\n                                    break;\n                                }\n                            }\n                        }\n                    } else {\n                        /*\n                         * Followers execute this part. They first add their vote to voteMap, and then\n                         * they wait for bounded amount of time. A leader notifies followers through the\n                         * FLETest.this object.\n                         *\n                         * Note that I can get FLETest.this, and then voteMap before adding the vote of\n                         * a follower, otherwise a follower would be blocked out until the leader notifies\n                         * or leaves the synchronized block on FLEtest.this.\n                         */\n\n\n                        LOG.info(\"Logical clock \" + ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock());\n                        synchronized(voteMap){\n                            LOG.info(\"Voting on \" + votes[i].getId() + \", round \" + ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock());\n                            if(voteMap.get(lc) == null)\n                                voteMap.put(lc, new HashSet<TestVote>());\n                            HashSet<TestVote> hs = voteMap.get(lc);\n                            hs.add(new TestVote(i, votes[i].getId()));\n                            if(countVotes(hs, votes[i].getId()) > (count/2)){\n                                LOG.info(\"Logical clock: \" + lc + \", \" + votes[i].getId());\n                                voteMap.notify();\n                            }\n                        }\n\n                        /*\n                         * In this part a follower waits until the leader notifies it, and remove its\n                         * vote if the leader takes too long to respond.\n                         */\n                        synchronized(FLETest.this){\n                            if (leader != votes[i].getId()) FLETest.this.wait(3000);\n\n                            LOG.info(\"The leader: \" + leader + \" and my vote \" + votes[i].getId());\n                            synchronized(voteMap){\n                                if (leader == votes[i].getId()) {\n                                    synchronized(finalObj){\n                                        successCount++;\n                                        joinedThreads.add((long)i);\n                                        if(successCount > (count/2)) finalObj.notify();\n                                    }\n                                    break;\n                                } else {\n                                    HashSet<TestVote> hs = voteMap.get(lc);\n                                    TestVote toRemove = null;\n                                    for(TestVote tv : hs){\n                                        if(v.getId() == i){\n                                            toRemove = tv;\n                                            break;\n                                        }\n                                    }\n                                    hs.remove(toRemove);\n                                }\n                            }\n                        }\n                    }\n                    /*\n                     * Add some randomness to the execution.\n                     */\n                    Thread.sleep(rand.nextInt(500));\n                    peer.setCurrentVote(new Vote(peer.getId(), 0));\n                }\n                LOG.debug(\"Thread \" + i + \" votes \" + v);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Test\n    public void testLE() throws Exception {\n\n        FastLeaderElection le[] = new FastLeaderElection[count];\n        leaderDies = true;\n        boolean allowOneBadLeader = leaderDies;\n\n        LOG.info(\"TestLE: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = PortAssignment.unique();\n        }\n\n        for(int i = 0; i < le.length; i++) {\n            QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i],\n                    port[i], 3, i, 1000, 2, 2);\n            peer.startLeaderElection();\n            LEThread thread = new LEThread(peer, i);\n            thread.start();\n            threads.add(thread);\n        }\n        LOG.info(\"Started threads \" + getTestName());\n\n\n        int waitCounter = 0;\n        synchronized(finalObj){\n            while((successCount <= count/2) && (waitCounter < 50)){\n                finalObj.wait(2000);\n                waitCounter++;\n            }\n        }\n\n        /*\n        * Lists what threads haven-t joined. A thread doesn't join if\n        * it hasn't decided upon a leader yet. It can happen that a\n        * peer is slow or disconnected, and it can take longer to\n        * nominate and connect to the current leader.\n        */\n       for (int i = 0; i < threads.size(); i++) {\n            if (threads.get(i).isAlive()) {\n                LOG.info(\"Threads didn't join: \" + i);\n            }\n        }\n\n       /*\n        * If we have a majority, then we are good to go.\n        */\n       if(successCount <= count/2){\n           Assert.fail(\"Fewer than a a majority has joined\");\n       }\n\n       synchronized(finalObj){\n           if(!joinedThreads.contains(leader)){\n               Assert.fail(\"Leader hasn't joined: \" + leader);\n           }\n       }\n    }\n\n    /*\n     * Class to verify of the thread has become a follower\n     */\n    class VerifyState extends Thread {\n        volatile private boolean success = false;\n        QuorumPeer peer;\n        public VerifyState(QuorumPeer peer) {\n            this.peer = peer;\n        }\n        public void run() {\n            setName(\"VerifyState-\" + peer.getId());\n            while (true) {\n                if(peer.getPeerState() == ServerState.FOLLOWING) {\n                    LOG.info(\"I am following\");\n                    success = true;\n                    break;\n                } else if (peer.getPeerState() == ServerState.LEADING) {\n                    LOG.info(\"I am leading\");\n                    success = false;\n                    break;\n                }\n                try {\n                    Thread.sleep(250);\n                } catch (Exception e) {\n                    LOG.warn(\"Sleep failed \", e);\n                }\n            }\n        }\n        public boolean isSuccess() {\n            return success;\n        }\n    }\n\n    /*\n     * For ZOOKEEPER-975 verify that a peer joining an established cluster\n     * does not go in LEADING state.\n     */\n    @Test\n    public void testJoin() throws Exception {\n        int sid;\n        QuorumPeer peer;\n        int waitTime = 10 * 1000;\n        ArrayList<QuorumPeer> peerList = new ArrayList<QuorumPeer>();\n        for(sid = 0; sid < 3; sid++) {\n            peers.put(Long.valueOf(sid),\n                      new QuorumServer(sid, \"0.0.0.0\", PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n            tmpdir[sid] = ClientBase.createTmpDir();\n            port[sid] = PortAssignment.unique();\n        }\n        // start 2 peers and verify if they form the cluster\n        for (sid = 0; sid < 2; sid++) {\n            peer = new QuorumPeer(peers, tmpdir[sid], tmpdir[sid],\n                                             port[sid], 3, sid, 2000, 2, 2);\n            LOG.info(\"Starting peer \" + peer.getId());\n            peer.start();\n            peerList.add(sid, peer);\n        }\n        peer = peerList.get(0);\n        VerifyState v1 = new VerifyState(peerList.get(0));\n        v1.start();\n        v1.join(waitTime);\n        Assert.assertFalse(\"Unable to form cluster in \" +\n            waitTime + \" ms\",\n            !v1.isSuccess());\n        // Start 3rd peer and check if it goes in LEADING state\n        peer = new QuorumPeer(peers, tmpdir[sid], tmpdir[sid],\n                 port[sid], 3, sid, 2000, 2, 2);\n        LOG.info(\"Starting peer \" + peer.getId());\n        peer.start();\n        peerList.add(sid, peer);\n        v1 = new VerifyState(peer);\n        v1.start();\n        v1.join(waitTime);\n        if (v1.isAlive()) {\n               Assert.fail(\"Peer \" + peer.getId() + \" failed to join the cluster \" +\n                \"within \" + waitTime + \" ms\");\n        } else if (!v1.isSuccess()) {\n               Assert.fail(\"Incorrect LEADING state for peer \" + peer.getId());\n        }\n        // cleanup\n        for (int id = 0; id < 3; id++) {\n            peer = peerList.get(id);\n            if (peer != null) {\n                peer.shutdown();\n            }\n        }\n    }\n\n    /*\n     * For ZOOKEEPER-1732 verify that it is possible to join an ensemble with\n     * inconsistent election round information.\n     */\n    @Test\n    public void testJoinInconsistentEnsemble() throws Exception {\n        int sid;\n        QuorumPeer peer;\n        int waitTime = 10 * 1000;\n        ArrayList<QuorumPeer> peerList = new ArrayList<QuorumPeer>();\n        for(sid = 0; sid < 3; sid++) {\n            peers.put(Long.valueOf(sid),\n                      new QuorumServer(sid, \"0.0.0.0\", PortAssignment.unique(),\n                                       PortAssignment.unique(), null));\n            tmpdir[sid] = ClientBase.createTmpDir();\n            port[sid] = PortAssignment.unique();\n        }\n        // start 2 peers and verify if they form the cluster\n        for (sid = 0; sid < 2; sid++) {\n            peer = new QuorumPeer(peers, tmpdir[sid], tmpdir[sid],\n                                             port[sid], 3, sid, 2000, 2, 2);\n            LOG.info(\"Starting peer \" + peer.getId());\n            peer.start();\n            peerList.add(sid, peer);\n        }\n        peer = peerList.get(0);\n        VerifyState v1 = new VerifyState(peerList.get(0));\n        v1.start();\n        v1.join(waitTime);\n        Assert.assertFalse(\"Unable to form cluster in \" +\n            waitTime + \" ms\",\n            !v1.isSuccess());\n        // Change the election round for one of the members of the ensemble\n        long leaderSid = peer.getCurrentVote().getId();\n        long zxid = peer.getCurrentVote().getZxid();\n        long electionEpoch = peer.getCurrentVote().getElectionEpoch();\n        ServerState state = peer.getCurrentVote().getState();\n        long peerEpoch = peer.getCurrentVote().getPeerEpoch();\n        Vote newVote = new Vote(leaderSid, zxid+100, electionEpoch+100, peerEpoch, state);\n        peer.setCurrentVote(newVote);\n        // Start 3rd peer and check if it joins the quorum\n        peer = new QuorumPeer(peers, tmpdir[2], tmpdir[2],\n                 port[2], 3, 2, 2000, 2, 2);\n        LOG.info(\"Starting peer \" + peer.getId());\n        peer.start();\n        peerList.add(sid, peer);\n        v1 = new VerifyState(peer);\n        v1.start();\n        v1.join(waitTime);\n        if (v1.isAlive()) {\n               Assert.fail(\"Peer \" + peer.getId() + \" failed to join the cluster \" +\n                \"within \" + waitTime + \" ms\");\n        }\n        // cleanup\n        for (int id = 0; id < 3; id++) {\n            peer = peerList.get(id);\n            if (peer != null) {\n                peer.shutdown();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Properties;\nimport java.util.Random;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.FastLeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class FLEZeroWeightTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(HierarchicalQuorumTest.class);\n\n    Properties qp;\n\n    int count;\n    HashMap<Long,QuorumServer> peers;\n    ArrayList<LEThread> threads;\n    File tmpdir[];\n    int port[];\n    Object finalObj;\n\n    volatile Vote votes[];\n    volatile boolean leaderDies;\n    volatile long leader = -1;\n    Random rand = new Random();\n\n\n    @Before\n    public void setUp() throws Exception {\n        count = 9;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        threads = new ArrayList<LEThread>(count);\n        votes = new Vote[count];\n        tmpdir = new File[count];\n        port = new int[count];\n        finalObj = new Object();\n\n        String config = \"group.1=0:1:2\\n\" +\n        \"group.2=3:4:5\\n\" +\n        \"group.3=6:7:8\\n\" +\n        \"weight.0=1\\n\" +\n        \"weight.1=1\\n\" +\n        \"weight.2=1\\n\" +\n        \"weight.3=0\\n\" +\n        \"weight.4=0\\n\" +\n        \"weight.5=0\\n\" +\n        \"weight.6=0\\n\" +\n        \"weight.7=0\\n\" +\n        \"weight.8=0\";\n\n        ByteArrayInputStream is = new ByteArrayInputStream(config.getBytes());\n        this.qp = new Properties();\n        qp.load(is);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        for(int i = 0; i < threads.size(); i++) {\n            LEThread leThread = threads.get(i);\n            // shutdown() has to be explicitly called for every thread to\n            // make sure that resources are freed properly and all fixed network ports\n            // are available for other test cases\n            QuorumBase.shutdown(leThread.peer);\n        }\n    }\n\n    class LEThread extends Thread {\n        int i;\n        QuorumPeer peer;\n        boolean fail;\n\n        LEThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n        }\n\n        public void run() {\n            try {\n                Vote v = null;\n                fail = false;\n                while(true){\n\n                    //while(true) {\n                    peer.setPeerState(ServerState.LOOKING);\n                    LOG.info(\"Going to call leader election.\");\n                    v = peer.getElectionAlg().lookForLeader();\n                    if(v == null){\n                        LOG.info(\"Thread \" + i + \" got a null vote\");\n                        return;\n                    }\n\n                    /*\n                     * A real zookeeper would take care of setting the current vote. Here\n                     * we do it manually.\n                     */\n                    peer.setCurrentVote(v);\n\n                    LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n                    votes[i] = v;\n\n                    if((peer.getPeerState() == ServerState.LEADING) &&\n                            (peer.getId() > 2)) fail = true;\n\n                    if((peer.getPeerState() == ServerState.FOLLOWING) ||\n                            (peer.getPeerState() == ServerState.LEADING)) break;\n                }\n                LOG.debug(\"Thread \" + i + \" votes \" + v);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Test\n    public void testZeroWeightQuorum() throws Exception {\n        FastLeaderElection le[] = new FastLeaderElection[count];\n\n        LOG.info(\"TestZeroWeightQuorum: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"0.0.0.0\", PortAssignment.unique(), PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = PortAssignment.unique();\n        }\n\n        for(int i = 0; i < le.length; i++) {\n            QuorumHierarchical hq = new QuorumHierarchical(qp);\n            QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i], port[i], 3, i, 1000, 2, 2, hq);\n            peer.startLeaderElection();\n            LEThread thread = new LEThread(peer, i);\n            thread.start();\n            threads.add(thread);\n        }\n        LOG.info(\"Started threads \" + getTestName());\n\n        for(int i = 0; i < threads.size(); i++) {\n            threads.get(i).join(15000);\n            if (threads.get(i).isAlive()) {\n                Assert.fail(\"Threads didn't join\");\n            } else {\n                if(threads.get(i).fail)\n                    Assert.fail(\"Elected zero-weight server\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FollowerResyncConcurrencyTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.log4j.Logger;\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n\npublic class FollowerResyncConcurrencyTest extends ZKTestCase {\n    private static final Logger LOG = Logger.getLogger(FollowerResyncConcurrencyTest.class);\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    private volatile int counter = 0;\n    private volatile int errors = 0;\n\n    /**\n     * See ZOOKEEPER-1319 - verify that a lagging follwer resyncs correctly\n     * \n     * 1) start with down quorum\n     * 2) start leader/follower1, add some data\n     * 3) restart leader/follower1\n     * 4) start follower2\n     * 5) verify data consistency across the ensemble\n     * \n     * @throws Exception\n     */\n    @Test\n    public void testLaggingFollowerResyncsUnderNewEpoch() throws Exception {\n        CountdownWatcher watcher1 = new CountdownWatcher();\n        CountdownWatcher watcher2 = new CountdownWatcher();\n        CountdownWatcher watcher3 = new CountdownWatcher();\n\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.shutdownAll();\n\n        qu.start(1);\n        qu.start(2);\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + qu.getPeer(1).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + qu.getPeer(2).clientPort, ClientBase.CONNECTION_TIMEOUT));\n\n        ZooKeeper zk1 =\n                createClient(qu.getPeer(1).peer.getClientPort(), watcher1);\n        LOG.info(\"zk1 has session id 0x\" + Long.toHexString(zk1.getSessionId()));\n\n        final String resyncPath = \"/resyncundernewepoch\";\n        zk1.create(resyncPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk1.close();\n\n        qu.shutdown(1);\n        qu.shutdown(2);\n        Assert.assertTrue(\"Waiting for server down\", ClientBase.waitForServerDown(\"127.0.0.1:\"\n                + qu.getPeer(1).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"Waiting for server down\", ClientBase.waitForServerDown(\"127.0.0.1:\"\n                + qu.getPeer(2).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        \n        qu.start(1);\n        qu.start(2);\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + qu.getPeer(1).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + qu.getPeer(2).clientPort, ClientBase.CONNECTION_TIMEOUT));\n\n        qu.start(3);\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + qu.getPeer(3).clientPort, ClientBase.CONNECTION_TIMEOUT));\n\n        zk1 = createClient(qu.getPeer(1).peer.getClientPort(), watcher1);\n        LOG.info(\"zk1 has session id 0x\" + Long.toHexString(zk1.getSessionId()));\n        \n        assertNotNull(\"zk1 has data\", zk1.exists(resyncPath, false));\n\n        final ZooKeeper zk2 =\n                createClient(qu.getPeer(2).peer.getClientPort(), watcher2);\n        LOG.info(\"zk2 has session id 0x\" + Long.toHexString(zk2.getSessionId()));\n\n        assertNotNull(\"zk2 has data\", zk2.exists(resyncPath, false));\n\n        final ZooKeeper zk3 =\n            createClient(qu.getPeer(3).peer.getClientPort(), watcher3);\n        LOG.info(\"zk3 has session id 0x\" + Long.toHexString(zk3.getSessionId()));\n\n        assertNotNull(\"zk3 has data\", zk3.exists(resyncPath, false));\n\n        zk1.close();\n        zk2.close();\n        zk3.close();\n        \n        qu.shutdownAll();\n    }      \n\n    /**\n     * See ZOOKEEPER-962. This tests for one of the bugs hit while fixing this,\n     * setting the ZXID of the SNAP packet\n     * Starts up 3 ZKs. Shut down F1, write a node, restart the one that was shut down\n     * The non-leader ZKs are writing to cluster\n     * Shut down F1 again\n     * Restart after sessions are expired, expect to get a snap file\n     * Shut down, run some transactions through.\n     * Restart to a diff while transactions are running in leader\n     * @throws IOException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    @Test\n    public void testResyncBySnapThenDiffAfterFollowerCrashes() \n        throws IOException, InterruptedException, KeeperException,  Throwable\n    {\n        final Semaphore sem = new Semaphore(0);\n\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n        CountdownWatcher watcher1 = new CountdownWatcher();\n        CountdownWatcher watcher2 = new CountdownWatcher();\n        CountdownWatcher watcher3 = new CountdownWatcher();\n\n        int index = 1;\n        while(qu.getPeer(index).peer.leader == null) {\n            index++;\n        }\n\n        Leader leader = qu.getPeer(index).peer.leader;\n        assertNotNull(leader);    \n\n        /* Reusing the index variable to select a follower to connect to */\n        index = (index == 1) ? 2 : 1;\n        LOG.info(\"Connecting to follower:\" + index);\n\n        qu.shutdown(index);\n\n        final ZooKeeper zk3 =\n            createClient(qu.getPeer(3).peer.getClientPort(), watcher3);\n        LOG.info(\"zk3 has session id 0x\" + Long.toHexString(zk3.getSessionId()));\n\n        zk3.create(\"/mybar\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);\n\n        qu.restart(index);\n        final ZooKeeper zk1 =\n            createClient(qu.getPeer(index).peer.getClientPort(), watcher1);\n        LOG.info(\"zk1 has session id 0x\" + Long.toHexString(zk1.getSessionId()));\n\n        final ZooKeeper zk2 =\n            createClient(qu.getPeer(index).peer.getClientPort(), watcher2);\n        LOG.info(\"zk2 has session id 0x\" + Long.toHexString(zk2.getSessionId()));\n        \n        zk1.create(\"/first\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Thread mytestfooThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                for(int i = 0; i < 3000; i++) {\n                    zk3.create(\"/mytestfoo\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n\n                        @Override\n                        public void processResult(int rc, String path, Object ctx, String name) {\n                            counter++;\n                            if (rc != 0) {\n                                errors++;\n                            }\n                            if(counter == 16200){\n                                sem.release();\n                            }\n                        }\n                    }, null);\n                    if(i%10==0){\n                        try {\n                            Thread.sleep(100);\n                        } catch (Exception e) {\n\n                        }\n                    }\n                }\n\n            }\n        });\n\n        for(int i = 0; i < 13000; i++) {\n            zk3.create(\"/mybar\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n\n                @Override\n                public void processResult(int rc, String path, Object ctx, String name) {\n                    counter++;\n                    if (rc != 0) {\n                        errors++;\n                    }\n                    if(counter == 16200){\n                        sem.release();\n                    }\n                }\n            }, null);            \n\n            if(i == 5000){\n                qu.shutdown(index);               \n                LOG.info(\"Shutting down s1\");\n            }\n            if(i == 12000){\n                //Restart off of snap, then get some txns for a log, then shut down\n                mytestfooThread.start();\n                qu.restart(index);       \n                Thread.sleep(300);\n                qu.shutdown(index);               \n                Thread.sleep(300);                \n                qu.restart(index);\n                LOG.info(\"Setting up server: \" + index);\n            }\n            if((i % 1000) == 0){\n                Thread.sleep(1000);\n            }\n\n            if(i%50 == 0) {\n                zk2.create(\"/newbaz\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n                    @Override\n                    public void processResult(int rc, String path, Object ctx, String name) {\n                        counter++;\n                        if (rc != 0) {\n                            errors++;\n                        }\n                        if(counter == 16200){\n                            sem.release();\n                        }\n                    }\n                }, null);\n            }\n        }\n\n        // Wait until all updates return\n        if(!sem.tryAcquire(ClientBase.CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)) {\n            LOG.warn(\"Did not aquire semaphore fast enough\");\n        }\n        mytestfooThread.join(ClientBase.CONNECTION_TIMEOUT);\n        if (mytestfooThread.isAlive()) {\n            LOG.error(\"mytestfooThread is still alive\");\n        }\n        Thread.sleep(1000);\n        \n        verifyState(qu, index, leader);\n        \n        zk1.close();\n        zk2.close();\n        zk3.close();\n        \n        qu.shutdownAll();\n    }      \n    \n    /**\n     * This test:\n     * Starts up 3 ZKs. The non-leader ZKs are writing to cluster\n     * Shut down one of the non-leader ZKs. \n     * Restart after sessions have expired but <500 txns have taken place (get a diff)\n     * Shut down immediately after restarting, start running separate thread with other transactions\n     * Restart to a diff while transactions are running in leader\n     * \n     * \n     * Before fixes for ZOOKEEPER-962, restarting off of diff could get an inconsistent view of data missing transactions that\n     * completed during diff syncing. Follower would also be considered \"restarted\" before all forwarded transactions\n     * were completely processed, so restarting would cause a snap file with a too-high zxid to be written, and transactions\n     * would be missed\n     * \n     * This test should pretty reliably catch the failure of restarting the server before all diff messages have been processed,\n     * however, due to the transient nature of the system it may not catch failures due to concurrent processing of transactions\n     * during the leader's diff forwarding.\n     * \n     * @throws IOException\n     * @throws InterruptedException\n     * @throws KeeperException\n     * @throws Throwable\n     */\n\n    @Test\n    public void testResyncByDiffAfterFollowerCrashes() \n        throws IOException, InterruptedException, KeeperException, Throwable\n    {\n        final Semaphore sem = new Semaphore(0);\n\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n        CountdownWatcher watcher1 = new CountdownWatcher();\n        CountdownWatcher watcher2 = new CountdownWatcher();\n        CountdownWatcher watcher3 = new CountdownWatcher();\n\n        int index = 1;\n        while(qu.getPeer(index).peer.leader == null) {\n            index++;\n        }\n\n        Leader leader = qu.getPeer(index).peer.leader;\n        assertNotNull(leader);\n\n        /* Reusing the index variable to select a follower to connect to */\n        index = (index == 1) ? 2 : 1;\n        LOG.info(\"Connecting to follower:\" + index);\n\n        final ZooKeeper zk1 =\n            createClient(qu.getPeer(index).peer.getClientPort(), watcher1);\n        LOG.info(\"zk1 has session id 0x\" + Long.toHexString(zk1.getSessionId()));\n\n        final ZooKeeper zk2 =\n            createClient(qu.getPeer(index).peer.getClientPort(), watcher2);\n        LOG.info(\"zk2 has session id 0x\" + Long.toHexString(zk2.getSessionId()));\n\n        final ZooKeeper zk3 =\n            createClient(qu.getPeer(3).peer.getClientPort(), watcher3);\n        LOG.info(\"zk3 has session id 0x\" + Long.toHexString(zk3.getSessionId()));\n\n        zk1.create(\"/first\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk2.create(\"/mybar\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);\n\n        final AtomicBoolean runNow = new AtomicBoolean(false);\n        Thread mytestfooThread = new Thread(new Runnable() {\n            @Override\n            public void run() {                                \n                int inSyncCounter = 0;\n                while(inSyncCounter < 400) {    \n                    if(runNow.get()) {\n                        zk3.create(\"/mytestfoo\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n\n                            @Override\n                            public void processResult(int rc, String path, Object ctx, String name) {\n                                counter++;\n                                if (rc != 0) {\n                                    errors++;\n                                }\n                                if(counter > 7300){\n                                    sem.release();\n                                }\n                            }\n                        }, null);\n                        \n                        try {\n                            Thread.sleep(10);\n                        } catch (Exception e) {\n                        }\n                        inSyncCounter++;\n                    } else {\n                        Thread.yield();\n                    }\n                }\n\n            }\n        });\n\n        mytestfooThread.start();\n        for(int i = 0; i < 5000; i++) {\n            zk2.create(\"/mybar\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n\n                @Override\n                public void processResult(int rc, String path, Object ctx, String name) {\n                    counter++;\n                    if (rc != 0) {\n                        errors++;\n                    }\n                    if(counter > 7300){\n                        sem.release();\n                    }\n                }\n            }, null);            \n\n            if(i == 1000){\n                qu.shutdown(index);      \n                Thread.sleep(1100);\n                LOG.info(\"Shutting down s1\");\n            }\n            if(i == 1100 || i == 1150 || i == 1200) {\n                Thread.sleep(1000);\n            }\n            \n            if(i == 1200){\n                qu.startThenShutdown(index);                                \n                runNow.set(true);\n                qu.restart(index);\n                LOG.info(\"Setting up server: \" + index);\n            }\n        \n            if(i>=1000 &&  i%2== 0) {\n                zk3.create(\"/newbaz\", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, new AsyncCallback.StringCallback() {\n\n                    @Override\n                    public void processResult(int rc, String path, Object ctx, String name) {\n                        counter++;\n                        if (rc != 0) {\n                            errors++;\n                        }\n                        if(counter > 7300){\n                            sem.release();\n                        }\n                    }\n                }, null);\n            }\n            if(i == 1050 || i == 1100 || i == 1150) {\n                Thread.sleep(1000);\n            }\n        }\n\n        // Wait until all updates return\n        if(!sem.tryAcquire(ClientBase.CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)) {\n            LOG.warn(\"Did not aquire semaphore fast enough\");\n        }\n        mytestfooThread.join(ClientBase.CONNECTION_TIMEOUT);\n        if (mytestfooThread.isAlive()) {\n            LOG.error(\"mytestfooThread is still alive\");\n        }\n\n        Thread.sleep(1000);\n        // Verify that server is following and has the same epoch as the leader\n        \n        verifyState(qu, index, leader);\n        \n        zk1.close();\n        zk2.close();\n        zk3.close();\n        \n        qu.shutdownAll();\n    }\n\n    private static DisconnectableZooKeeper createClient(int port,\n            CountdownWatcher watcher)\n        throws IOException, TimeoutException, InterruptedException\n    {\n        DisconnectableZooKeeper zk = new DisconnectableZooKeeper(\n                \"127.0.0.1:\" + port, ClientBase.CONNECTION_TIMEOUT, watcher);\n\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        return zk;\n    }\n\n    private static TestableZooKeeper createTestableClient(String hp)\n        throws IOException, TimeoutException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createTestableClient(watcher, hp);\n    }\n\n    private static TestableZooKeeper createTestableClient(\n            CountdownWatcher watcher, String hp)\n            throws IOException, TimeoutException, InterruptedException\n        {\n            TestableZooKeeper zk = new TestableZooKeeper(\n                    hp, ClientBase.CONNECTION_TIMEOUT, watcher);\n\n            watcher.waitForConnected(CONNECTION_TIMEOUT);\n            return zk;\n        }\n\n    private void verifyState(QuorumUtil qu, int index, Leader leader) {\n        assertTrue(\"Not following\", qu.getPeer(index).peer.follower != null);\n        long epochF = (qu.getPeer(index).peer.getActiveServer().getZxid() >> 32L);\n        long epochL = (leader.getEpoch() >> 32L);\n        assertTrue(\"Zxid: \" + qu.getPeer(index).peer.getActiveServer().getZKDatabase().getDataTreeLastProcessedZxid() + \n                \"Current epoch: \" + epochF, epochF == epochL);\n        int leaderIndex = (index == 1) ? 2 : 1;    \n        Collection<Long> sessionsRestarted = qu.getPeer(index).peer.getActiveServer().getZKDatabase().getSessions();\n        Collection<Long> sessionsNotRestarted = qu.getPeer(leaderIndex).peer.getActiveServer().getZKDatabase().getSessions();\n        \n        for(Long l : sessionsRestarted) {\n            assertTrue(\"Should have same set of sessions in both servers, did not expect: \" + l, sessionsNotRestarted.contains(l));        \n        }      \n        assertEquals(\"Should have same number of sessions\", sessionsNotRestarted.size(), sessionsRestarted.size());\n        ZKDatabase restarted = qu.getPeer(index).peer.getActiveServer().getZKDatabase();\n        ZKDatabase clean =  qu.getPeer(3).peer.getActiveServer().getZKDatabase();\n        ZKDatabase lead = qu.getPeer(leaderIndex).peer.getActiveServer().getZKDatabase();\n        for(Long l : sessionsRestarted) {\n            assertTrue(\"Should have same set of sessions in both servers, did not expect: \" + l, sessionsNotRestarted.contains(l));\n            HashSet ephemerals = restarted.getEphemerals(l);\n            HashSet cleanEphemerals = clean.getEphemerals(l);\n            for(Object o : cleanEphemerals) {\n                if(!ephemerals.contains(o)) {\n                    LOG.info(\"Restarted follower doesn't contain ephemeral \" + o);\n                }\n            }\n            HashSet leadEphemerals = lead.getEphemerals(l);\n            for(Object o : leadEphemerals) {\n                if(!cleanEphemerals.contains(o)) {\n                    LOG.info(\"Follower doesn't contain ephemeral from leader \" + o);\n                }\n            }\n            assertEquals(\"Should have same number of ephemerals in both followers\", ephemerals.size(), cleanEphemerals.size());            \n            assertEquals(\"Leader should equal follower\", lead.getEphemerals(l).size(), cleanEphemerals.size());\n        }\n    }      \n\n    /**\n     * Verify that the server is sending the proper zxid. See ZOOKEEPER-1412.\n     */\n    @Test\n    public void testFollowerSendsLastZxid() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        int index = 1;\n        while(qu.getPeer(index).peer.follower == null) {\n            index++;\n        }\n        LOG.info(\"Connecting to follower:\" + index);\n\n        TestableZooKeeper zk =\n                createTestableClient(\"localhost:\" + qu.getPeer(index).peer.getClientPort());\n\n        assertEquals(0L, zk.testableLastZxid());\n        zk.exists(\"/\", false);\n        long lzxid = zk.testableLastZxid();\n        assertTrue(\"lzxid:\" + lzxid + \" > 0\", lzxid > 0);\n        zk.close();\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        LinkedBlockingQueue<WatchedEvent> events =\n            new LinkedBlockingQueue<WatchedEvent>();\n\n        public void process(WatchedEvent event) {\n            super.process(event);\n            if (event.getType() != Event.EventType.None) {\n                try {\n                    events.put(event);\n                } catch (InterruptedException e) {\n                    LOG.warn(\"ignoring interrupt during event.put\");\n                }\n            }\n        }\n    }\n\n    /**\n     * Verify that the server is sending the proper zxid, and as a result\n     * the watch doesn't fire. See ZOOKEEPER-1412.\n     */\n    @Test\n    public void testFollowerWatcherResync() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        int index = 1;\n        while(qu.getPeer(index).peer.follower == null) {\n            index++;\n        }\n        LOG.info(\"Connecting to follower:\" + index);\n\n        TestableZooKeeper zk1 = createTestableClient(\n                \"localhost:\" + qu.getPeer(index).peer.getClientPort());\n        zk1.create(\"/foo\", \"foo\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n\n        MyWatcher watcher = new MyWatcher();\n        TestableZooKeeper zk2 = createTestableClient(watcher,\n                \"localhost:\" + qu.getPeer(index).peer.getClientPort());\n\n        zk2.exists(\"/foo\", true);\n\n        watcher.reset();\n        zk2.testableConnloss();\n        if (!watcher.clientConnected.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS))\n        {\n            fail(\"Unable to connect to server\");\n        }\n        assertArrayEquals(\"foo\".getBytes(), zk2.getData(\"/foo\", false, null));\n\n        assertNull(watcher.events.poll(5, TimeUnit.SECONDS));\n\n        zk1.close();\n        zk2.close();\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FollowerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.OpResult;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.server.quorum.LearnerHandler;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FollowerTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(FollowerTest.class);\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    volatile int counter = 0;\n    volatile int errors = 0;\n\n    /** \n     * See ZOOKEEPER-790 for details \n     * */\n    @Test\n    public void testFollowersStartAfterLeader() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        CountdownWatcher watcher = new CountdownWatcher();\n        qu.startQuorum();\n        \n        int index = 1;\n        while(qu.getPeer(index).peer.leader == null) {\n            index++;\n        }\n        \n        ZooKeeper zk = new ZooKeeper(\n                \"127.0.0.1:\" + qu.getPeer((index == 1)?2:1).peer.getClientPort(),\n                ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        \n        // break the quorum\n        qu.shutdown(index);\n\n        // Wait until we disconnect to proceed\n        watcher.waitForDisconnected(CONNECTION_TIMEOUT);\n        \n        // try to reestablish the quorum\n        qu.start(index);\n\n        try{\n            watcher.waitForConnected(30000);      \n        } catch(TimeoutException e) {\n            Assert.fail(\"client could not connect to reestablished quorum: giving up after 30+ seconds.\");\n        }\n\n        zk.close();\n\n        qu.tearDown();\n    }\n\n    // skip superhammer and clientcleanup as they are too expensive for quorum\n    \n    /**\n     * Tests if a multiop submitted to a non-leader propagates to the leader properly\n     * (see ZOOKEEPER-1124).\n     * \n     * The test works as follows. It has a client connect to a follower and submit a multiop\n     * to the follower. It then verifies that the multiop successfully gets committed by the leader.\n     *\n     * Without the fix in ZOOKEEPER-1124, this fails with a ConnectionLoss KeeperException.\n     */\n    @Test\n    public void testMultiToFollower() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        CountdownWatcher watcher = new CountdownWatcher();\n        qu.startQuorum();\n        \n        int index = 1;\n        while(qu.getPeer(index).peer.leader == null) {\n            index++;\n        }\n        \n        ZooKeeper zk = new ZooKeeper(\n                \"127.0.0.1:\" + qu.getPeer((index == 1)?2:1).peer.getClientPort(),\n                ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        \n        List<OpResult> results = new ArrayList<OpResult>();\n\n        results = zk.multi(Arrays.asList(\n                Op.create(\"/multi0\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi1\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi2\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                ));\n        zk.getData(\"/multi0\", false, null);\n        zk.getData(\"/multi1\", false, null);\n        zk.getData(\"/multi2\", false, null);\n\n        zk.close();\n\n        qu.tearDown();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FourLetterWordsQuorumTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class FourLetterWordsQuorumTest extends QuorumBase {\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(FourLetterWordsQuorumTest.class);\n\n    /** Test the various four letter words */\n    @Test\n    public void testFourLetterWords() throws Exception {\n        String servers[] = hostPort.split(\",\");\n        for (String hp : servers) {\n            verify(hp, \"ruok\", \"imok\");\n            verify(hp, \"envi\", \"java.version\");\n            verify(hp, \"conf\", \"clientPort\");\n            verify(hp, \"stat\", \"Outstanding\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", \"queued\");\n            verify(hp, \"dump\", \"Session\");\n            verify(hp, \"wchs\", \"watches\");\n            verify(hp, \"wchp\", \"\");\n            verify(hp, \"wchc\", \"\");\n\n            verify(hp, \"srst\", \"reset\");\n            verify(hp, \"crst\", \"reset\");\n\n            verify(hp, \"stat\", \"Outstanding\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", \"queued\");\n\n            TestableZooKeeper zk = createClient(hp);\n            String sid = getHexSessionId(zk.getSessionId());\n\n            verify(hp, \"stat\", \"queued\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", sid);\n            verify(hp, \"dump\", sid);\n\n            zk.getData(\"/\", true, null);\n\n            verify(hp, \"stat\", \"queued\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", sid);\n            verify(hp, \"dump\", sid);\n            verify(hp, \"wchs\", \"watching 1\");\n            verify(hp, \"wchp\", sid);\n            verify(hp, \"wchc\", sid);\n\n            zk.close();\n\n            verify(hp, \"ruok\", \"imok\");\n            verify(hp, \"envi\", \"java.version\");\n            verify(hp, \"conf\", \"clientPort\");\n            verify(hp, \"stat\", \"Outstanding\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", \"queued\");\n            verify(hp, \"dump\", \"Session\");\n            verify(hp, \"wchs\", \"watch\");\n            verify(hp, \"wchp\", \"\");\n            verify(hp, \"wchc\", \"\");\n\n            verify(hp, \"srst\", \"reset\");\n            verify(hp, \"crst\", \"reset\");\n\n            verify(hp, \"stat\", \"Outstanding\");\n            verify(hp, \"srvr\", \"Outstanding\");\n            verify(hp, \"cons\", \"queued\");\n\n            verify(hp, \"mntr\", \"zk_version\\t\");\n        }\n    }\n\n    private void verify(String hp, String cmd, String expected)\n        throws IOException\n    {\n        for(HostPort hpobj: parseHostPortList(hp)) {\n            String resp = send4LetterWord(hpobj.host, hpobj.port, cmd);\n            LOG.info(\"cmd \" + cmd + \" expected \" + expected + \" got \" + resp);\n            if (cmd.equals(\"dump\")) {\n                Assert.assertTrue(resp.contains(expected)\n                        || resp.contains(\"Sessions with Ephemerals\"));\n            } else {\n                Assert.assertTrue(resp.contains(expected));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FourLetterWordsTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.regex.Pattern;\n\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.common.IOUtils;\nimport static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.Timeout;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FourLetterWordsTest extends ClientBase {\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(FourLetterWordsTest.class);\n\n    @Rule\n    public Timeout timeout = new Timeout(30000);\n\n    /** Test the various four letter words */\n    @Test\n    public void testFourLetterWords() throws Exception {\n        verify(\"ruok\", \"imok\");\n        verify(\"envi\", \"java.version\");\n        verify(\"conf\", \"clientPort\");\n        verify(\"stat\", \"Outstanding\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", \"queued\");\n        verify(\"dump\", \"Session\");\n        verify(\"wchs\", \"watches\");\n        verify(\"wchp\", \"\");\n        verify(\"wchc\", \"\");\n\n        verify(\"srst\", \"reset\");\n        verify(\"crst\", \"reset\");\n\n        verify(\"stat\", \"Outstanding\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", \"queued\");\n\n        TestableZooKeeper zk = createClient();\n        String sid = getHexSessionId(zk.getSessionId());\n\n        verify(\"stat\", \"queued\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", sid);\n        verify(\"dump\", sid);\n\n        zk.getData(\"/\", true, null);\n\n        verify(\"stat\", \"queued\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", sid);\n        verify(\"dump\", sid);\n\n        verify(\"wchs\", \"watching 1\");\n        verify(\"wchp\", sid);\n        verify(\"wchc\", sid);\n        zk.close();\n\n        verify(\"ruok\", \"imok\");\n        verify(\"envi\", \"java.version\");\n        verify(\"conf\", \"clientPort\");\n        verify(\"stat\", \"Outstanding\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", \"queued\");\n        verify(\"dump\", \"Session\");\n        verify(\"wchs\", \"watch\");\n        verify(\"wchp\", \"\");\n        verify(\"wchc\", \"\");\n\n        verify(\"srst\", \"reset\");\n        verify(\"crst\", \"reset\");\n\n        verify(\"stat\", \"Outstanding\");\n        verify(\"srvr\", \"Outstanding\");\n        verify(\"cons\", \"queued\");\n        verify(\"mntr\", \"zk_server_state\\tstandalone\");\n        verify(\"mntr\", \"num_alive_connections\");\n        verify(\"stat\", \"Connections\");\n        verify(\"srvr\", \"Connections\");\n    }\n\n    private String sendRequest(String cmd) throws IOException {\n      HostPort hpobj = ClientBase.parseHostPortList(hostPort).get(0);\n      return send4LetterWord(hpobj.host, hpobj.port, cmd);\n    }\n    private String sendRequest(String cmd, int timeout) throws IOException {\n        HostPort hpobj = ClientBase.parseHostPortList(hostPort).get(0);\n        return send4LetterWord(hpobj.host, hpobj.port, cmd, timeout);\n      }\n\n    private void verify(String cmd, String expected) throws IOException {\n        String resp = sendRequest(cmd);\n        LOG.info(\"cmd \" + cmd + \" expected \" + expected + \" got \" + resp);\n        Assert.assertTrue(resp.contains(expected));\n    }\n    \n    @Test\n    public void testValidateStatOutput() throws Exception {\n        ZooKeeper zk1 = createClient();\n        ZooKeeper zk2 = createClient();\n        \n        String resp = sendRequest(\"stat\");\n        BufferedReader in = new BufferedReader(new StringReader(resp));\n\n        String line;\n        // first line should be version info\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^.*\\\\s\\\\d+\\\\.\\\\d+\\\\.\\\\d+-.*$\", line));\n        Assert.assertTrue(Pattern.matches(\"^Clients:$\", in.readLine()));\n\n        int count = 0;\n        while ((line = in.readLine()).length() > 0) {\n            count++;\n            Assert.assertTrue(Pattern.matches(\"^ /.*:\\\\d+\\\\[\\\\d+\\\\]\\\\(queued=\\\\d+,recved=\\\\d+,sent=\\\\d+\\\\)$\", line));\n        }\n        // ensure at least the two clients we created are accounted for\n        Assert.assertTrue(count >= 2);\n\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Latency min/avg/max: \\\\d+/\\\\d+/\\\\d+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Received: \\\\d+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Sent: \\\\d+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Connections: \\\\d+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Outstanding: \\\\d+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Zxid: 0x[\\\\da-fA-F]+$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Mode: .*$\", line));\n        line = in.readLine();\n        Assert.assertTrue(Pattern.matches(\"^Node count: \\\\d+$\", line));\n\n        zk1.close();\n        zk2.close();\n    }\n\n    @Test\n    public void testValidateConsOutput() throws Exception {\n        ZooKeeper zk1 = createClient();\n        ZooKeeper zk2 = createClient();\n        \n        String resp = sendRequest(\"cons\");\n        BufferedReader in = new BufferedReader(new StringReader(resp));\n\n        String line;\n        int count = 0;\n        while ((line = in.readLine()) != null && line.length() > 0) {\n            count++;\n            Assert.assertTrue(line, Pattern.matches(\"^ /.*:\\\\d+\\\\[\\\\d+\\\\]\\\\(queued=\\\\d+,recved=\\\\d+,sent=\\\\d+.*\\\\)$\", line));\n        }\n        // ensure at least the two clients we created are accounted for\n        Assert.assertTrue(count >= 2);\n\n        zk1.close();\n        zk2.close();\n    }\n\n    @Test(timeout=60000)\n    public void testValidateSocketTimeout() throws Exception {\n        /**\n         * testing positive scenario that even with timeout parameter the\n         * functionality works fine\n         */\n        String resp = sendRequest(\"isro\", 2000);\n        Assert.assertTrue(resp.contains(\"rw\"));\n    }\n\n    @Test\n    public void testSetTraceMask() throws Exception {\n        String gtmkResp = sendRequest(\"gtmk\");\n        Assert.assertNotNull(gtmkResp);\n        gtmkResp = gtmkResp.trim();\n        Assert.assertFalse(gtmkResp.isEmpty());\n        long formerMask = Long.valueOf(gtmkResp);\n        try {\n            verify(buildSetTraceMaskRequest(0), \"0\");\n            verify(\"gtmk\", \"0\");\n        } finally {\n            // Restore former value.\n            sendRequest(buildSetTraceMaskRequest(formerMask));\n        }\n    }\n\n    /**\n     * Builds a SetTraceMask request to be sent to the server, consisting of\n     * \"stmk\" followed by the 8-byte long representation of the trace mask.\n     *\n     * @param mask trace mask to set\n     * @return built request\n     * @throws IOException if there is an I/O error\n     */\n    private String buildSetTraceMaskRequest(long mask) throws IOException {\n        ByteArrayOutputStream baos = null;\n        DataOutputStream dos = null;\n        try {\n            baos = new ByteArrayOutputStream();\n            dos = new DataOutputStream(baos);\n            dos.writeBytes(\"stmk\");\n            dos.writeLong(mask);\n        } finally {\n            IOUtils.closeStream(dos);\n            IOUtils.closeStream(baos);\n        }\n        return new String(baos.toByteArray());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/FourLetterWordsWhiteListTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.server.ServerCnxn;\nimport static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.Timeout;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FourLetterWordsWhiteListTest extends ClientBase {\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(FourLetterWordsTest.class);\n\n    @Rule\n    public Timeout timeout = new Timeout(30000);\n\n    /*\n     * ZOOKEEPER-2693: test white list of four letter words.\n     * For 3.5.x default white list is empty. Verify that is\n     * the case (except 'stat' command which is enabled in ClientBase\n     * which other tests depend on.).\n     */\n    @Test(timeout=30000)\n    public void testFourLetterWordsAllDisabledByDefault() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"stat\");\n        startServer();\n\n        // Default white list for 3.5.x is empty, so all command should fail.\n        verifyAllCommandsFail();\n\n        TestableZooKeeper zk = createClient();\n\n        verifyAllCommandsFail();\n\n        zk.getData(\"/\", true, null);\n\n        verifyAllCommandsFail();\n\n        zk.close();\n\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyAllCommandsFail();\n    }\n\n    @Test(timeout=30000)\n    public void testFourLetterWordsEnableSomeCommands() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"stat, ruok, isro\");\n        startServer();\n        // stat, ruok and isro are white listed.\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyExactMatch(\"ruok\", \"imok\");\n        verifyExactMatch(\"isro\", \"rw\");\n\n        // Rest of commands fail.\n        verifyExactMatch(\"conf\", generateExpectedMessage(\"conf\"));\n        verifyExactMatch(\"cons\", generateExpectedMessage(\"cons\"));\n        verifyExactMatch(\"crst\", generateExpectedMessage(\"crst\"));\n        verifyExactMatch(\"dump\", generateExpectedMessage(\"dump\"));\n        verifyExactMatch(\"envi\", generateExpectedMessage(\"envi\"));\n        verifyExactMatch(\"gtmk\", generateExpectedMessage(\"gtmk\"));\n        verifyExactMatch(\"stmk\", generateExpectedMessage(\"stmk\"));\n        verifyExactMatch(\"srst\", generateExpectedMessage(\"srst\"));\n        verifyExactMatch(\"wchc\", generateExpectedMessage(\"wchc\"));\n        verifyExactMatch(\"wchp\", generateExpectedMessage(\"wchp\"));\n        verifyExactMatch(\"wchs\", generateExpectedMessage(\"wchs\"));\n        verifyExactMatch(\"mntr\", generateExpectedMessage(\"mntr\"));\n    }\n\n    @Test(timeout=30000)\n    public void testISROEnabledWhenReadOnlyModeEnabled() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"stat\");\n        System.setProperty(\"readonlymode.enabled\", \"true\");\n        startServer();\n        verifyExactMatch(\"isro\", \"rw\");\n        System.clearProperty(\"readonlymode.enabled\");\n    }\n\n    @Test(timeout=30000)\n    public void testFourLetterWordsInvalidConfiguration() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"foo bar\" +\n                \" foo,,, \" +\n                \"bar :.,@#$%^&*() , , , , bar, bar, stat,        \");\n        startServer();\n\n        // Just make sure we are good when admin made some mistakes in config file.\n        verifyAllCommandsFail();\n        // But still, what's valid in white list will get through.\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n    }\n\n    @Test(timeout=30000)\n    public void testFourLetterWordsEnableAllCommandsThroughAsterisk() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\", \"*\");\n        startServer();\n        verifyAllCommandsSuccess();\n    }\n\n    @Test(timeout=30000)\n    public void testFourLetterWordsEnableAllCommandsThroughExplicitList() throws Exception {\n        stopServer();\n        ServerCnxn.resetWhiteList();\n        System.setProperty(\"zookeeper.4lw.commands.whitelist\",\n                \"ruok, envi, conf, stat, srvr, cons, dump,\" +\n                        \"wchs, wchp, wchc, srst, crst, \" +\n                        \"mntr, gtmk, isro, stmk\");\n        startServer();\n        verifyAllCommandsSuccess();\n    }\n\n    private void verifyAllCommandsSuccess() throws Exception {\n        verifyExactMatch(\"ruok\", \"imok\");\n        verifyFuzzyMatch(\"envi\", \"java.version\");\n        verifyFuzzyMatch(\"conf\", \"clientPort\");\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", \"queued\");\n        verifyFuzzyMatch(\"dump\", \"Session\");\n        verifyFuzzyMatch(\"wchs\", \"watches\");\n        verifyFuzzyMatch(\"wchp\", \"\");\n        verifyFuzzyMatch(\"wchc\", \"\");\n\n        verifyFuzzyMatch(\"srst\", \"reset\");\n        verifyFuzzyMatch(\"crst\", \"reset\");\n\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", \"queued\");\n        verifyFuzzyMatch(\"gtmk\", \"306\");\n        verifyFuzzyMatch(\"isro\", \"rw\");\n\n        TestableZooKeeper zk = createClient();\n        String sid = getHexSessionId(zk.getSessionId());\n\n        verifyFuzzyMatch(\"stat\", \"queued\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", sid);\n        verifyFuzzyMatch(\"dump\", sid);\n\n        zk.getData(\"/\", true, null);\n\n        verifyFuzzyMatch(\"stat\", \"queued\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", sid);\n        verifyFuzzyMatch(\"dump\", sid);\n\n        verifyFuzzyMatch(\"wchs\", \"watching 1\");\n        verifyFuzzyMatch(\"wchp\", sid);\n        verifyFuzzyMatch(\"wchc\", sid);\n        zk.close();\n\n        verifyExactMatch(\"ruok\", \"imok\");\n        verifyFuzzyMatch(\"envi\", \"java.version\");\n        verifyFuzzyMatch(\"conf\", \"clientPort\");\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", \"queued\");\n        verifyFuzzyMatch(\"dump\", \"Session\");\n        verifyFuzzyMatch(\"wchs\", \"watch\");\n        verifyFuzzyMatch(\"wchp\", \"\");\n        verifyFuzzyMatch(\"wchc\", \"\");\n\n        verifyFuzzyMatch(\"srst\", \"reset\");\n        verifyFuzzyMatch(\"crst\", \"reset\");\n\n        verifyFuzzyMatch(\"stat\", \"Outstanding\");\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n        verifyFuzzyMatch(\"cons\", \"queued\");\n        verifyFuzzyMatch(\"mntr\", \"zk_server_state\\tstandalone\");\n        verifyFuzzyMatch(\"mntr\", \"num_alive_connections\");\n        verifyFuzzyMatch(\"stat\", \"Connections\");\n        verifyFuzzyMatch(\"srvr\", \"Connections\");\n    }\n\n    private void verifyAllCommandsFail() throws Exception {\n        verifyExactMatch(\"ruok\", generateExpectedMessage(\"ruok\"));\n        verifyExactMatch(\"conf\", generateExpectedMessage(\"conf\"));\n        verifyExactMatch(\"cons\", generateExpectedMessage(\"cons\"));\n        verifyExactMatch(\"crst\", generateExpectedMessage(\"crst\"));\n        verifyExactMatch(\"dump\", generateExpectedMessage(\"dump\"));\n        verifyExactMatch(\"envi\", generateExpectedMessage(\"envi\"));\n        verifyExactMatch(\"gtmk\", generateExpectedMessage(\"gtmk\"));\n        verifyExactMatch(\"stmk\", generateExpectedMessage(\"stmk\"));\n        verifyExactMatch(\"srst\", generateExpectedMessage(\"srst\"));\n        verifyExactMatch(\"wchc\", generateExpectedMessage(\"wchc\"));\n        verifyExactMatch(\"wchp\", generateExpectedMessage(\"wchp\"));\n        verifyExactMatch(\"wchs\", generateExpectedMessage(\"wchs\"));\n        verifyExactMatch(\"mntr\", generateExpectedMessage(\"mntr\"));\n        verifyExactMatch(\"isro\", generateExpectedMessage(\"isro\"));\n\n        // srvr is enabled by default due to the sad fact zkServer.sh uses it.\n        verifyFuzzyMatch(\"srvr\", \"Outstanding\");\n    }\n\n    private void verifyFuzzyMatch(String cmd, String expected) throws IOException {\n        String resp = sendRequest(cmd);\n        LOG.info(\"cmd \" + cmd + \" expected \" + expected + \" got \" + resp);\n        Assert.assertTrue(resp.contains(expected));\n    }\n\n    private String generateExpectedMessage(String command) {\n        return command + \" is not executed because it is not in the whitelist.\";\n    }\n\n    private void verifyExactMatch(String cmd, String expected) throws IOException {\n        String resp = sendRequest(cmd);\n        LOG.info(\"cmd \" + cmd + \" expected an exact match of \" + expected + \"; got \" + resp);\n        Assert.assertTrue(resp.trim().equals(expected));\n    }\n\n    private String sendRequest(String cmd) throws IOException {\n      HostPort hpobj = ClientBase.parseHostPortList(hostPort).get(0);\n      return send4LetterWord(hpobj.host, hpobj.port, cmd);\n    }\n\n    private String sendRequest(String cmd, int timeout) throws IOException {\n        HostPort hpobj = ClientBase.parseHostPortList(hostPort).get(0);\n        return send4LetterWord(hpobj.host, hpobj.port, cmd, timeout);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/GetChildren2Test.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class GetChildren2Test extends ClientBase {\n    private ZooKeeper zk;\n\n    @Override\n    public void setUp() throws Exception {\n        super.setUp();\n\n        zk = createClient();\n    }\n\n    @Override\n    public void tearDown() throws Exception {\n        super.tearDown();\n\n        zk.close();\n    }\n\n    @Test\n    public void testChild()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        String childname = name + \"/bar\";\n        zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n\n        Stat stat = new Stat();\n        List<String> s = zk.getChildren(name, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid() + 1, stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(1, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(0, stat.getEphemeralOwner());\n        Assert.assertEquals(name.length(), stat.getDataLength());\n        Assert.assertEquals(1, stat.getNumChildren());\n        Assert.assertEquals(s.size(), stat.getNumChildren());\n\n        s = zk.getChildren(childname, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid(), stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(0, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(zk.getSessionId(), stat.getEphemeralOwner());\n        Assert.assertEquals(childname.length(), stat.getDataLength());\n        Assert.assertEquals(0, stat.getNumChildren());\n        Assert.assertEquals(s.size(), stat.getNumChildren());\n    }\n\n    @Test\n    public void testChildren()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        List<String> children = new ArrayList<String>();\n        List<String> children_s = new ArrayList<String>();\n\n        for (int i = 0; i < 10; i++) {\n            String childname = name + \"/bar\" + i;\n            String childname_s = \"bar\" + i;\n            children.add(childname);\n            children_s.add(childname_s);\n        }\n\n        for(int i = 0; i < children.size(); i++) {\n            String childname = children.get(i);\n            zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL);\n\n            Stat stat = new Stat();\n            List<String> s = zk.getChildren(name, false, stat);\n\n            Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n            Assert.assertEquals(stat.getCzxid() + i + 1, stat.getPzxid());\n            Assert.assertEquals(stat.getCtime(), stat.getMtime());\n            Assert.assertEquals(i + 1, stat.getCversion());\n            Assert.assertEquals(0, stat.getVersion());\n            Assert.assertEquals(0, stat.getAversion());\n            Assert.assertEquals(0, stat.getEphemeralOwner());\n            Assert.assertEquals(name.length(), stat.getDataLength());\n            Assert.assertEquals(i + 1, stat.getNumChildren());\n            Assert.assertEquals(s.size(), stat.getNumChildren());\n        }\n        List<String> p = zk.getChildren(name, false, null);\n        List<String> c_a = children_s;\n        List<String> c_b = p;\n        Collections.sort(c_a);\n        Collections.sort(c_b);\n        Assert.assertEquals(c_a.size(), 10);\n        Assert.assertEquals(c_a, c_b);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.jmx.CommonNames;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class HierarchicalQuorumTest extends ClientBase {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumBase.class);\n\n    File s1dir, s2dir, s3dir, s4dir, s5dir;\n    QuorumPeer s1, s2, s3, s4, s5;\n    protected int port1;\n    protected int port2;\n    protected int port3;\n    protected int port4;\n    protected int port5;\n\n    protected int leport1;\n    protected int leport2;\n    protected int leport3;\n    protected int leport4;\n    protected int leport5;\n\n    Properties qp;\n    protected final ClientHammerTest cht = new ClientHammerTest();\n    \n    @Override\n    public void setUp() throws Exception {\n        setupTestEnv();\n\n        JMXEnv.setUp();\n\n        setUpAll();\n\n        port1 = PortAssignment.unique();\n        port2 = PortAssignment.unique();\n        port3 = PortAssignment.unique();\n        port4 = PortAssignment.unique();\n        port5 = PortAssignment.unique();\n        leport1 = PortAssignment.unique();\n        leport2 = PortAssignment.unique();\n        leport3 = PortAssignment.unique();\n        leport4 = PortAssignment.unique();\n        leport5 = PortAssignment.unique();\n\n        hostPort = \"127.0.0.1:\" + port1 \n            + \",127.0.0.1:\" + port2 \n            + \",127.0.0.1:\" + port3 \n            + \",127.0.0.1:\" + port4 \n            + \",127.0.0.1:\" + port5;\n        LOG.info(\"Ports are: \" + hostPort);\n\n        s1dir = ClientBase.createTmpDir();\n        s2dir = ClientBase.createTmpDir();\n        s3dir = ClientBase.createTmpDir();\n        s4dir = ClientBase.createTmpDir();\n        s5dir = ClientBase.createTmpDir();\n\n        String config = \"group.1=1:2:3\\n\" +\n        \"group.2=4:5\\n\" +\n        \"weight.1=1\\n\" +\n        \"weight.2=1\\n\" +\n        \"weight.3=1\\n\" +\n        \"weight.4=0\\n\" +\n        \"weight.5=0\\n\";\n\n        ByteArrayInputStream is = new ByteArrayInputStream(config.getBytes());\n        this.qp = new Properties();\n        \n        qp.load(is);\n        startServers();\n\n        cht.hostPort = hostPort;\n        cht.setUpAll();\n        \n        LOG.info(\"Setup finished\");\n    }\n    \n    /**\n     * This method is here to keep backwards compatibility with the test code \n     * written before observers. \n     * @throws Exception\n     */\n    void startServers() throws Exception {\n        startServers(false);\n    }\n    \n    /**\n     * Starts 5 Learners. When withObservers == false, all 5 are Followers.\n     * When withObservers == true, 3 are Followers and 2 Observers.\n     * @param withObservers\n     * @throws Exception\n     */\n    void startServers(boolean withObservers) throws Exception {\n        int tickTime = 2000;\n        int initLimit = 3;\n        int syncLimit = 3;\n        HashMap<Long,QuorumServer> peers = new HashMap<Long,QuorumServer>();\n        peers.put(Long.valueOf(1), new QuorumServer(1, \"127.0.0.1\", port1 + 1000, leport1 + 1000, null));\n        peers.put(Long.valueOf(2), new QuorumServer(2, \"127.0.0.1\", port2 + 1000, leport2 + 1000, null));\n        peers.put(Long.valueOf(3), new QuorumServer(3, \"127.0.0.1\", port3 + 1000, leport3 + 1000, null));\n        peers.put(Long.valueOf(4), new QuorumServer(4, \"127.0.0.1\", port4 + 1000, leport4 + 1000,\n                withObservers ? QuorumPeer.LearnerType.OBSERVER\n                        : QuorumPeer.LearnerType.PARTICIPANT));\n        peers.put(Long.valueOf(5), new QuorumServer(5, \"127.0.0.1\", port5 + 1000, leport5 + 1000,\n                withObservers ? QuorumPeer.LearnerType.OBSERVER\n                        : QuorumPeer.LearnerType.PARTICIPANT));\n\n        LOG.info(\"creating QuorumPeer 1 port \" + port1);\n        List <QuorumPeer> qps = new ArrayList<QuorumPeer>();\n        QuorumHierarchical hq1 = new QuorumHierarchical(qp); \n        s1 = new QuorumPeer(peers, s1dir, s1dir, port1, 3, 1, tickTime, initLimit, syncLimit, hq1);\n        qps.add(s1);\n        Assert.assertEquals(port1, s1.getClientPort());\n        \n        LOG.info(\"creating QuorumPeer 2 port \" + port2);\n        QuorumHierarchical hq2 = new QuorumHierarchical(qp); \n        s2 = new QuorumPeer(peers, s2dir, s2dir, port2, 3, 2, tickTime, initLimit, syncLimit, hq2);\n        qps.add(s2);\n        Assert.assertEquals(port2, s2.getClientPort());\n        \n        LOG.info(\"creating QuorumPeer 3 port \" + port3);\n        QuorumHierarchical hq3 = new QuorumHierarchical(qp); \n        s3 = new QuorumPeer(peers, s3dir, s3dir, port3, 3, 3, tickTime, initLimit, syncLimit, hq3);\n        qps.add(s3);\n        Assert.assertEquals(port3, s3.getClientPort());\n        \n        LOG.info(\"creating QuorumPeer 4 port \" + port4);\n        QuorumHierarchical hq4 = new QuorumHierarchical(qp); \n        s4 = new QuorumPeer(peers, s4dir, s4dir, port4, 3, 4, tickTime, initLimit, syncLimit, hq4);\n        qps.add(s4);\n        if (withObservers) {\n            s4.setLearnerType(QuorumPeer.LearnerType.OBSERVER);\n        }\n        Assert.assertEquals(port4, s4.getClientPort());\n                       \n        LOG.info(\"creating QuorumPeer 5 port \" + port5);\n        QuorumHierarchical hq5 = new QuorumHierarchical(qp); \n        s5 = new QuorumPeer(peers, s5dir, s5dir, port5, 3, 5, tickTime, initLimit, syncLimit, hq5);\n        qps.add(s5);\n        if (withObservers) {\n            s5.setLearnerType(QuorumPeer.LearnerType.OBSERVER);\n        }\n        Assert.assertEquals(port5, s5.getClientPort());\n        \n        // Observers are currently only compatible with LeaderElection\n        if (withObservers) {\n            s1.setElectionType(0);\n            s2.setElectionType(0);\n            s3.setElectionType(0);\n            s4.setElectionType(0);\n            s5.setElectionType(0);\n        }\n        \n        LOG.info(\"start QuorumPeer 1\");\n        s1.start();\n        LOG.info(\"start QuorumPeer 2\");\n        s2.start();\n        LOG.info(\"start QuorumPeer 3\");\n        s3.start();\n        LOG.info(\"start QuorumPeer 4\" + (withObservers ? \"(observer)\" : \"\"));\n        s4.start();\n        LOG.info(\"start QuorumPeer 5\" + (withObservers ? \"(observer)\" : \"\"));\n        s5.start();\n        LOG.info(\"started QuorumPeer 5\");\n\n        LOG.info (\"Closing ports \" + hostPort);\n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(hp,\n                                    CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is accepting client connections\");\n        }\n\n        // interesting to see what's there...\n        JMXEnv.dump();\n        // make sure we have these 5 servers listed\n        Set<String> ensureNames = new LinkedHashSet<String>();\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"InMemoryDataTree\");\n        }\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"name0=ReplicatedServer_id\" + i\n                 + \",name1=replica.\" + i + \",name2=\");\n        }\n        for (int i = 1; i <= 5; i++) {\n            for (int j = 1; j <= 5; j++) {\n                ensureNames.add(\"name0=ReplicatedServer_id\" + i\n                     + \",name1=replica.\" + j);\n            }\n        }\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"name0=ReplicatedServer_id\" + i);\n        }\n        JMXEnv.ensureAll(ensureNames.toArray(new String[ensureNames.size()]));\n        verifyElectionTimeTakenJMXAttribute(qps);\n    }\n\n    @Override\n    public void tearDown() throws Exception {\n        LOG.info(\"TearDown started\");\n        cht.tearDownAll();\n\n        LOG.info(\"Shutting down server 1\");\n        shutdown(s1);\n        LOG.info(\"Shutting down server 2\");\n        shutdown(s2);\n        LOG.info(\"Shutting down server 3\");\n        shutdown(s3);\n        LOG.info(\"Shutting down server 4\");\n        shutdown(s4);\n        LOG.info(\"Shutting down server 5\");\n        shutdown(s5);\n        \n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(hp,\n                                           ClientBase.CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is no longer accepting client connections\");\n        }\n\n        JMXEnv.tearDown();\n    }\n\n    protected void shutdown(QuorumPeer qp) {\n        QuorumBase.shutdown(qp);\n    }\n\n    protected TestableZooKeeper createClient()\n        throws IOException, InterruptedException\n    {\n        return createClient(hostPort);\n    }\n\n    protected TestableZooKeeper createClient(String hp)\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createClient(watcher, hp);\n    }\n\n    private void verifyElectionTimeTakenJMXAttribute(List<QuorumPeer> peers)\n            throws Exception {\n        LOG.info(\"Verify QuorumPeer#electionTimeTaken jmx bean attribute\");\n\n        for (int i = 1; i <= peers.size(); i++) {\n            QuorumPeer qp = peers.get(i - 1);\n            if (qp.getLearnerType() == LearnerType.OBSERVER) {\n                continue; // Observer don't have electionTimeTaken attribute.\n            }\n            Long electionTimeTaken = -1L;\n            String bean = \"\";\n            if (qp.getPeerState() == ServerState.FOLLOWING) {\n                bean = String.format(\n                        \"%s:name0=ReplicatedServer_id%d,name1=replica.%d,name2=Follower\",\n                        CommonNames.DOMAIN, i, i);\n            } else if (qp.getPeerState() == ServerState.LEADING) {\n                bean = String.format(\n                        \"%s:name0=ReplicatedServer_id%d,name1=replica.%d,name2=Leader\",\n                        CommonNames.DOMAIN, i, i);\n            }\n            electionTimeTaken = (Long) JMXEnv.ensureBeanAttribute(bean,\n                    \"ElectionTimeTaken\");\n            Assert.assertTrue(\"Wrong electionTimeTaken value!\",\n                    electionTimeTaken >= 0);\n        }\n    }\n\n    @Test\n    public void testHierarchicalQuorum() throws Throwable {\n        cht.runHammer(5, 10);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/IntegrityCheck.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\n/**\n * This is a simple test to check the integrity of ZooKeeper servers. The client\n * simply cycles through blasting changes to ZooKeeper and the checking what it\n * gets back.\n *\n * The check is very simple. The value of the last successful read or write is\n * stored in lastValue. When we issue a request, that value becomes a possible\n * value. The difficulty is that when a communication error happens, the client\n * doesn't know if the set actually went through. So, our invariant that we\n * check for is that we always read a value that is greater than or equal to\n * a value that we have previously read or set. (Each time we set a value, the\n * value will be one more than the previous set.)\n */\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.HashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.DataCallback;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.data.Stat;\n\npublic class IntegrityCheck implements Watcher, StatCallback, DataCallback {\n    private static final Logger LOG = LoggerFactory.getLogger(IntegrityCheck.class);\n\n    ZooKeeper zk;\n\n    HashMap<String, byte[]> lastValue = new HashMap<String, byte[]>();\n\n    int count;\n\n    String path;\n\n    int iteration;\n\n    int outstanding;\n\n    int errorCount;\n\n    synchronized void incOutstanding() {\n        outstanding++;\n    }\n\n    synchronized void decOutstanding() {\n        outstanding--;\n        notifyAll();\n    }\n\n    synchronized void waitOutstanding() throws InterruptedException {\n        while (outstanding > 0) {\n            wait();\n        }\n    }\n\n    IntegrityCheck(String hostPort, String path, int count) throws\n            IOException {\n        zk = new ZooKeeper(hostPort, 30000, this);\n        this.path = path;\n        this.count = count;\n    }\n\n    public void run() throws InterruptedException, KeeperException {\n        try{\n            LOG.warn(\"Creating znodes for \"+path);\n            doCreate();\n            LOG.warn(\"Staring the test loop for \"+path);\n            while (true) {\n                LOG.warn(\"Staring write cycle for \"+path);\n                doPopulate();\n                waitOutstanding();\n                LOG.warn(\"Staring read cycle for \"+path);\n                readAll();\n                waitOutstanding();\n            }\n        }finally{\n            LOG.warn(\"Test loop terminated for \"+path);\n        }\n    }\n\n    void readAll() {\n        for (int i = 0; i < count; i++) {\n            String cpath = path + \"/\" + i;\n            zk.getData(cpath, false, this, null);\n            incOutstanding();\n        }\n\n    }\n\n    void doCreate() throws InterruptedException, KeeperException {\n        // create top level znode\n        try{\n            zk.create(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }catch(KeeperException.NodeExistsException e){\n            // ignore duplicate create\n        }\n        iteration++;\n        byte v[] = (\"\" + iteration).getBytes();\n        // create child znodes\n        for (int i = 0; i < count; i++) {\n            String cpath = path + \"/\" + i;\n            try{\n                if(i%10==0)\n                    LOG.warn(\"Creating znode \"+cpath);\n                zk.create(cpath, v, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }catch(KeeperException.NodeExistsException e){\n                // ignore duplicate create\n            }\n            lastValue.put(cpath, v);\n        }\n    }\n\n    void doPopulate() {\n        iteration++;\n        byte v[] = (\"\" + iteration).getBytes();\n        for (int i = 0; i < count; i++) {\n            String cpath = path + \"/\" + i;\n            zk.setData(cpath, v, -1, this, v);\n            incOutstanding();\n        }\n    }\n\n    // watcher callback\n    public void process(WatchedEvent event) {\n        if(event.getState()==KeeperState.SyncConnected){\n            synchronized(this){\n                notifyAll();\n            }\n        }\n    }\n\n    synchronized void ensureConnected(){\n        while(zk.getState()!=ZooKeeper.States.CONNECTED){\n            try {\n                wait();\n            } catch (InterruptedException e) {\n                return;\n            }\n        }\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        if (args.length < 3) {\n            System.err.println(\"USAGE: IntegrityCheck zookeeperHostPort znode #children\");\n            return;\n        }\n        int childrenCount=0;\n        try {\n            childrenCount=Integer.parseInt(args[2]);\n        } catch (NumberFormatException e) {\n            e.printStackTrace();\n            System.exit(1);\n        }\n\n        try{\n            final IntegrityCheck ctest = new IntegrityCheck(args[0], args[1],childrenCount);\n            Runtime.getRuntime().addShutdownHook(new Thread() {\n                public void run() {\n                    System.out.println(new Date().toString()+\": Error count = \" + ctest.errorCount);\n                }\n            });\n            while(true){\n                try{\n                    ctest.ensureConnected();\n                    ctest.run();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.exit(2);\n        }\n    }\n\n    public void processResult(int rc, String path, Object ctx, Stat stat) {\n        if (rc == 0) {\n            lastValue.put(path, (byte[]) ctx);\n        }\n        decOutstanding();\n    }\n\n    public void processResult(int rc, String path, Object ctx, byte[] data,\n            Stat stat) {\n        if (rc == 0) {\n            String string = new String(data);\n            String lastString = null;\n            byte[] v = lastValue.get(path);\n            if (v != null) {\n                lastString = new String(v);\n            }\n            if (lastString != null\n                    && Integer.parseInt(string) < Integer.parseInt(lastString)) {\n                LOG.error(\"ERROR: Got \" + string + \" expected >= \"\n                        + lastString);\n                errorCount++;\n            }\n            lastValue.put(path, (byte[]) ctx);\n        }\n        decOutstanding();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/InvalidSnapshotTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.server.LogFormatter;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SnapshotFormatter;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class InvalidSnapshotTest extends ZKTestCase implements Watcher {\n    private final static Logger LOG = LoggerFactory.getLogger(UpgradeTest.class);\n    private static final String HOSTPORT =\n            \"127.0.0.1:\" + PortAssignment.unique();\n\n    private static final File testData = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"));\n    private CountDownLatch startSignal;\n\n    /**\n     * Verify the LogFormatter by running it on a known file.\n     */\n    @Test\n    public void testLogFormatter() throws Exception {\n        File snapDir = new File(testData, \"invalidsnap\");\n        File logfile = new File(new File(snapDir, \"version-2\"), \"log.274\");\n        String[] args = {logfile.getCanonicalFile().toString()};\n        LogFormatter.main(args);\n    }\n    \n\n    /**\n     * Verify the SnapshotFormatter by running it on a known file.\n     */\n    @Test\n    public void testSnapshotFormatter() throws Exception {\n        File snapDir = new File(testData, \"invalidsnap\");\n        File snapfile = new File(new File(snapDir, \"version-2\"), \"snapshot.272\");\n        String[] args = {snapfile.getCanonicalFile().toString()};\n        SnapshotFormatter.main(args);\n    }\n    \n    /**\n     * Verify the SnapshotFormatter by running it on a known file with one null data.\n     */\n    @Test\n    public void testSnapshotFormatterWithNull() throws Exception {\n        File snapDir = new File(testData, \"invalidsnap\");\n        File snapfile = new File(new File(snapDir, \"version-2\"), \"snapshot.273\");\n        String[] args = {snapfile.getCanonicalFile().toString()};\n        SnapshotFormatter.main(args);\n    }\n    \n    /**\n     * test the snapshot\n     * @throws Exception an exception could be expected\n     */\n    @Test\n    public void testSnapshot() throws Exception {\n        File snapDir = new File(testData, \"invalidsnap\");\n        ZooKeeperServer zks = new ZooKeeperServer(snapDir, snapDir, 3000);\n        SyncRequestProcessor.setSnapCount(1000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        LOG.info(\"starting up the zookeeper server .. waiting\");\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, 20000, this);\n        try {\n            // we know this from the data files\n            // this node is the last node in the snapshot\n\n            Assert.assertTrue(zk.exists(\"/9/9/8\", false) != null);\n        } finally {\n            zk.close();\n        }\n        f.shutdown();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(HOSTPORT,\n                           ClientBase.CONNECTION_TIMEOUT));\n\n    }\n\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \" + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected\n                && startSignal != null && startSignal.getCount() > 0)\n        {\n            startSignal.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/JMXEnv.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport javax.management.MBeanServer;\nimport javax.management.MBeanServerConnection;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\nimport javax.management.remote.JMXConnector;\nimport javax.management.remote.JMXConnectorFactory;\nimport javax.management.remote.JMXConnectorServer;\nimport javax.management.remote.JMXConnectorServerFactory;\nimport javax.management.remote.JMXServiceURL;\n\nimport junit.framework.TestCase;\n\nimport org.apache.zookeeper.jmx.CommonNames;\nimport org.apache.zookeeper.jmx.MBeanRegistry;\nimport org.junit.Assert;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class JMXEnv {\n    protected static final Logger LOG = LoggerFactory.getLogger(JMXEnv.class);\n\n    private static JMXConnectorServer cs;\n    private static JMXConnector cc;\n\n    public static void setUp() throws IOException {\n        MBeanServer mbs = MBeanRegistry.getInstance().getPlatformMBeanServer();\n        \n        JMXServiceURL url = new JMXServiceURL(\"service:jmx:rmi://\");\n        cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);\n        cs.start();\n\n       JMXServiceURL addr = cs.getAddress();\n        \n       cc = JMXConnectorFactory.connect(addr);\n    }\n    \n    public static void tearDown() {\n        try {\n            if (cc != null) {\n                cc.close();\n            }\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected, ignoring\", e);\n            \n        }\n        cc = null;\n        try {\n            if (cs != null) {\n                cs.stop();\n            }\n        } catch (IOException e) {\n            LOG.warn(\"Unexpected, ignoring\", e);\n            \n        }\n        cs = null;\n    }\n    \n    public static MBeanServerConnection conn() throws IOException {\n        return cc.getMBeanServerConnection();\n    }\n\n    /**\n     * Ensure that all of the specified names are registered.\n     * Note that these are components of the name, and in particular\n     * order matters - you want the more specific name (leafs) specified\n     * before their parent(s) (since names are hierarchical)\n     * It waits in a loop up to 60 seconds before failing if there is a\n     * mismatch.\n     * @param expectedNames\n     * @return\n     * @throws IOException\n     * @throws MalformedObjectNameException\n     */\n    public static Set<ObjectName> ensureAll(String... expectedNames)\n        throws IOException, InterruptedException\n    {\n        Set<ObjectName> beans;\n        Set<ObjectName> found;\n        int nTry = 0;\n        do {\n            if (nTry++ > 0) {\n                Thread.sleep(100);\n            }\n            try {\n                beans = conn().queryNames(\n                        new ObjectName(CommonNames.DOMAIN + \":*\"), null);\n            } catch (MalformedObjectNameException e) {\n                throw new RuntimeException(e);\n            }\n        \n            found = new HashSet<ObjectName>();\n            for (String name : expectedNames) {\n                LOG.info(\"expect:\" + name);\n                for (ObjectName bean : beans) {\n                    if (bean.toString().contains(name)) {\n                        LOG.info(\"found:\" + name + \" \" + bean);\n                        found.add(bean);\n                        break;\n                    }\n                }\n                beans.removeAll(found);\n            }\n        } while ((expectedNames.length != found.size()) && (nTry < 600));\n        TestCase.assertEquals(\"expected \" + Arrays.toString(expectedNames),\n                expectedNames.length, found.size());\n        return beans;\n    }\n\n    /**\n     * Ensure that only the specified names are registered.\n     * Note that these are components of the name, and in particular\n     * order matters - you want the more specific name (leafs) specified\n     * before their parent(s) (since names are hierarchical)\n     * @param expectedNames\n     * @return\n     * @throws IOException\n     * @throws MalformedObjectNameException\n     */\n    public static Set<ObjectName> ensureOnly(String... expectedNames)\n        throws IOException, InterruptedException\n    {\n        LOG.info(\"ensureOnly:\" + Arrays.toString(expectedNames));\n        Set<ObjectName> beans = ensureAll(expectedNames);\n        for (ObjectName bean : beans) {\n            LOG.info(\"unexpected:\" + bean.toString());\n        }\n        TestCase.assertEquals(0, beans.size());\n        return beans;\n    }\n    \n    public static void ensureNone(String... expectedNames)\n        throws IOException, InterruptedException\n    {\n        Set<ObjectName> beans;\n        int nTry = 0;\n        boolean foundUnexpected = false;\n        String unexpectedName = \"\";\n        do {\n            if (nTry++ > 0) {\n                Thread.sleep(100);\n            }\n            try {\n                beans = conn().queryNames(\n                        new ObjectName(CommonNames.DOMAIN + \":*\"), null);\n            } catch (MalformedObjectNameException e) {\n                throw new RuntimeException(e);\n            }\n  \n            foundUnexpected = false; \n            for (String name : expectedNames) {\n                for (ObjectName bean : beans) {\n                    if (bean.toString().contains(name)) {\n                        LOG.info(\"didntexpect:\" + name);\n                        foundUnexpected = true;\n                        unexpectedName = name + \" \" + bean.toString();\n                        break;\n                    }\n                }\n                if (foundUnexpected) {\n                    break;\n                }\n            }\n        } while ((foundUnexpected) && (nTry < 600));\n        if (foundUnexpected) {\n            LOG.info(\"List of all beans follows:\");\n            for (ObjectName bean : beans) {\n                LOG.info(\"bean:\" + bean.toString());\n            }\n            TestCase.fail(unexpectedName);\n        }\n    }\n\n    public static void dump() throws IOException {\n        LOG.info(\"JMXEnv.dump() follows\");\n        Set<ObjectName> beans;\n        try {\n            beans = conn().queryNames(\n                    new ObjectName(CommonNames.DOMAIN + \":*\"), null);\n        } catch (MalformedObjectNameException e) {\n            throw new RuntimeException(e);\n        }\n        for (ObjectName bean : beans) {\n            LOG.info(\"bean:\" + bean.toString());\n        }\n    }\n\n    /**\n     * Ensure that the specified parent names are registered. Note that these\n     * are components of the name. It waits in a loop up to 60 seconds before\n     * failing if there is a mismatch. This will return the beans which are not\n     * matched.\n     * \n     * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1858}\n     * \n     * @param expectedNames\n     *            - expected beans\n     * @return the beans which are not matched with the given expected names\n     * \n     * @throws IOException\n     * @throws InterruptedException\n     * \n     */\n    public static Set<ObjectName> ensureParent(String... expectedNames)\n            throws IOException, InterruptedException {\n        LOG.info(\"ensureParent:\" + Arrays.toString(expectedNames));\n\n        Set<ObjectName> beans;\n        int nTry = 0;\n        Set<ObjectName> found = new HashSet<ObjectName>();\n        do {\n            if (nTry++ > 0) {\n                Thread.sleep(500);\n            }\n            try {\n                beans = conn().queryNames(\n                        new ObjectName(CommonNames.DOMAIN + \":*\"), null);\n            } catch (MalformedObjectNameException e) {\n                throw new RuntimeException(e);\n            }\n            found.clear();\n            for (String name : expectedNames) {\n                LOG.info(\"expect:\" + name);\n                for (ObjectName bean : beans) {\n                    // check the existence of name in bean\n                    if (compare(bean.toString(), name)) {\n                        LOG.info(\"found:\" + name + \" \" + bean);\n                        found.add(bean);\n                        break;\n                    }\n                }\n                beans.removeAll(found);\n            }\n        } while (expectedNames.length != found.size() && nTry < 120);\n        TestCase.assertEquals(\"expected \" + Arrays.toString(expectedNames),\n                expectedNames.length, found.size());\n        return beans;\n    }\n\n    /**\n     * Comparing that the given name exists in the bean. For component beans,\n     * the component name will be present at the end of the bean name\n     * \n     * For example 'StandaloneServer' will present in the bean name like\n     * 'org.apache.ZooKeeperService:name0=StandaloneServer_port-1'\n     */\n    private static boolean compare(String bean, String name) {\n        String[] names = bean.split(\"=\");\n        if (names.length > 0 && names[names.length - 1].contains(name)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Ensure that the specified bean name and its attribute is registered. Note\n     * that these are components of the name. It waits in a loop up to 60\n     * seconds before failing if there is a mismatch. This will return the beans\n     * which are not matched.\n     *\n     * @param expectedName\n     *            - expected bean\n     * @param expectedAttribute\n     *            - expected attribute\n     * @return the value of the attribute\n     *\n     * @throws Exception\n     */\n    public static Object ensureBeanAttribute(String expectedName,\n            String expectedAttribute) throws Exception {\n        String value = \"\";\n        LOG.info(\"ensure bean:{}, attribute:{}\", new Object[] { expectedName,\n                expectedAttribute });\n\n        Set<ObjectName> beans;\n        int nTry = 0;\n        do {\n            if (nTry++ > 0) {\n                Thread.sleep(500);\n            }\n            try {\n                beans = conn().queryNames(\n                        new ObjectName(CommonNames.DOMAIN + \":*\"), null);\n            } catch (MalformedObjectNameException e) {\n                throw new RuntimeException(e);\n            }\n            LOG.info(\"expect:\" + expectedName);\n            for (ObjectName bean : beans) {\n                // check the existence of name in bean\n                if (bean.toString().equals(expectedName)) {\n                    LOG.info(\"found:{} {}\", new Object[] { expectedName, bean });\n                    return conn().getAttribute(bean, expectedAttribute);\n                }\n            }\n        } while (nTry < 120);\n        Assert.fail(\"Failed to find bean:\" + expectedName + \", attribute:\"\n                + expectedAttribute);\n        return value;\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/KeeperStateTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.EnumSet;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class KeeperStateTest extends ZKTestCase {\n    \n    @Test\n    public void testIntConversion() {\n        // Ensure that we can convert all valid integers to KeeperStates\n        EnumSet<KeeperState> allStates = EnumSet.allOf(KeeperState.class);\n\n        for(KeeperState as : allStates) {\n            Assert.assertEquals(as, KeeperState.fromInt( as.getIntValue() ) );\n        }\n    }\n\n    @Test\n    public void testInvalidIntConversion() {\n        try {\n            KeeperState ks = KeeperState.fromInt(324142);\n            Assert.fail(\"Was able to create an invalid KeeperState via an integer\");\n        } catch(RuntimeException re) {\n            // we're good.\n        }\n\n    }\n\n    /** Validate that the deprecated constant still works. There were issues\n     * found with switch statements - which need compile time constants.\n     */\n    @Test\n    @SuppressWarnings(\"deprecation\")\n    public void testDeprecatedCodeOkInSwitch() {\n        int test = 1;\n        switch (test) {\n        case Code.Ok:\n            Assert.assertTrue(true);\n            break;\n        }\n    }\n\n    /** Verify the enum works (paranoid) */\n    @Test\n    public void testCodeOKInSwitch() {\n        Code test = Code.OK;\n        switch (test) {\n        case OK:\n            Assert.assertTrue(true);\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/LENonTerminateTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetSocketAddress;\nimport java.net.SocketException;\nimport java.nio.ByteBuffer;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.quorum.Election;\nimport org.apache.zookeeper.server.quorum.FLELostMessageTest;\nimport org.apache.zookeeper.server.quorum.LeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.quorum.flexible.QuorumMaj;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class LENonTerminateTest extends ZKTestCase {\n    public class MockLeaderElection extends LeaderElection {\n        public MockLeaderElection(QuorumPeer self) {\n            super(self);            \n        }\n\n        /**\n         * Temporary for 3.3.0 - we want to ensure that a round of voting happens\n         * before any of the peers update their votes. The easiest way to do that\n         * is to add a latch that all wait on after counting their votes. \n         * \n         * In 3.4.0 we intend to make this class more testable, and therefore\n         * there should be much less duplicated code.\n         * \n         * JMX bean method calls are removed to reduce noise.\n         */\n        public Vote lookForLeader() throws InterruptedException {            \n            self.setCurrentVote(new Vote(self.getId(),\n                    self.getLastLoggedZxid()));\n            // We are going to look for a leader by casting a vote for ourself\n            byte requestBytes[] = new byte[4];\n            ByteBuffer requestBuffer = ByteBuffer.wrap(requestBytes);\n            byte responseBytes[] = new byte[28];\n            ByteBuffer responseBuffer = ByteBuffer.wrap(responseBytes);\n            /* The current vote for the leader. Initially me! */\n            DatagramSocket s = null;\n            try {\n                s = new DatagramSocket();\n                s.setSoTimeout(200);\n            } catch (SocketException e1) {\n                LOG.error(\"Socket exception when creating socket for leader election\", e1);\n                System.exit(4);\n            }\n            DatagramPacket requestPacket = new DatagramPacket(requestBytes,\n                    requestBytes.length);\n            DatagramPacket responsePacket = new DatagramPacket(responseBytes,\n                    responseBytes.length);\n            int xid = epochGen.nextInt();\n            while (self.isRunning()) {\n                HashMap<InetSocketAddress, Vote> votes =\n                    new HashMap<InetSocketAddress, Vote>(self.getVotingView().size());\n\n                requestBuffer.clear();\n                requestBuffer.putInt(xid);\n                requestPacket.setLength(4);\n                HashSet<Long> heardFrom = new HashSet<Long>();\n                for (QuorumServer server :\n                    self.getVotingView().values())\n                {\n                    LOG.info(\"Server address: \" + server.addr);\n                    try {\n                        requestPacket.setSocketAddress(server.addr);\n                    } catch (IllegalArgumentException e) {\n                        // Sun doesn't include the address that causes this\n                        // exception to be thrown, so we wrap the exception\n                        // in order to capture this critical detail.\n                        throw new IllegalArgumentException(\n                                \"Unable to set socket address on packet, msg:\"\n                                + e.getMessage() + \" with addr:\" + server.addr,\n                                e);\n                    }\n\n                    try {\n                        s.send(requestPacket);\n                        responsePacket.setLength(responseBytes.length);\n                        s.receive(responsePacket);\n                        if (responsePacket.getLength() != responseBytes.length) {\n                            LOG.error(\"Got a short response: \"\n                                    + responsePacket.getLength());\n                            continue;\n                        }\n                        responseBuffer.clear();\n                        int recvedXid = responseBuffer.getInt();\n                        if (recvedXid != xid) {\n                            LOG.error(\"Got bad xid: expected \" + xid\n                                    + \" got \" + recvedXid);\n                            continue;\n                        }\n                        long peerId = responseBuffer.getLong();\n                        heardFrom.add(peerId);\n                        //if(server.id != peerId){\n                        Vote vote = new Vote(responseBuffer.getLong(),\n                                responseBuffer.getLong());\n                        InetSocketAddress addr =\n                            (InetSocketAddress) responsePacket\n                            .getSocketAddress();\n                        votes.put(addr, vote);\n                        //}\n                    } catch (IOException e) {\n                        LOG.warn(\"Ignoring exception while looking for leader\",\n                                e);\n                        // Errors are okay, since hosts may be\n                        // down\n                    }\n                }\n\n                ElectionResult result = countVotes(votes, heardFrom);\n                \n                /**\n                 * This is the only difference from LeaderElection - wait for\n                 * this latch on the first time through this method. This ensures\n                 * that the first round of voting happens before setCurrentVote\n                 * is called below.\n                 */\n                LOG.info(\"Waiting for first round of voting to complete\");\n                latch.countDown();\n                Assert.assertTrue(\"Thread timed out waiting for latch\",\n                        latch.await(10000, TimeUnit.MILLISECONDS));\n                \n                // ZOOKEEPER-569:\n                // If no votes are received for live peers, reset to voting \n                // for ourselves as otherwise we may hang on to a vote \n                // for a dead peer                 \n                if (result.numValidVotes == 0) {\n                    self.setCurrentVote(new Vote(self.getId(),\n                            self.getLastLoggedZxid()));\n                } else {\n                    if (result.winner.getId() >= 0) {\n                        self.setCurrentVote(result.vote);\n                        // To do: this doesn't use a quorum verifier\n                        if (result.winningCount > (self.getVotingView().size() / 2)) {\n                            self.setCurrentVote(result.winner);\n                            s.close();\n                            Vote current = self.getCurrentVote();\n                            LOG.info(\"Found leader: my type is: \" + self.getLearnerType());\n                            /*\n                             * We want to make sure we implement the state machine\n                             * correctly. If we are a PARTICIPANT, once a leader\n                             * is elected we can move either to LEADING or \n                             * FOLLOWING. However if we are an OBSERVER, it is an\n                             * error to be elected as a Leader.\n                             */\n                            if (self.getLearnerType() == LearnerType.OBSERVER) {\n                                if (current.getId() == self.getId()) {\n                                    // This should never happen!\n                                    LOG.error(\"OBSERVER elected as leader!\");\n                                    Thread.sleep(100);\n                                }\n                                else {\n                                    self.setPeerState(ServerState.OBSERVING);\n                                    Thread.sleep(100);\n                                    return current;\n                                }\n                            } else {\n                                self.setPeerState((current.getId() == self.getId())\n                                        ? ServerState.LEADING: ServerState.FOLLOWING);\n                                if (self.getPeerState() == ServerState.FOLLOWING) {\n                                    Thread.sleep(100);\n                                }                            \n                                return current;\n                            }\n                        }\n                    }\n                }\n                Thread.sleep(1000);\n            }\n            return null;\n        }         \n    }\n    \n    public class MockQuorumPeer extends QuorumPeer {\n        public MockQuorumPeer(Map<Long,QuorumServer> quorumPeers, File snapDir,\n                File logDir, int clientPort, int electionAlg,\n                long myid, int tickTime, int initLimit, int syncLimit)\n        throws IOException\n        {\n            super(quorumPeers, snapDir, logDir, electionAlg,\n                    myid,tickTime, initLimit,syncLimit, false,\n                    ServerCnxnFactory.createFactory(clientPort, -1),\n                    new QuorumMaj(countParticipants(quorumPeers)));\n        }\n        \n        protected  Election createElectionAlgorithm(int electionAlgorithm){\n            LOG.info(\"Returning mocked leader election\");\n            return new MockLeaderElection(this);\n        }\n    }\n    \n    \n    protected static final Logger LOG = LoggerFactory.getLogger(FLELostMessageTest.class);\n    \n    int count;\n    HashMap<Long,QuorumServer> peers;\n    File tmpdir[];\n    int port[];   \n   \n    @Before\n    public void setUp() throws Exception {\n        count = 3;\n\n        peers = new HashMap<Long,QuorumServer>(count);\n        tmpdir = new File[count];\n        port = new int[count];\n    }\n\n    static final CountDownLatch latch = new CountDownLatch(2);\n    static final CountDownLatch mockLatch = new CountDownLatch(1);\n\n    class LEThread extends Thread {\n        int i;\n        QuorumPeer peer;\n        \n\n        LEThread(QuorumPeer peer, int i) {\n            this.i = i;\n            this.peer = peer;\n            LOG.info(\"Constructor: \" + getName());\n\n        }\n\n        public void run(){            \n            try{\n                Vote v = null;\n                peer.setPeerState(ServerState.LOOKING);\n                LOG.info(\"Going to call leader election: \" + i);\n                v = peer.getElectionAlg().lookForLeader();\n\n                if (v == null){\n                    Assert.fail(\"Thread \" + i + \" got a null vote\");\n                }                                \n\n                /*\n                 * A real zookeeper would take care of setting the current vote. Here\n                 * we do it manually.\n                 */\n                peer.setCurrentVote(v);\n\n                LOG.info(\"Finished election: \" + i + \", \" + v.getId());\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            LOG.info(\"Joining\");\n        }\n    }\n    \n    /**\n     * This tests ZK-569.\n     * With three peers A, B and C, the following could happen:\n     * 1. Round 1, A,B and C all vote for themselves\n     * 2. Round 2, C dies, A and B vote for C\n     * 3. Because C has died, votes for it are ignored, but A and B never\n     * reset their votes. Hence LE never terminates. ZK-569 fixes this by\n     * resetting votes to themselves if the set of votes for live peers is null.\n     */\n    @Test\n    public void testNonTermination() throws Exception {                \n        LOG.info(\"TestNonTermination: \" + getTestName()+ \", \" + count);\n        for(int i = 0; i < count; i++) {\n            int clientport = PortAssignment.unique();\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"127.0.0.1\", clientport,\n                                       PortAssignment.unique(), null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = clientport;\n        }\n        \n        /*\n         * peer1 and peer2 are A and B in the above example. \n         */\n        QuorumPeer peer1 = new MockQuorumPeer(peers, tmpdir[0], tmpdir[0], port[0], 0, 0, 2, 2, 2);\n        peer1.startLeaderElection();\n        LEThread thread1 = new LEThread(peer1, 0);\n        \n        QuorumPeer peer2 = new MockQuorumPeer(peers, tmpdir[1], tmpdir[1], port[1], 0, 1, 2, 2, 2);\n        peer2.startLeaderElection();        \n        LEThread thread2 = new LEThread(peer2, 1);\n                            \n        /*\n         * Start mock server.\n         */\n        Thread thread3 = new Thread() { \n            public void run() {\n                try {\n                    mockServer();\n                } catch (Exception e) {\n                    LOG.error(\"exception\", e);\n                    Assert.fail(\"Exception when running mocked server \" + e);\n                }\n            }\n        };        \n        \n        thread3.start();\n        Assert.assertTrue(\"mockServer did not start in 5s\",\n                mockLatch.await(5000, TimeUnit.MILLISECONDS));\n        thread1.start();\n        thread2.start();\n        /*\n         * Occasionally seen false negatives with a 5s timeout.\n         */\n        thread1.join(15000);\n        thread2.join(15000);\n        thread3.join(15000);\n        if (thread1.isAlive() || thread2.isAlive() || thread3.isAlive()) {\n            Assert.fail(\"Threads didn't join\");\n        }\n    }\n     \n    /**\n     * MockServer plays the role of peer C. Respond to two requests for votes\n     * with vote for self and then Assert.fail. \n     */\n    void mockServer() throws InterruptedException, IOException {          \n        byte b[] = new byte[36];\n        ByteBuffer responseBuffer = ByteBuffer.wrap(b);\n        DatagramPacket packet = new DatagramPacket(b, b.length);\n        QuorumServer server = peers.get(Long.valueOf(2));\n        DatagramSocket udpSocket = new DatagramSocket(server.addr.getPort());\n        LOG.info(\"In MockServer\");\n        mockLatch.countDown();\n        Vote current = new Vote(2, 1);\n        for (int i=0;i<2;++i) {\n            udpSocket.receive(packet);\n            responseBuffer.rewind();\n            LOG.info(\"Received \" + responseBuffer.getInt() + \" \" + responseBuffer.getLong() + \" \" + responseBuffer.getLong());\n            LOG.info(\"From \" + packet.getSocketAddress());\n            responseBuffer.clear();\n            responseBuffer.getInt(); // Skip the xid\n            responseBuffer.putLong(2);\n            \n            responseBuffer.putLong(current.getId());\n            responseBuffer.putLong(current.getZxid());\n            packet.setData(b);\n            udpSocket.send(packet);\n        }\n    }    \n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/LETest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Random;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.LeaderElection;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.Vote;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class LETest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(LETest.class);\n    volatile Vote votes[];\n    volatile boolean leaderDies;\n    volatile long leader = -1;\n    Random rand = new Random();\n    class LEThread extends Thread {\n        LeaderElection le;\n        int i;\n        QuorumPeer peer;\n        LEThread(LeaderElection le, QuorumPeer peer, int i) {\n            this.le = le;\n            this.i = i;\n            this.peer = peer;\n        }\n        public void run() {\n            try {\n                Vote v = null;\n                while(true) {\n                    v = le.lookForLeader();\n                    votes[i] = v;\n                    if (v.getId() == i) {\n                        synchronized(LETest.this) {\n                            if (leaderDies) {\n                                leaderDies = false;\n                                peer.stopLeaderElection();\n                                LOG.info(\"Leader \" + i + \" dying\");\n                                leader = -2;\n                            } else {\n                                leader = i;\n                            }\n                            LETest.this.notifyAll();\n                        }\n                        break;\n                    }\n                    synchronized(LETest.this) {\n                        if (leader == -1) {\n                            LETest.this.wait();\n                        }\n                        if (leader == v.getId()) {\n                            break;\n                        }\n                    }\n                    Thread.sleep(rand.nextInt(1000));\n                    peer.setCurrentVote(new Vote(peer.getId(), 0));\n                }\n                LOG.info(\"Thread \" + i + \" votes \" + v);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Test\n    public void testLE() throws Exception {\n        int count = 30;\n        HashMap<Long,QuorumServer> peers = new HashMap<Long,QuorumServer>(count);\n        ArrayList<LEThread> threads = new ArrayList<LEThread>(count);\n        File tmpdir[] = new File[count];\n        int port[] = new int[count];\n        votes = new Vote[count];\n        for(int i = 0; i < count; i++) {\n            peers.put(Long.valueOf(i),\n                      new QuorumServer(i, \"127.0.0.1\", PortAssignment.unique(), 0, null));\n            tmpdir[i] = ClientBase.createTmpDir();\n            port[i] = PortAssignment.unique();\n        }\n        LeaderElection le[] = new LeaderElection[count];\n        leaderDies = true;\n        boolean allowOneBadLeader = leaderDies;\n        for(int i = 0; i < le.length; i++) {\n            QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i],\n                    port[i], 0, i, 1000, 2, 2);\n            peer.startLeaderElection();\n            le[i] = new LeaderElection(peer);\n            LEThread thread = new LEThread(le[i], peer, i);\n            thread.start();\n            threads.add(thread);\n        }\n        for(int i = 0; i < threads.size(); i++) {\n            threads.get(i).join(15000);\n            if (threads.get(i).isAlive()) {\n                Assert.fail(\"Threads didn't join\");\n            }\n        }\n        long id = votes[0].getId();\n        for(int i = 1; i < votes.length; i++) {\n            if (votes[i] == null) {\n                Assert.fail(\"Thread \" + i + \" had a null vote\");\n            }\n            if (votes[i].getId() != id) {\n                if (allowOneBadLeader && votes[i].getId() == i) {\n                    allowOneBadLeader = false;\n                } else {\n                    Assert.fail(\"Thread \" + i + \" got \" + votes[i].getId() + \" expected \" + id);\n                }\n            }\n        }\n    }    \n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/LoadFromLogNoServerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.jute.BinaryInputArchive;\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.server.DataNode;\nimport org.apache.zookeeper.server.DataTree;\nimport org.apache.zookeeper.server.persistence.FileHeader;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.txn.CreateTxn;\nimport org.apache.zookeeper.txn.DeleteTxn;\nimport org.apache.zookeeper.txn.MultiTxn;\nimport org.apache.zookeeper.txn.Txn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class LoadFromLogNoServerTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(LoadFromLogNoServerTest.class);\n\n    /**\n     * For ZOOKEEPER-1046. Verify if cversion and pzxid if incremented\n     * after create/delete failure during restore.\n     */\n    @Test\n    public void testTxnFailure() throws Exception {\n        long count = 1;\n        File tmpDir = ClientBase.createTmpDir();\n        FileTxnSnapLog logFile = new FileTxnSnapLog(tmpDir, tmpDir);\n        DataTree dt = new DataTree();\n        dt.createNode(\"/test\", new byte[0], null, 0, -1, 1, 1);\n        for (count = 1; count <= 3; count++) {\n            dt.createNode(\"/test/\" + count, new byte[0], null, 0, -1, count,\n                    Time.currentElapsedTime());\n        }\n        DataNode zk = dt.getNode(\"/test\");\n\n        // Make create to fail, then verify cversion.\n        LOG.info(\"Attempting to create \" + \"/test/\" + (count - 1));\n        doOp(logFile, ZooDefs.OpCode.create, \"/test/\" + (count - 1), dt, zk, -1);\n\n        LOG.info(\"Attempting to create \" + \"/test/\" + (count - 1));\n        doOp(logFile, ZooDefs.OpCode.create, \"/test/\" + (count - 1), dt, zk,\n                zk.stat.getCversion() + 1);\n\n        LOG.info(\"Attempting to create \" + \"/test/\" + (count - 1));\n        doOp(logFile, ZooDefs.OpCode.multi, \"/test/\" + (count - 1), dt, zk,\n                zk.stat.getCversion() + 1);\n\n        LOG.info(\"Attempting to create \" + \"/test/\" + (count - 1));\n        doOp(logFile, ZooDefs.OpCode.multi, \"/test/\" + (count - 1), dt, zk,\n                -1);\n\n        // Make delete fo fail, then verify cversion.\n        // this doesn't happen anymore, we only set the cversion on create\n        // LOG.info(\"Attempting to delete \" + \"/test/\" + (count + 1));\n        // doOp(logFile, OpCode.delete, \"/test/\" + (count + 1), dt, zk);\n    }\n\n    /*\n     * Does create/delete depending on the type and verifies\n     * if cversion before the operation is 1 less than cversion afer.\n     */\n    private void doOp(FileTxnSnapLog logFile, int type, String path,\n                      DataTree dt, DataNode parent, int cversion) throws Exception {\n        int lastSlash = path.lastIndexOf('/');\n        String parentName = path.substring(0, lastSlash);\n\n        int prevCversion = parent.stat.getCversion();\n        long prevPzxid = parent.stat.getPzxid();\n        List<String> child = dt.getChildren(parentName, null, null);\n        String childStr = \"\";\n        for (String s : child) {\n            childStr += s + \" \";\n        }\n        LOG.info(\"Children: \" + childStr + \" for \" + parentName);\n        LOG.info(\"(cverions, pzxid): \" + prevCversion + \", \" + prevPzxid);\n\n        Record txn = null;\n        TxnHeader txnHeader = null;\n        if (type == ZooDefs.OpCode.delete) {\n            txn = new DeleteTxn(path);\n            txnHeader = new TxnHeader(0xabcd, 0x123, prevPzxid + 1,\n                    Time.currentElapsedTime(), ZooDefs.OpCode.delete);\n        } else if (type == ZooDefs.OpCode.create) {\n            txnHeader = new TxnHeader(0xabcd, 0x123, prevPzxid + 1,\n                    Time.currentElapsedTime(), ZooDefs.OpCode.create);\n            txn = new CreateTxn(path, new byte[0], null, false, cversion);\n        }\n        else if (type == ZooDefs.OpCode.multi) {\n            txnHeader = new TxnHeader(0xabcd, 0x123, prevPzxid + 1,\n                    Time.currentElapsedTime(), ZooDefs.OpCode.create);\n            txn = new CreateTxn(path, new byte[0], null, false, cversion);\n            ArrayList txnList = new ArrayList();\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n            txn.serialize(boa, \"request\") ;\n            ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n            Txn txact = new Txn(ZooDefs.OpCode.create,  bb.array());\n            txnList.add(txact);\n            txn = new MultiTxn(txnList);\n            txnHeader = new TxnHeader(0xabcd, 0x123, prevPzxid + 1,\n                    Time.currentElapsedTime(), ZooDefs.OpCode.multi);\n        }\n        logFile.processTransaction(txnHeader, dt, null, txn);\n\n        int newCversion = parent.stat.getCversion();\n        long newPzxid = parent.stat.getPzxid();\n        child = dt.getChildren(parentName, null, null);\n        childStr = \"\";\n        for (String s : child) {\n            childStr += s + \" \";\n        }\n        LOG.info(\"Children: \" + childStr + \" for \" + parentName);\n        LOG.info(\"(cverions, pzxid): \" +newCversion + \", \" + newPzxid);\n        Assert.assertTrue(type + \" <cversion, pzxid> verification failed. Expected: <\" +\n                        (prevCversion + 1) + \", \" + (prevPzxid + 1) + \">, found: <\" +\n                        newCversion + \", \" + newPzxid + \">\",\n                (newCversion == prevCversion + 1 && newPzxid == prevPzxid + 1));\n    }\n\n    /**\n     * Simulates ZOOKEEPER-1069 and verifies that flush() before padLogFile\n     * fixes it.\n     */\n    @Test\n    public void testPad() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        FileTxnLog txnLog = new FileTxnLog(tmpDir);\n        TxnHeader txnHeader = new TxnHeader(0xabcd, 0x123, 0x123,\n                Time.currentElapsedTime(), ZooDefs.OpCode.create);\n        Record txn = new CreateTxn(\"/Test\", new byte[0], null, false, 1);\n        txnLog.append(txnHeader, txn);\n        FileInputStream in = new FileInputStream(tmpDir.getPath() + \"/log.\" +\n                Long.toHexString(txnHeader.getZxid()));\n        BinaryInputArchive ia  = BinaryInputArchive.getArchive(in);\n        FileHeader header = new FileHeader();\n        header.deserialize(ia, \"fileheader\");\n        LOG.info(\"Received magic : \" + header.getMagic() +\n                \" Expected : \" + FileTxnLog.TXNLOG_MAGIC);\n        Assert.assertTrue(\"Missing magic number \",\n                header.getMagic() == FileTxnLog.TXNLOG_MAGIC);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/LoadFromLogTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.TxnLog.TxnIterator;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\n\npublic class LoadFromLogTest extends ClientBase {\n    private static final int NUM_MESSAGES = 300;\n    protected static final Logger LOG = LoggerFactory.getLogger(LoadFromLogTest.class);\n\n    // setting up the quorum has a transaction overhead for creating and closing the session\n    private static final int TRANSACTION_OVERHEAD = 2;\t\n    private static final int TOTAL_TRANSACTIONS = NUM_MESSAGES + TRANSACTION_OVERHEAD;\n\n    @Before\n     public void setUp() throws Exception {\n                SyncRequestProcessor.setSnapCount(50);\n                super.setUp();\n            }\n\n    /**\n     * test that all transactions from the Log are loaded, and only once\n     * @throws Exception an exception might be thrown here\n     */\n    @Test\n    public void testLoad() throws Exception {\n        ZooKeeper zk = createZKClient(hostPort);\n\n        // generate some transactions that will get logged\n        try {\n            for (int i = 0; i< NUM_MESSAGES; i++) {\n                zk.create(\"/invalidsnap-\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n        stopServer();\n\n        // now verify that the FileTxnLog reads every transaction only once\n        File logDir = new File(tmpDir, FileTxnSnapLog.version + FileTxnSnapLog.VERSION);\n        FileTxnLog txnLog = new FileTxnLog(logDir);\n\n        TxnIterator itr = txnLog.read(0);\n        long expectedZxid = 0;\n        long lastZxid = 0;\n        TxnHeader hdr;\n        do {\n            hdr = itr.getHeader();\n            expectedZxid++;\n            Assert.assertTrue(\"not the same transaction. lastZxid=\" + lastZxid + \", zxid=\" + hdr.getZxid(), lastZxid != hdr.getZxid());\n            Assert.assertTrue(\"excepting next transaction. expected=\" + expectedZxid + \", retreived=\" + hdr.getZxid(), (hdr.getZxid() == expectedZxid));\n            lastZxid = hdr.getZxid();\n        }while(itr.next());\n\t\n        Assert.assertTrue(\"processed all transactions. \" + expectedZxid + \" == \" + TOTAL_TRANSACTIONS, (expectedZxid == TOTAL_TRANSACTIONS));\n    }\n\n    /**\n     * Test we can restore the snapshot that has data ahead of the zxid\n     * of the snapshot file. \n     */\n    @Test\n    public void testRestore() throws Exception {\n        ZooKeeper zk = createZKClient(hostPort);\n\n\t\t// generate some transactions\n\t\tString lastPath = null;\n\t\ttry {\n\t\t\tzk.create(\"/invalidsnap\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n\t\t\t\t\tCreateMode.PERSISTENT);\n\t\t\tfor (int i = 0; i < NUM_MESSAGES; i++) {\n\t\t\t\tlastPath = zk.create(\"/invalidsnap/test-\", new byte[0],\n\t\t\t\t\t\tIds.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n\t\t\t}\n\t\t} finally {\n\t\t\tzk.close();\n\t\t}\n\t\tString[] tokens = lastPath.split(\"-\");\n\t\tString expectedPath = \"/invalidsnap/test-\"\n\t\t\t\t+ String.format(\"%010d\",\n                Integer.parseInt(tokens[1]) + 1);\n        ZooKeeperServer zks = getServer(serverFactory);\n\t\tlong eZxid = zks.getZKDatabase().getDataTreeLastProcessedZxid();\n\t\t// force the zxid to be behind the content\n\t\tzks.getZKDatabase().setlastProcessedZxid(\n\t\t\t\tzks.getZKDatabase().getDataTreeLastProcessedZxid() - 10);\n\t\tLOG.info(\"Set lastProcessedZxid to \"\n\t\t\t\t+ zks.getZKDatabase().getDataTreeLastProcessedZxid());\n\t\t// Force snapshot and restore\n\t\tzks.takeSnapshot();\n\t\tzks.shutdown();\n\t\tstopServer();\n\n\t\tstartServer();\n\t\tzks = getServer(serverFactory);\n\t\tlong fZxid = zks.getZKDatabase().getDataTreeLastProcessedZxid();\n\n\t\t// Verify lastProcessedZxid is set correctly\n\t\tAssert.assertTrue(\"Restore failed expected zxid=\" + eZxid + \" found=\"\n\t\t\t\t+ fZxid, fZxid == eZxid);\n        zk = createZKClient(hostPort);\n\n\t\t// Verify correctness of data and whether sequential znode creation \n\t\t// proceeds correctly after this point\n\t\tString[] children;\n\t\tString path;\n\t\ttry {\n\t\t\tchildren = zk.getChildren(\"/invalidsnap\", false).toArray(\n\t\t\t\t\tnew String[0]);\n\t\t\tpath = zk.create(\"/invalidsnap/test-\", new byte[0],\n\t\t\t\t\tIds.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n\t\t} finally {\n\t\t\tzk.close();\n\t\t}\n\t\tLOG.info(\"Expected \" + expectedPath + \" found \" + path);\n\t\tAssert.assertTrue(\"Error in sequential znode creation expected \"\n\t\t\t\t+ expectedPath + \" found \" + path, path.equals(expectedPath));\n\t\tAssert.assertTrue(\"Unexpected number of children \" + children.length\n\t\t\t\t+ \" expected \" + NUM_MESSAGES,\n\t\t\t\t(children.length == NUM_MESSAGES));\n\t}\n    \n    /**\n     * Test we can restore a snapshot that has errors and data ahead of the zxid\n     * of the snapshot file. \n     */\n    @Test\n    public void testRestoreWithTransactionErrors() throws Exception {\n        ZooKeeper zk = createZKClient(hostPort);\n\n        // generate some transactions\n        try {\n            for (int i = 0; i < NUM_MESSAGES; i++) {\n                try {\n                    zk.create(\"/invaliddir/test-\", new byte[0],\n                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                } catch(NoNodeException e) {\n                    //Expected\n                }\n            }\n        } finally {\n            zk.close();\n        }\n\n        // force the zxid to be behind the content\n        ZooKeeperServer zks = getServer(serverFactory);\n        zks.getZKDatabase().setlastProcessedZxid(\n                zks.getZKDatabase().getDataTreeLastProcessedZxid() - 10);\n        LOG.info(\"Set lastProcessedZxid to \"\n                + zks.getZKDatabase().getDataTreeLastProcessedZxid());\n        \n        // Force snapshot and restore\n        zks.takeSnapshot();\n        zks.shutdown();\n        stopServer();\n\n        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        startServer();\n   }\n\n    /**\n     * ZOOKEEPER-1573: test restoring a snapshot with deleted txns ahead of the\n     * snapshot file's zxid.\n     */\n    @Test\n    public void testReloadSnapshotWithMissingParent() throws Exception {\n        ZooKeeper zk = createZKClient(hostPort);\n\n        // create transactions to create the snapshot with create/delete pattern\n        zk.create(\"/a\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        Stat stat = zk.exists(\"/a\", false);\n        long createZxId = stat.getMzxid();\n        zk.create(\"/a/b\", \"\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.delete(\"/a/b\", -1);\n        zk.delete(\"/a\", -1);\n        // force the zxid to be behind the content\n        ZooKeeperServer zks = getServer(serverFactory);\n        zks.getZKDatabase().setlastProcessedZxid(createZxId);\n        LOG.info(\"Set lastProcessedZxid to {}\", zks.getZKDatabase()\n                .getDataTreeLastProcessedZxid());\n        // Force snapshot and restore\n        zks.takeSnapshot();\n        zks.shutdown();\n        stopServer();\n        startServer();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/MaxCnxnsTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.proto.ConnectRequest;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class MaxCnxnsTest extends ClientBase {\n    final private int numCnxns = 30;\n    AtomicInteger numConnected = new AtomicInteger(0);\n    String host;\n    int port;\n\n    @Override\n    public void setUp() throws Exception {\n        maxCnxns = numCnxns;\n        super.setUp();\n    }\n\n    class CnxnThread extends Thread {\n        int i;\n        SocketChannel socket;\n        public CnxnThread(int i) {\n            super(\"CnxnThread-\"+i);\n            this.i = i;\n        }\n\n        public void run() {\n            SocketChannel sChannel = null;\n            try {\n                /*\n                 * For future unwary socket programmers: although connect 'blocks' it\n                 * does not require an accept on the server side to return. Therefore\n                 * you can not assume that all the sockets are connected at the end of\n                 * this for loop.\n                 */\n                sChannel = SocketChannel.open();\n                sChannel.connect(new InetSocketAddress(host,port));\n                // Construct a connection request\n                ConnectRequest conReq = new ConnectRequest(0, 0,\n                        10000, 0, \"password\".getBytes());\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n                boa.writeInt(-1, \"len\");\n                conReq.serialize(boa, \"connect\");\n                baos.close();\n                ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());\n                bb.putInt(bb.capacity() - 4);\n                bb.rewind();\n\n                /* Send a connect request. Any socket that has been closed (or at least\n                 * not added to the cnxn list on the server) will not have any bytes to\n                 * read and get an eof.\n                 *\n                 *  The trick here was finding a call that caused the server to put\n                 *  bytes in the input stream without closing the cnxn. None of\n                 *  the four letter commands do that, so we actually try to create\n                 *  a session which should send us something back, while maintaining\n                 *  the connection.\n                 */\n\n                int eof = sChannel.write(bb);\n                // If the socket times out, we count that as Assert.failed -\n                // the server should respond within 10s\n                sChannel.socket().setSoTimeout(10000);\n                if (!sChannel.socket().isClosed()){\n                    eof = sChannel.socket().getInputStream().read();\n                    if (eof != -1) {\n                        numConnected.incrementAndGet();\n                    }\n                }\n            }\n            catch (IOException io) {\n                // \"Connection reset by peer\"\n            }\n            finally {\n                if (sChannel != null) {\n                    try {\n                        sChannel.close();\n                    }\n                    catch (Exception e) {\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Verify the ability to limit the number of concurrent connections.\n     * @throws IOException\n     * @throws InterruptedException\n     */\n    @Test\n    public void testMaxCnxns() throws IOException, InterruptedException{\n        String split[] = hostPort.split(\":\");\n        host = split[0];\n        port = Integer.parseInt(split[1]);\n        int numThreads = numCnxns + 5;\n        CnxnThread[] threads = new CnxnThread[numThreads];\n\n        for (int i=0;i<numCnxns;++i) {\n          threads[i] = new CnxnThread(i);\n        }\n\n        for (int i=0;i<numCnxns;++i) {\n            threads[i].start();\n        }\n\n        for (int i=0;i<numCnxns;++i) {\n            threads[i].join();\n        }\n        Assert.assertSame(numCnxns,numConnected.get());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/MultiTransactionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.*;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.log4j.Logger;\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.AsyncCallback.MultiCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.OpResult;\nimport org.apache.zookeeper.Transaction;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.OpResult.CheckResult;\nimport org.apache.zookeeper.OpResult.CreateResult;\nimport org.apache.zookeeper.OpResult.DeleteResult;\nimport org.apache.zookeeper.OpResult.ErrorResult;\nimport org.apache.zookeeper.OpResult.SetDataResult;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n@RunWith(Parameterized.class)\npublic class MultiTransactionTest extends ClientBase {\n    private static final Logger LOG = Logger.getLogger(MultiTransactionTest.class);\n\n    private ZooKeeper zk;\n    private ZooKeeper zk_chroot;\n\n    private final boolean useAsync;\n\n    public MultiTransactionTest(boolean useAsync) {\n        this.useAsync = useAsync;\n    }\n\n    @Parameters\n    public static Collection<Object[]> configs() {\n        return Arrays.asList(new Object[][] {\n            { false }, { true },\n        });\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        SyncRequestProcessor.setSnapCount(150);\n        super.setUp();\n        zk = createClient();\n    }\n\n    static class MultiResult {\n        int rc;\n        List<OpResult> results;\n        boolean finished = false;\n    }\n\n    private List<OpResult> multi(ZooKeeper zk, Iterable<Op> ops)\n    throws KeeperException, InterruptedException {\n        if (useAsync) {\n            final MultiResult res = new MultiResult();\n            zk.multi(ops, new MultiCallback() {\n                @Override\n                public void processResult(int rc, String path, Object ctx,\n                                          List<OpResult> opResults) {\n                    synchronized (res) {\n                        res.rc = rc;\n                        res.results = opResults;\n                        res.finished = true;\n                        res.notifyAll();\n                    }\n                }\n            }, null);\n            synchronized (res) {\n                while (!res.finished) {\n                    res.wait();\n                }\n            }\n            if (KeeperException.Code.OK.intValue() != res.rc) {\n                KeeperException ke = KeeperException.create(KeeperException.Code.get(res.rc));\n                throw ke;\n            }\n            return res.results;\n        } else {\n            return zk.multi(ops);\n        }\n    }\n\n    private void multiHavingErrors(ZooKeeper zk, Iterable<Op> ops,\n            List<Integer> expectedResultCodes, String expectedErr)\n            throws KeeperException, InterruptedException {\n        if (useAsync) {\n            final MultiResult res = new MultiResult();\n            zk.multi(ops, new MultiCallback() {\n                    @Override\n                    public void processResult(int rc, String path, Object ctx,\n                                              List<OpResult> opResults) {\n                        synchronized (res) {\n                            res.rc = rc;\n                            res.results = opResults;\n                            res.finished = true;\n                            res.notifyAll();\n                        }\n                    }\n                }, null);\n            synchronized (res) {\n                while (!res.finished) {\n                    res.wait();\n                }\n            }\n            for (int i = 0; i < res.results.size(); i++) {\n                OpResult opResult = res.results.get(i);\n                Assert.assertTrue(\"Did't recieve proper error response\",\n                                  opResult instanceof ErrorResult);\n                ErrorResult errRes = (ErrorResult) opResult;\n                Assert.assertEquals(\"Did't recieve proper error code\",\n                                    expectedResultCodes.get(i).intValue(), errRes.getErr());\n            }\n        } else {\n            try {\n                zk.multi(ops);\n                Assert.fail(\"Shouldn't have validated in ZooKeeper client!\");\n            } catch (KeeperException e) {\n                Assert.assertEquals(\"Wrong exception\", expectedErr, e.code()\n                                    .name());\n            } catch (IllegalArgumentException e) {\n                Assert.assertEquals(\"Wrong exception\", expectedErr,\n                                    e.getMessage());\n            }\n        }\n    }\n\n    private List<OpResult> commit(Transaction txn)\n    throws KeeperException, InterruptedException {\n        if (useAsync) {\n            final MultiResult res = new MultiResult();\n            txn.commit(new MultiCallback() {\n                @Override\n                public void processResult(int rc, String path, Object ctx,\n                                          List<OpResult> opResults) {\n                    synchronized (res) {\n                        res.rc = rc;\n                        res.results = opResults;\n                        res.finished = true;\n                        res.notifyAll();\n                    }\n                }\n            }, null);\n            synchronized (res) {\n                while (!res.finished) {\n                    res.wait();\n                }\n            }\n            if (KeeperException.Code.OK.intValue() != res.rc) {\n                KeeperException ke = KeeperException.create(KeeperException.Code.get(res.rc));\n                throw ke;\n            }\n            return res.results;\n        } else {\n            return txn.commit();\n        }\n    }\n\n    /**\n     * Test verifies the multi calls with invalid znode path\n     */\n    @Test(timeout = 90000)\n    public void testInvalidPath() throws Exception {\n        List<Integer> expectedResultCodes = new ArrayList<Integer>();\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n        expectedResultCodes.add(KeeperException.Code.BADARGUMENTS.intValue());\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n        // create with CreateMode\n        List<Op> opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  CreateMode.PERSISTENT),\n                                        Op.create(\n                                                  \"/multi1/\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  CreateMode.PERSISTENT),\n                                        Op.create(\"/multi2\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  CreateMode.PERSISTENT));\n        String expectedErr = \"Path must not end with / character\";\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n\n        // create with valid sequential flag\n        opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                         Ids.OPEN_ACL_UNSAFE,\n                                         CreateMode.PERSISTENT),\n                               Op.create(\"multi1/\", new byte[0],\n                                         Ids.OPEN_ACL_UNSAFE,\n                                         CreateMode.EPHEMERAL_SEQUENTIAL.toFlag()),\n                               Op.create(\"/multi2\",\n                                         new byte[0], Ids.OPEN_ACL_UNSAFE,\n                                         CreateMode.PERSISTENT));\n        expectedErr = \"Path must start with / character\";\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n\n        // check\n        opList = Arrays.asList(Op.check(\"/multi0\", -1),\n                               Op.check(\"/multi1/\", 100),\n                               Op.check(\"/multi2\", 5));\n        expectedErr = \"Path must not end with / character\";\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n\n        // delete\n        opList = Arrays.asList(Op.delete(\"/multi0\", -1),\n                               Op.delete(\"/multi1/\", 100),\n                               Op.delete(\"/multi2\", 5));\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n\n        // Multiple bad arguments\n        expectedResultCodes.add(KeeperException.Code.BADARGUMENTS.intValue());\n\n        // setdata\n        opList = Arrays.asList(Op.setData(\"/multi0\", new byte[0], -1),\n                               Op.setData(\"/multi1/\", new byte[0], -1),\n                               Op.setData(\"/multi2\", new byte[0], -1),\n                               Op.setData(\"multi3\", new byte[0], -1));\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n    }\n\n    /**\n     * Test verifies the multi calls with blank znode path\n     */\n    @Test(timeout = 90000)\n    public void testBlankPath() throws Exception {\n        List<Integer> expectedResultCodes = new ArrayList<Integer>();\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n        expectedResultCodes.add(KeeperException.Code.BADARGUMENTS.intValue());\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n        expectedResultCodes.add(KeeperException.Code.BADARGUMENTS.intValue());\n\n        // delete\n        String expectedErr = \"Path cannot be null\";\n        List<Op> opList = Arrays.asList(Op.delete(\"/multi0\", -1),\n                                        Op.delete(null, 100),\n                                        Op.delete(\"/multi2\", 5),\n                                        Op.delete(\"\", -1));\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n    }\n\n    /**\n     * Test verifies the multi.create with invalid createModeFlag\n     */\n    @Test(timeout = 90000)\n    public void testInvalidCreateModeFlag() throws Exception {\n        List<Integer> expectedResultCodes = new ArrayList<Integer>();\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n        expectedResultCodes.add(KeeperException.Code.BADARGUMENTS.intValue());\n        expectedResultCodes.add(KeeperException.Code.RUNTIMEINCONSISTENCY\n                                .intValue());\n\n        int createModeFlag = 6789;\n        List<Op> opList = Arrays.asList(Op.create(\"/multi0\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  CreateMode.PERSISTENT),\n                                        Op.create(\"/multi1\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  createModeFlag),\n                                        Op.create(\"/multi2\", new byte[0],\n                                                  Ids.OPEN_ACL_UNSAFE,\n                                                  CreateMode.PERSISTENT));\n        String expectedErr = KeeperException.Code.BADARGUMENTS.name();\n        multiHavingErrors(zk, opList, expectedResultCodes, expectedErr);\n    }\n\n    /**\n     * ZOOKEEPER-2052:\n     * Multi abort shouldn't have any side effect.\n     * We fix a bug in rollback and the following scenario should work:\n     * 1. multi delete abort because of not empty directory\n     * 2. ephemeral nodes under that directory are deleted\n     * 3. multi delete should succeed.\n     */\n    @Test\n    public void testMultiRollback() throws Exception {\n        zk.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n\n        ZooKeeper epheZk = createClient();\n        epheZk.create(\"/foo/bar\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n        List<Op> opList = Arrays.asList(Op.delete(\"/foo\", -1));\n        try {\n            multi(zk, opList);\n            Assert.fail(\"multi delete should failed for not empty directory\");\n        } catch (KeeperException.NotEmptyException e) {\n        }\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        zk.exists(\"/foo/bar\", new Watcher() {\n                @Override\n                public void process(WatchedEvent event) {\n                    if (event.getType() == Event.EventType.NodeDeleted){\n                        latch.countDown();\n                    }\n                }\n            });\n\n        epheZk.close();\n\n        latch.await();\n\n        try {\n            zk.getData(\"/foo/bar\", false, null);\n            Assert.fail(\"ephemeral node should have been deleted\");\n        } catch (KeeperException.NoNodeException e) {\n        }\n\n        multi(zk, opList);\n\n        try {\n            zk.getData(\"/foo\", false, null);\n            Assert.fail(\"persistent node should have been deleted after multi\");\n        } catch (KeeperException.NoNodeException e) {\n        }\n    }\n\n    @Test\n    public void testChRootCreateDelete() throws Exception {\n        // creating the subtree for chRoot clients.\n        String chRoot = createNameSpace();\n        // Creating child using chRoot client.\n        zk_chroot = createClient(this.hostPort + chRoot);\n        Op createChild = Op.create(\"/myid\", new byte[0],\n                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        multi(zk_chroot, Arrays.asList(createChild));\n        \n        Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, zk\n                .exists(chRoot + \"/myid\", false));\n        Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot,\n                zk_chroot.exists(\"/myid\", false));\n        Assert.assertNull(\"zNode is created directly under '/', ignored configured chroot\",\n                zk.exists(\"/myid\", false));\n        \n        // Deleting child using chRoot client.\n        Op deleteChild = Op.delete(\"/myid\", 0);\n        multi(zk_chroot, Arrays.asList(deleteChild));\n        Assert.assertNull(\"zNode exists under chroot:\" + chRoot, zk.exists(\n                chRoot + \"/myid\", false));\n        Assert.assertNull(\"zNode exists under chroot:\" + chRoot, zk_chroot\n                .exists(\"/myid\", false));\n    }\n\n    @Test\n    public void testChRootSetData() throws Exception {\n        // creating the subtree for chRoot clients.\n        String chRoot = createNameSpace();\n        // setData using chRoot client.\n        zk_chroot = createClient(this.hostPort + chRoot);\n        String[] names = {\"/multi0\", \"/multi1\", \"/multi2\"};\n        List<Op> ops = new ArrayList<Op>();\n\n        for (int i = 0; i < names.length; i++) {\n            ops.add(Op.create(names[i], new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT));\n            ops.add(Op.setData(names[i], names[i].getBytes(), 0));\n        }\n\n        multi(zk_chroot, ops) ;\n\n        for (int i = 0; i < names.length; i++) {\n            Assert.assertArrayEquals(\"zNode data not matching\", names[i]\n                    .getBytes(), zk_chroot.getData(names[i], false, null));\n        }\n    }\n\n    @Test\n    public void testChRootCheck() throws Exception {\n        // creating the subtree for chRoot clients.\n        String chRoot = createNameSpace();\n        // checking the child version using chRoot client.\n        zk_chroot = createClient(this.hostPort + chRoot);\n        String[] names = {\"/multi0\", \"/multi1\", \"/multi2\"};\n        List<Op> ops = new ArrayList<Op>();\n        for (int i = 0; i < names.length; i++) {\n            zk.create(chRoot + names[i], new byte[0], Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n        for (int i = 0; i < names.length; i++) {\n            ops.add(Op.check(names[i], 0));\n        }\n        multi(zk_chroot, ops) ;\n    }\n\n    @Test\n    public void testChRootTransaction() throws Exception {\n        // creating the subtree for chRoot clients.\n        String chRoot = createNameSpace();\n        // checking the child version using chRoot client.\n        zk_chroot = createClient(this.hostPort + chRoot);\n        String childPath = \"/myid\";\n        Transaction transaction = zk_chroot.transaction();\n        transaction.create(childPath, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        transaction.check(childPath, 0);\n        transaction.setData(childPath, childPath.getBytes(), 0);\n        commit(transaction);\n\n        Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot, zk\n                .exists(chRoot + childPath, false));\n        Assert.assertNotNull(\"zNode is not created under chroot:\" + chRoot,\n                zk_chroot.exists(childPath, false));\n        Assert.assertNull(\"zNode is created directly under '/', ignored configured chroot\",\n                        zk.exists(childPath, false));\n        Assert.assertArrayEquals(\"zNode data not matching\", childPath\n                .getBytes(), zk_chroot.getData(childPath, false, null));\n\n        transaction = zk_chroot.transaction();\n        // Deleting child using chRoot client.\n        transaction.delete(childPath, 1);\n        commit(transaction);\n\n        Assert.assertNull(\"chroot:\" + chRoot + \" exists after delete\", zk\n                .exists(chRoot + \"/myid\", false));\n        Assert.assertNull(\"chroot:\" + chRoot + \" exists after delete\",\n                zk_chroot.exists(\"/myid\", false));\n    }\n\n    private String createNameSpace() throws InterruptedException,\n            KeeperException {\n        // creating the subtree for chRoot clients.\n        String chRoot = \"/appsX\";\n        Op createChRoot = Op.create(chRoot, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        multi(zk, Arrays.asList(createChRoot));\n        return chRoot;\n    }\n\n    @Test\n    public void testCreate() throws Exception {\n        multi(zk, Arrays.asList(\n                Op.create(\"/multi0\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi1\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi2\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                ));\n        zk.getData(\"/multi0\", false, null);\n        zk.getData(\"/multi1\", false, null);\n        zk.getData(\"/multi2\", false, null);\n    }\n    \n    @Test\n    public void testCreateDelete() throws Exception {\n\n        multi(zk, Arrays.asList(\n                Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.delete(\"/multi\", 0)\n                ));\n\n        // '/multi' should have been deleted\n        Assert.assertNull(zk.exists(\"/multi\", null));\n    }\n\n    @Test\n    public void testInvalidVersion() throws Exception {\n\n        try {\n            multi(zk, Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/multi\", 1)\n            ));\n            Assert.fail(\"delete /multi should have failed\");\n        } catch (KeeperException e) {\n            /* PASS */\n        }\n    }\n\n    @Test\n    public void testNestedCreate() throws Exception {\n\n        multi(zk, Arrays.asList(\n                /* Create */\n                Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi/a\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.create(\"/multi/a/1\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n\n                /* Delete */\n                Op.delete(\"/multi/a/1\", 0),\n                Op.delete(\"/multi/a\", 0),\n                Op.delete(\"/multi\", 0)\n                ));\n\n        //Verify tree deleted\n        Assert.assertNull(zk.exists(\"/multi/a/1\", null));\n        Assert.assertNull(zk.exists(\"/multi/a\", null));\n        Assert.assertNull(zk.exists(\"/multi\", null));\n    }\n\n    @Test\n    public void testSetData() throws Exception {\n\n        String[] names = {\"/multi0\", \"/multi1\", \"/multi2\"};\n        List<Op> ops = new ArrayList<Op>();\n\n        for (int i = 0; i < names.length; i++) {\n            ops.add(Op.create(names[i], new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT));\n            ops.add(Op.setData(names[i], names[i].getBytes(), 0));\n        }\n\n        multi(zk, ops) ;\n\n        for (int i = 0; i < names.length; i++) {\n            Assert.assertArrayEquals(names[i].getBytes(), zk.getData(names[i], false, null));\n        }\n    }\n\n    @Test\n    public void testUpdateConflict() throws Exception {\n    \n        Assert.assertNull(zk.exists(\"/multi\", null));\n        \n        try {\n            multi(zk, Arrays.asList(\n                    Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.setData(\"/multi\", \"X\".getBytes(), 0),\n                    Op.setData(\"/multi\", \"Y\".getBytes(), 0)\n                    ));\n            Assert.fail(\"Should have thrown a KeeperException for invalid version\");\n        } catch (KeeperException e) {\n            //PASS\n            LOG.error(\"STACKTRACE: \" + e);\n        }\n\n        Assert.assertNull(zk.exists(\"/multi\", null));\n\n        //Updating version solves conflict -- order matters\n        multi(zk, Arrays.asList(\n                Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.setData(\"/multi\", \"X\".getBytes(), 0),\n                Op.setData(\"/multi\", \"Y\".getBytes(), 1)\n                ));\n\n        Assert.assertArrayEquals(zk.getData(\"/multi\", false, null), \"Y\".getBytes());\n    }\n\n    @Test\n    public void TestDeleteUpdateConflict() throws Exception {\n\n        /* Delete of a node folowed by an update of the (now) deleted node */\n        try {\n            multi(zk, Arrays.asList(\n                Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.delete(\"/multi\", 0),\n                Op.setData(\"/multi\", \"Y\".getBytes(), 0)\n                ));\n            Assert.fail(\"/multi should have been deleted so setData should have failed\");\n        } catch (KeeperException e) {\n            /* PASS */\n        }\n\n        // '/multi' should never have been created as entire op should fail\n        Assert.assertNull(zk.exists(\"/multi\", null)) ;\n    }\n\n    @Test\n    public void TestGetResults() throws Exception {\n        /* Delete of a node folowed by an update of the (now) deleted node */\n        Iterable<Op> ops = Arrays.asList(\n                Op.create(\"/multi\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.delete(\"/multi\", 0),\n                Op.setData(\"/multi\", \"Y\".getBytes(), 0),\n                Op.create(\"/foo\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n        );\n        List<OpResult> results = null;\n        if (useAsync) {\n            final MultiResult res = new MultiResult();\n            zk.multi(ops, new MultiCallback() {\n                @Override\n                public void processResult(int rc, String path, Object ctx,\n                                          List<OpResult> opResults) {\n                    synchronized (res) {\n                        res.rc = rc;\n                        res.results = opResults;\n                        res.finished = true;\n                        res.notifyAll();\n                    }\n                }\n            }, null);\n            synchronized (res) {\n                while (!res.finished) {\n                    res.wait();\n                }\n            }\n            Assert.assertFalse(\"/multi should have been deleted so setData should have failed\",\n                               KeeperException.Code.OK.intValue() == res.rc);\n            Assert.assertNull(zk.exists(\"/multi\", null));\n            results = res.results;\n        } else {\n            try {\n                zk.multi(ops);\n                Assert.fail(\"/multi should have been deleted so setData should have failed\");\n            } catch (KeeperException e) {\n                // '/multi' should never have been created as entire op should fail\n                Assert.assertNull(zk.exists(\"/multi\", null));\n                results = e.getResults();\n            }\n        }\n\n        Assert.assertNotNull(results);\n        for (OpResult r : results) {\n            LOG.info(\"RESULT==> \" + r);\n            if (r instanceof ErrorResult) {\n                ErrorResult er = (ErrorResult) r;\n                LOG.info(\"ERROR RESULT: \" + er + \" ERR=>\" + KeeperException.Code.get(er.getErr()));\n            }\n        }\n    }\n\n    /**\n     * Exercise the equals methods of OpResult classes.\n     */\n    @Test\n    public void testOpResultEquals() {\n        opEquals(new CreateResult(\"/foo\"),\n                new CreateResult(\"/foo\"),\n                new CreateResult(\"nope\"));\n\n        opEquals(new CheckResult(),\n                new CheckResult(),\n                null);\n        \n        opEquals(new SetDataResult(new Stat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)),\n                new SetDataResult(new Stat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)),\n                new SetDataResult(new Stat(11, 12, 13, 14, 15, 16, 17, 18, 19, 110, 111)));\n        \n        opEquals(new ErrorResult(1),\n                new ErrorResult(1),\n                new ErrorResult(2));\n        \n        opEquals(new DeleteResult(),\n                new DeleteResult(),\n                null);\n\n        opEquals(new ErrorResult(1),\n                new ErrorResult(1),\n                new ErrorResult(2));\n    }\n\n    private void opEquals(OpResult expected, OpResult value, OpResult near) {\n        assertEquals(value, value);\n        assertFalse(value.equals(new Object()));\n        assertFalse(value.equals(near));\n        assertFalse(value.equals(value instanceof CreateResult ?\n                new ErrorResult(1) : new CreateResult(\"nope2\")));\n        assertTrue(value.equals(expected));\n    }\n\n    @Test\n    public void testWatchesTriggered() throws KeeperException, InterruptedException {\n        HasTriggeredWatcher watcher = new HasTriggeredWatcher();\n        zk.getChildren(\"/\", watcher);\n        multi(zk, Arrays.asList(\n                Op.create(\"/t\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                Op.delete(\"/t\", -1)\n        ));\n        assertTrue(watcher.triggered.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testNoWatchesTriggeredForFailedMultiRequest() throws InterruptedException, KeeperException {\n        HasTriggeredWatcher watcher = new HasTriggeredWatcher();\n        zk.getChildren(\"/\", watcher);\n        try {\n            multi(zk, Arrays.asList(\n                    Op.create(\"/t\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),\n                    Op.delete(\"/nonexisting\", -1)\n            ));\n            fail(\"expected previous multi op to fail!\");\n        } catch (KeeperException.NoNodeException e) {\n            // expected\n        }\n        SyncCallback cb = new SyncCallback();\n        zk.sync(\"/\", cb, null);\n\n        // by waiting for the callback we're assured that the event queue is flushed\n        cb.done.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);\n        assertEquals(1, watcher.triggered.getCount());\n    }\n    \n    @Test\n    public void testTransactionBuilder() throws Exception {\n        List<OpResult> results = commit(zk.transaction()\n                .create(\"/t1\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                .create(\"/t1/child\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                .create(\"/t2\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL));\n        assertEquals(3, results.size());\n        for (OpResult r : results) {\n            CreateResult c = (CreateResult)r;\n            assertTrue(c.getPath().startsWith(\"/t\"));\n            assertNotNull(c.toString());\n        }\n        assertNotNull(zk.exists(\"/t1\", false));\n        assertNotNull(zk.exists(\"/t1/child\", false));\n        assertNotNull(zk.exists(\"/t2\", false));\n        \n        results = commit(zk.transaction()\n                .check(\"/t1\", 0)\n                .check(\"/t1/child\", 0)\n                .check(\"/t2\", 0));\n        assertEquals(3, results.size());\n        for (OpResult r : results) {\n            CheckResult c = (CheckResult)r;\n            assertNotNull(c.toString());\n        }\n        \n        try {\n            results = commit(zk.transaction()\n                    .check(\"/t1\", 0)\n                    .check(\"/t1/child\", 0)\n                    .check(\"/t2\", 1));\n            fail();\n        } catch (KeeperException.BadVersionException e) {\n            // expected\n        }\n        \n        results = commit(zk.transaction()\n                .check(\"/t1\", 0)\n                .setData(\"/t1\", new byte[0], 0));\n        assertEquals(2, results.size());\n        for (OpResult r : results) {\n            assertNotNull(r.toString());\n        }\n\n        try {\n            results = commit(zk.transaction()\n                    .check(\"/t1\", 1)\n                    .setData(\"/t1\", new byte[0], 2));\n            fail();\n        } catch (KeeperException.BadVersionException e) {\n            // expected\n        }\n        \n        results = commit(zk.transaction()\n                .check(\"/t1\", 1)\n                .check(\"/t1/child\", 0)\n                .check(\"/t2\", 0));\n        assertEquals(3, results.size());\n\n        results = commit(zk.transaction()\n                .delete(\"/t2\", -1)\n                .delete(\"/t1/child\", -1));\n        assertEquals(2, results.size());\n        for (OpResult r : results) {\n            DeleteResult d = (DeleteResult)r;\n            assertNotNull(d.toString());\n        }\n        assertNotNull(zk.exists(\"/t1\", false));\n        assertNull(zk.exists(\"/t1/child\", false));\n        assertNull(zk.exists(\"/t2\", false));\n    }\n\n    private static class HasTriggeredWatcher implements Watcher {\n        private final CountDownLatch triggered = new CountDownLatch(1);\n\n        @Override\n        public void process(WatchedEvent event) {\n            triggered.countDown();\n        }\n    }\n    private static class SyncCallback implements AsyncCallback.VoidCallback {\n        private final CountDownLatch done = new CountDownLatch(1);\n\n        @Override\n        public void processResult(int rc, String path, Object ctx) {\n            done.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/NioNettySuiteBase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.zookeeper.server.NettyServerCnxnFactory;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\n\n/**\n * Run tests with: Nio Client against Netty server\n */\n@RunWith(Suite.class)\npublic class NioNettySuiteBase {\n    @BeforeClass\n    public static void setUp() {\n        System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,\n                NettyServerCnxnFactory.class.getName());\n    }\n\n    @AfterClass\n    public static void tearDown() {\n        System.clearProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/NioNettySuiteHammerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.junit.runners.Suite;\n\n/**\n * Run tests with: Nio Client against Netty server\n */\n@Suite.SuiteClasses({\n        AsyncHammerTest.class\n        })\npublic class NioNettySuiteHammerTest extends NioNettySuiteBase {\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/NioNettySuiteTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.junit.runners.Suite;\n\n/**\n * Run tests with: Nio Client against Netty server\n */\n@Suite.SuiteClasses({\n        ACLTest.class,\n        AsyncOpsTest.class,\n        ChrootClientTest.class,\n        ClientTest.class,\n        FourLetterWordsTest.class,\n        NullDataTest.class,\n        SessionTest.class,\n        WatcherTest.class\n        })\npublic class NioNettySuiteTest extends NioNettySuiteBase {\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/NonRecoverableErrorTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.util.UUID;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * This class tests the non-recoverable error behavior of quorum server.\n */\npublic class NonRecoverableErrorTest extends QuorumPeerTestBase {\n    private static final String NODE_PATH = \"/noLeaderIssue\";\n\n    /**\n     * Test case for https://issues.apache.org/jira/browse/ZOOKEEPER-2247.\n     * Test to verify that even after non recoverable error (error while\n     * writing transaction log), ZooKeeper is still available.\n     */\n    @Test(timeout = 30000)\n    public void testZooKeeperServiceAvailableOnLeader() throws Exception {\n        int SERVER_COUNT = 3;\n        final int clientPorts[] = new int[SERVER_COUNT];\n        StringBuilder sb = new StringBuilder();\n        String server;\n\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            clientPorts[i] = PortAssignment.unique();\n            server = \"server.\" + i + \"=127.0.0.1:\" + PortAssignment.unique()\n                    + \":\" + PortAssignment.unique();\n            sb.append(server + \"\\n\");\n        }\n        String currentQuorumCfgSection = sb.toString();\n        MainThread mt[] = new MainThread[SERVER_COUNT];\n\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            mt[i] = new MainThread(i, clientPorts[i], currentQuorumCfgSection);\n            mt[i].start();\n        }\n\n        // ensure server started\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            Assert.assertTrue(\"waiting for server \" + i + \" being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + clientPorts[i],\n                            CONNECTION_TIMEOUT));\n        }\n\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(\"127.0.0.1:\" + clientPorts[0],\n                ClientBase.CONNECTION_TIMEOUT, watcher);\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n\n        String data = \"originalData\";\n        zk.create(NODE_PATH, data.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        // get information of current leader\n        QuorumPeer leader = getLeaderQuorumPeer(mt);\n        assertNotNull(\"Leader must have been elected by now\", leader);\n\n        // inject problem in leader\n        FileTxnSnapLog snapLog = leader.getActiveServer().getTxnLogFactory();\n        FileTxnSnapLog fileTxnSnapLogWithError = new FileTxnSnapLog(\n                snapLog.getDataDir(), snapLog.getSnapDir()) {\n            @Override\n            public void commit() throws IOException {\n                throw new IOException(\"Input/output error\");\n            }\n        };\n        ZKDatabase originalZKDatabase = leader.getActiveServer()\n                .getZKDatabase();\n        long leaderCurrentEpoch = leader.getCurrentEpoch();\n\n        ZKDatabase newDB = new ZKDatabase(fileTxnSnapLogWithError);\n        leader.getActiveServer().setZKDatabase(newDB);\n\n        try {\n            // do create operation, so that injected IOException is thrown\n            zk.create(uniqueZnode(), data.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n            fail(\"IOException is expected due to error injected to transaction log commit\");\n        } catch (Exception e) {\n            // do nothing\n        }\n\n        // resetting watcher so that this watcher can be again used to ensure\n        // that the zkClient is able to re-establish connection with the\n        // newly elected zookeeper quorum.\n        watcher.reset();\n        waitForNewLeaderElection(leader, leaderCurrentEpoch);\n\n        // ensure server started, give enough time, so that new leader election\n        // takes place\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            Assert.assertTrue(\"waiting for server \" + i + \" being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + clientPorts[i],\n                            CONNECTION_TIMEOUT));\n        }\n\n        // revert back the error\n        leader.getActiveServer().setZKDatabase(originalZKDatabase);\n\n        // verify that now ZooKeeper service is up and running\n        leader = getLeaderQuorumPeer(mt);\n        assertNotNull(\"New leader must have been elected by now\", leader);\n\n        String uniqueNode = uniqueZnode();\n        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);\n        String createNode = zk.create(uniqueNode, data.getBytes(),\n                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        // if node is created successfully then it means that ZooKeeper service\n        // is available\n        assertEquals(\"Failed to create znode\", uniqueNode, createNode);\n        zk.close();\n        // stop all severs\n        for (int i = 0; i < SERVER_COUNT; i++) {\n            mt[i].shutdown();\n        }\n    }\n\n    private void waitForNewLeaderElection(QuorumPeer peer,\n            long leaderCurrentEpoch) throws IOException, InterruptedException {\n        LOG.info(\"Waiting for new LE cycle..\");\n        int count = 100; // giving a grace period of 10seconds\n        while (count > 0) {\n            if (leaderCurrentEpoch == peer.getCurrentEpoch()) {\n                Thread.sleep(100);\n            }\n            count--;\n        }\n        Assert.assertTrue(\"New LE cycle must have triggered\",\n                leaderCurrentEpoch != peer.getCurrentEpoch());\n    }\n\n    private QuorumPeer getLeaderQuorumPeer(MainThread[] mt) {\n        for (int i = mt.length - 1; i >= 0; i--) {\n            QuorumPeer quorumPeer = mt[i].getQuorumPeer();\n            if (null != quorumPeer\n                    && ServerState.LEADING == quorumPeer.getPeerState()) {\n                return quorumPeer;\n            }\n        }\n        return null;\n    }\n\n    private String uniqueZnode() {\n        UUID randomUUID = UUID.randomUUID();\n        String node = NODE_PATH + \"/\" + randomUUID.toString();\n        return node;\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/NullDataTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class NullDataTest extends ClientBase implements StatCallback {\n    String snapCount;\n    CountDownLatch cn = new CountDownLatch(1);\n    \n    @Override\n    public void setUp() throws Exception {\n        // Change the snapcount to happen more often\n        snapCount = System.getProperty(\"zookeeper.snapCount\", \"1024\");\n        System.setProperty(\"zookeeper.snapCount\", \"10\");\n        super.setUp();\n    }\n    \n    @Override\n    public void tearDown() throws Exception {\n        System.setProperty(\"zookeeper.snapCount\", snapCount);\n        super.tearDown();\n    }\n    \n    @Test\n    public void testNullData() throws IOException, \n        InterruptedException, KeeperException {\n        String path = \"/SIZE\";\n        ZooKeeper zk = null;\n        zk = createClient();\n        try {\n            zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            // try sync zk exists \n            zk.exists(path, false);\n            zk.exists(path, false, this , null);\n            cn.await(10, TimeUnit.SECONDS);\n            Assert.assertSame(0L, cn.getCount());\n        } finally {\n            if(zk != null)\n                zk.close();\n        }\n        \n    }\n\n    public void processResult(int rc, String path, Object ctx, Stat stat) {\n        cn.countDown();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/OOMTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class OOMTest extends ZKTestCase implements Watcher {\n    @Test\n    public void testOOM() throws IOException, InterruptedException, KeeperException {\n        // This test takes too long tos run!\n        if (true)\n            return;\n        File tmpDir = ClientBase.createTmpDir();\n        // Grab some memory so that it is easier to cause an\n        // OOM condition;\n        ArrayList<byte[]> hog = new ArrayList<byte[]>();\n        while (true) {\n            try {\n                hog.add(new byte[1024 * 1024 * 2]);\n            } catch (OutOfMemoryError e) {\n                hog.remove(0);\n                break;\n            }\n        }\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n\n        final int PORT = PortAssignment.unique();\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        Assert.assertTrue(\"waiting for server up\",\n                   ClientBase.waitForServerUp(\"127.0.0.1:\" + PORT,\n                                              CONNECTION_TIMEOUT));\n\n        System.err.println(\"OOM Stage 0\");\n        utestPrep(PORT);\n        System.out.println(\"Free = \" + Runtime.getRuntime().freeMemory()\n                + \" total = \" + Runtime.getRuntime().totalMemory() + \" max = \"\n                + Runtime.getRuntime().maxMemory());\n        System.err.println(\"OOM Stage 1\");\n        for (int i = 0; i < 1000; i++) {\n            System.out.println(i);\n            utestExists(PORT);\n        }\n        System.out.println(\"Free = \" + Runtime.getRuntime().freeMemory()\n                + \" total = \" + Runtime.getRuntime().totalMemory() + \" max = \"\n                + Runtime.getRuntime().maxMemory());\n        System.err.println(\"OOM Stage 2\");\n        for (int i = 0; i < 1000; i++) {\n            System.out.println(i);\n            utestGet(PORT);\n        }\n        System.out.println(\"Free = \" + Runtime.getRuntime().freeMemory()\n                + \" total = \" + Runtime.getRuntime().totalMemory() + \" max = \"\n                + Runtime.getRuntime().maxMemory());\n        System.err.println(\"OOM Stage 3\");\n        for (int i = 0; i < 1000; i++) {\n            System.out.println(i);\n            utestChildren(PORT);\n        }\n        System.out.println(\"Free = \" + Runtime.getRuntime().freeMemory()\n                + \" total = \" + Runtime.getRuntime().totalMemory() + \" max = \"\n                + Runtime.getRuntime().maxMemory());\n        hog.get(0)[0] = (byte) 1;\n\n        f.shutdown();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(\"127.0.0.1:\" + PORT,\n                                                CONNECTION_TIMEOUT));\n    }\n\n    private void utestExists(int port)\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk =\n            new ZooKeeper(\"127.0.0.1:\" + port, CONNECTION_TIMEOUT, this);\n        for (int i = 0; i < 10000; i++) {\n            zk.exists(\"/this/path/doesnt_exist!\", true);\n        }\n        zk.close();\n    }\n\n    private void utestPrep(int port)\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk =\n            new ZooKeeper(\"127.0.0.1:\" + port, CONNECTION_TIMEOUT, this);\n        for (int i = 0; i < 10000; i++) {\n            zk.create(\"/\" + i, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n    }\n\n    private void utestGet(int port)\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk =\n            new ZooKeeper(\"127.0.0.1:\" + port, CONNECTION_TIMEOUT, this);\n        for (int i = 0; i < 10000; i++) {\n            Stat stat = new Stat();\n            zk.getData(\"/\" + i, true, stat);\n        }\n        zk.close();\n    }\n\n    private void utestChildren(int port)\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk =\n            new ZooKeeper(\"127.0.0.1:\" + port, CONNECTION_TIMEOUT, this);\n        for (int i = 0; i < 10000; i++) {\n            zk.getChildren(\"/\" + i, true);\n        }\n        zk.close();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.proto.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        System.err.println(\"Got event \" + event.getType() + \" \"\n                + event.getState() + \" \" + event.getPath());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/OSMXBeanTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.Before;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.apache.zookeeper.server.util.OSMXBean;\n\npublic class OSMXBeanTest {\n    \n    private OSMXBean osMbean;\n    private Long ofdc = 0L;\n    private Long mfdc = 0L;\n    protected static final Logger LOG = LoggerFactory.getLogger(OSMXBeanTest.class);\n\n    @Before\n    public void initialize() {\n        this.osMbean = new OSMXBean();\n        Assert.assertNotNull(\"Could not initialize OSMXBean object!\", osMbean);\n    }\n    \n    @Test\n    public final void testGetUnix() {\n        boolean isUnix = osMbean.getUnix();\n        if (!isUnix) {\n        \tLOG.info(\"Running in a Windows system! Output won't be printed!\");\n        } else {\n        \tLOG.info(\"Running in a Unix or Linux system!\");\n        }\n    }\n\n    @Test\n    public final void testGetOpenFileDescriptorCount() {\n        if (osMbean != null && osMbean.getUnix() == true) {\n            ofdc = osMbean.getOpenFileDescriptorCount();\n            LOG.info(\"open fdcount is: \" + ofdc);\n        }   \n        Assert.assertFalse(\"The number of open file descriptor is negative\",(ofdc < 0));\n    }\n\n    @Test\n    public final void testGetMaxFileDescriptorCount() {\n        if (osMbean != null && osMbean.getUnix() == true) {\n            mfdc = osMbean.getMaxFileDescriptorCount();\n            LOG.info(\"max fdcount is: \" + mfdc);\n        }\n        Assert.assertFalse(\"The max file descriptor number is negative\",(mfdc < 0));\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ObserverHierarchicalQuorumTest.java",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.junit.Test;\n\npublic class ObserverHierarchicalQuorumTest extends HierarchicalQuorumTest {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumBase.class);\n       \n    /**\n     * startServers(true) puts two observers into a 5 peer ensemble\n     */\n    void startServers() throws Exception {\n        startServers(true);\n    }\n           \n    protected void shutdown(QuorumPeer qp) {\n        QuorumBase.shutdown(qp);\n    }\n\n    @Test\n    public void testHierarchicalQuorum() throws Throwable {\n        cht.runHammer(5, 10);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ObserverLETest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.*;\n\nimport java.util.Arrays;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumStats;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ObserverLETest extends ZKTestCase {\n    final QuorumBase qb = new QuorumBase();\n    final ClientTest ct = new ClientTest();\n\n    @Before\n    public void establishThreeParticipantOneObserverEnsemble() throws Exception {\n        qb.setUp(true);\n        ct.hostPort = qb.hostPort;\n        ct.setUpAll();\n        qb.s5.shutdown();\n    }\n\n    @After\n    public void shutdownQuorum() throws Exception {\n        ct.tearDownAll();\n        qb.tearDown();\n    }\n\n    /**\n     * See ZOOKEEPER-1294. Confirms that an observer will not support the quorum\n     * of a leader by forming a 5-node, 2-observer ensemble (so quorum size is 2).\n     * When all but the leader and one observer are shut down, the leader should\n     * enter the 'looking' state, not stay in the 'leading' state.\n     */\n    @Test\n    public void testLEWithObserver() throws Exception {\n        QuorumPeer leader = null;\n        for (QuorumPeer server : Arrays.asList(qb.s1, qb.s2, qb.s3)) {\n            if (server.getServerState().equals(\n                    QuorumStats.Provider.FOLLOWING_STATE)) {\n                server.shutdown();\n                assertTrue(\"Waiting for server down\", ClientBase\n                        .waitForServerDown(\"127.0.0.1:\"\n                                + server.getClientPort(),\n                                ClientBase.CONNECTION_TIMEOUT));\n            } else {\n                assertNull(\"More than one leader found\", leader);\n                leader = server;\n            }\n        }\n        assertTrue(\"Leader is not in Looking state\", ClientBase\n                .waitForServerState(leader, ClientBase.CONNECTION_TIMEOUT,\n                        QuorumStats.Provider.LOOKING_STATE));\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ObserverQuorumHammerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ObserverQuorumHammerTest extends QuorumHammerTest {\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    \n    @Before\n    @Override\n    public void setUp() throws Exception {\n        qb.setUp(true);\n        cht.hostPort = qb.hostPort;\n        cht.setUpAll();\n    }\n   \n    @Test\n    public void testHammerBasic() throws Throwable {\n        cht.testHammerBasic();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ObserverTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ObserverTest extends QuorumPeerTestBase implements Watcher{\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(ObserverTest.class);    \n      \n    CountDownLatch latch;\n    ZooKeeper zk;\n    WatchedEvent lastEvent = null;\n          \n    /**\n     * This test ensures two things:\n     * 1. That Observers can successfully proxy requests to the ensemble.\n     * 2. That Observers don't participate in leader elections.\n     * The second is tested by constructing an ensemble where a leader would\n     * be elected if and only if an Observer voted. \n     * @throws Exception\n     */\n    @Test\n    public void testObserver() throws Exception {\n        ClientBase.setupTestEnv();\n        // We expect two notifications before we want to continue        \n        latch = new CountDownLatch(2);\n        \n        final int PORT_QP1 = PortAssignment.unique();\n        final int PORT_QP2 = PortAssignment.unique();\n        final int PORT_OBS = PortAssignment.unique();\n        final int PORT_QP_LE1 = PortAssignment.unique();\n        final int PORT_QP_LE2 = PortAssignment.unique();\n        final int PORT_OBS_LE = PortAssignment.unique();\n\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();\n        final int CLIENT_PORT_QP2 = PortAssignment.unique();\n        final int CLIENT_PORT_OBS = PortAssignment.unique();\n\n        \n        String quorumCfgSection =\n            \"electionAlg=3\\n\" + \n            \"server.1=127.0.0.1:\" + (PORT_QP1)\n            + \":\" + (PORT_QP_LE1)\n            + \"\\nserver.2=127.0.0.1:\" + (PORT_QP2)\n            + \":\" + (PORT_QP_LE2)\n            + \"\\nserver.3=127.0.0.1:\" \n            + (PORT_OBS)+ \":\" + (PORT_OBS_LE) + \":observer\";\n        String obsCfgSection =  quorumCfgSection + \"\\npeerType=observer\";\n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        MainThread q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n        MainThread q3 = new MainThread(3, CLIENT_PORT_OBS, obsCfgSection);\n        q1.start();\n        q2.start();\n        q3.start();\n        Assert.assertTrue(\"waiting for server 1 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                        CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"waiting for server 2 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                        CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"waiting for server 3 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_OBS,\n                        CONNECTION_TIMEOUT));        \n        \n        zk = new ZooKeeper(\"127.0.0.1:\" + CLIENT_PORT_OBS,\n                ClientBase.CONNECTION_TIMEOUT, this);\n        zk.create(\"/obstest\", \"test\".getBytes(),Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        \n        // Assert that commands are getting forwarded correctly\n        Assert.assertEquals(new String(zk.getData(\"/obstest\", null, null)), \"test\");\n        \n        // Now check that other commands don't blow everything up\n        zk.sync(\"/\", null, null);\n        zk.setData(\"/obstest\", \"test2\".getBytes(), -1);\n        zk.getChildren(\"/\", false);\n        \n        Assert.assertEquals(zk.getState(), States.CONNECTED);\n        \n        LOG.info(\"Shutting down server 2\");\n        // Now kill one of the other real servers        \n        q2.shutdown();\n                \n        Assert.assertTrue(\"Waiting for server 2 to shut down\",\n                    ClientBase.waitForServerDown(\"127.0.0.1:\"+CLIENT_PORT_QP2, \n                                    ClientBase.CONNECTION_TIMEOUT));\n\n        LOG.info(\"Server 2 down\");\n\n        // Now the resulting ensemble shouldn't be quorate         \n        latch.await();        \n        Assert.assertNotSame(\"Client is still connected to non-quorate cluster\", \n                KeeperState.SyncConnected,lastEvent.getState());\n\n        LOG.info(\"Latch returned\");\n\n        try {\n            Assert.assertFalse(\"Shouldn't get a response when cluster not quorate!\",\n                    new String(zk.getData(\"/obstest\", null, null)).equals(\"test\"));\n        }\n        catch (ConnectionLossException c) {\n            LOG.info(\"Connection loss exception caught - ensemble not quorate (this is expected)\");\n        }\n        \n        latch = new CountDownLatch(1);\n\n        LOG.info(\"Restarting server 2\");\n\n        // Bring it back\n        q2 = new MainThread(2, CLIENT_PORT_QP2, quorumCfgSection);\n        q2.start();\n        \n        LOG.info(\"Waiting for server 2 to come up\");\n        Assert.assertTrue(\"waiting for server 2 being up\",\n                ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP2,\n                        CONNECTION_TIMEOUT));\n        \n        LOG.info(\"Server 2 started, waiting for latch\");\n\n        latch.await();\n        // It's possible our session expired - but this is ok, shows we \n        // were able to talk to the ensemble\n        Assert.assertTrue(\"Client didn't reconnect to quorate ensemble (state was\" +\n                lastEvent.getState() + \")\",\n                (KeeperState.SyncConnected==lastEvent.getState() ||\n                KeeperState.Expired==lastEvent.getState())); \n\n        LOG.info(\"Shutting down all servers\");\n\n        q1.shutdown();\n        q2.shutdown();\n        q3.shutdown();\n        \n        LOG.info(\"Closing zk client\");\n\n        zk.close();        \n        Assert.assertTrue(\"Waiting for server 1 to shut down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\"+CLIENT_PORT_QP1, \n                                ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"Waiting for server 2 to shut down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\"+CLIENT_PORT_QP2, \n                                ClientBase.CONNECTION_TIMEOUT));\n        Assert.assertTrue(\"Waiting for server 3 to shut down\",\n                ClientBase.waitForServerDown(\"127.0.0.1:\"+CLIENT_PORT_OBS, \n                                ClientBase.CONNECTION_TIMEOUT));\n    \n    }\n    \n    /**\n     * Implementation of watcher interface.\n     */\n    public void process(WatchedEvent event) {\n        lastEvent = event;\n        latch.countDown();\n        LOG.info(\"Latch got event :: \" + event);        \n    }    \n    \n    /**\n     * This test ensures that an Observer does not elect itself as a leader, or\n     * indeed come up properly, if it is the lone member of an ensemble.\n     * @throws Exception\n     */\n    @Test\n    public void testObserverOnly() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();        \n        \n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + (PortAssignment.unique())\n            + \":\" + (PortAssignment.unique()) + \":observer\\npeerType=observer\\n\";\n                    \n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        q1.start();\n        q1.join(ClientBase.CONNECTION_TIMEOUT);\n        Assert.assertFalse(q1.isAlive());\n    }    \n    \n    /**\n     * Ensure that observer only comes up when a proper ensemble is configured.\n     * (and will not come up with standalone server).\n     */\n    @Test\n    public void testObserverWithStandlone() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();        \n\n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + (PortAssignment.unique())\n            + \":\" + (PortAssignment.unique()) + \":observer\\n\"\n            + \"server.2=127.0.0.1:\" + (PortAssignment.unique())\n            + \":\" + (PortAssignment.unique()) + \"\\npeerType=observer\\n\";\n\n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        q1.start();\n        q1.join(ClientBase.CONNECTION_TIMEOUT);\n        Assert.assertFalse(q1.isAlive());\n    }    \n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumBase.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.server.quorum.Election;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.util.OSMXBean;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n\npublic class QuorumBase extends ClientBase {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumBase.class);\n\n    File s1dir, s2dir, s3dir, s4dir, s5dir;\n    QuorumPeer s1, s2, s3, s4, s5;\n    protected int port1;\n    protected int port2;\n    protected int port3;\n    protected int port4;\n    protected int port5;\n    \n    protected int portLE1;\n    protected int portLE2;\n    protected int portLE3;\n    protected int portLE4;\n    protected int portLE5;\n\n    @Test\n    // This just avoids complaints by junit\n    public void testNull() {\n    }\n    \n    @Override\n    public void setUp() throws Exception {\n        setUp(false);\n    }\n        \n    protected void setUp(boolean withObservers) throws Exception {\n        LOG.info(\"QuorumBase.setup \" + getTestName());\n        setupTestEnv();\n\n        JMXEnv.setUp();\n\n        setUpAll();\n\n        port1 = PortAssignment.unique();\n        port2 = PortAssignment.unique();\n        port3 = PortAssignment.unique();\n        port4 = PortAssignment.unique();\n        port5 = PortAssignment.unique();\n        \n        portLE1 = PortAssignment.unique();\n        portLE2 = PortAssignment.unique();\n        portLE3 = PortAssignment.unique();\n        portLE4 = PortAssignment.unique();\n        portLE5 = PortAssignment.unique();\n        \n        hostPort = \"127.0.0.1:\" + port1\n            + \",127.0.0.1:\" + port2\n            + \",127.0.0.1:\" + port3\n            + \",127.0.0.1:\" + port4\n            + \",127.0.0.1:\" + port5;\n        LOG.info(\"Ports are: \" + hostPort);\n\n        s1dir = ClientBase.createTmpDir();\n        s2dir = ClientBase.createTmpDir();\n        s3dir = ClientBase.createTmpDir();\n        s4dir = ClientBase.createTmpDir();\n        s5dir = ClientBase.createTmpDir();\n\n        startServers(withObservers);\n\n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == true) {\n            LOG.info(\"Initial fdcount is: \"\n                    + osMbean.getOpenFileDescriptorCount());\n        }\n\n        LOG.info(\"Setup finished\");\n    }\n    \n    void startServers() throws Exception {\n        startServers(false);        \n    }\n    \n    void startServers(boolean withObservers) throws Exception {\n        int tickTime = 2000;\n        int initLimit = 3;\n        int syncLimit = 3;\n        HashMap<Long,QuorumServer> peers = new HashMap<Long,QuorumServer>();\n        peers.put(Long.valueOf(1), new QuorumServer(1, \"127.0.0.1\", port1 + 1000,\n                                                    portLE1 + 1000,\n                LearnerType.PARTICIPANT));\n        peers.put(Long.valueOf(2), new QuorumServer(2, \"127.0.0.1\", port2 + 1000,\n                                                    portLE2 + 1000,\n                LearnerType.PARTICIPANT));\n        peers.put(Long.valueOf(3), new QuorumServer(3, \"127.0.0.1\", port3 + 1000,\n                                                    portLE3 + 1000,\n                LearnerType.PARTICIPANT));\n        peers.put(Long.valueOf(4), new QuorumServer(4, \"127.0.0.1\", port4 + 1000,\n                                                    portLE4 + 1000,\n                LearnerType.PARTICIPANT));\n        peers.put(Long.valueOf(5), new QuorumServer(5, \"127.0.0.1\", port5 + 1000,\n                                                    portLE5 + 1000,\n                LearnerType.PARTICIPANT));\n        \n        if (withObservers) {\n            peers.get(Long.valueOf(4)).type = LearnerType.OBSERVER;        \n            peers.get(Long.valueOf(5)).type = LearnerType.OBSERVER;\n        }\n\n        LOG.info(\"creating QuorumPeer 1 port \" + port1);\n        s1 = new QuorumPeer(peers, s1dir, s1dir, port1, 3, 1, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(port1, s1.getClientPort());\n        LOG.info(\"creating QuorumPeer 2 port \" + port2);\n        s2 = new QuorumPeer(peers, s2dir, s2dir, port2, 3, 2, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(port2, s2.getClientPort());\n        LOG.info(\"creating QuorumPeer 3 port \" + port3);\n        s3 = new QuorumPeer(peers, s3dir, s3dir, port3, 3, 3, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(port3, s3.getClientPort());\n        LOG.info(\"creating QuorumPeer 4 port \" + port4);\n        s4 = new QuorumPeer(peers, s4dir, s4dir, port4, 3, 4, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(port4, s4.getClientPort());\n        LOG.info(\"creating QuorumPeer 5 port \" + port5);\n        s5 = new QuorumPeer(peers, s5dir, s5dir, port5, 3, 5, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(port5, s5.getClientPort());\n        \n        if (withObservers) {\n            s4.setLearnerType(LearnerType.OBSERVER);\n            s5.setLearnerType(LearnerType.OBSERVER);\n        }\n        \n        LOG.info(\"QuorumPeer 1 voting view: \" + s1.getVotingView());\n        LOG.info(\"QuorumPeer 2 voting view: \" + s2.getVotingView());\n        LOG.info(\"QuorumPeer 3 voting view: \" + s3.getVotingView());\n        LOG.info(\"QuorumPeer 4 voting view: \" + s4.getVotingView());\n        LOG.info(\"QuorumPeer 5 voting view: \" + s5.getVotingView());       \n        \n        LOG.info(\"start QuorumPeer 1\");\n        s1.start();\n        LOG.info(\"start QuorumPeer 2\");\n        s2.start();\n        LOG.info(\"start QuorumPeer 3\");\n        s3.start();\n        LOG.info(\"start QuorumPeer 4\");\n        s4.start();\n        LOG.info(\"start QuorumPeer 5\");\n        s5.start();\n        LOG.info(\"started QuorumPeer 5\");\n\n        LOG.info (\"Checking ports \" + hostPort);\n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(hp,\n                                    CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is accepting client connections\");\n        }\n\n        // interesting to see what's there...\n        JMXEnv.dump();\n        // make sure we have these 5 servers listed\n        Set<String> ensureNames = new LinkedHashSet<String>();\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"InMemoryDataTree\");\n        }\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"name0=ReplicatedServer_id\" + i\n                 + \",name1=replica.\" + i + \",name2=\");\n        }\n        for (int i = 1; i <= 5; i++) {\n            for (int j = 1; j <= 5; j++) {\n                ensureNames.add(\"name0=ReplicatedServer_id\" + i\n                     + \",name1=replica.\" + j);\n            }\n        }\n        for (int i = 1; i <= 5; i++) {\n            ensureNames.add(\"name0=ReplicatedServer_id\" + i);\n        }\n        JMXEnv.ensureAll(ensureNames.toArray(new String[ensureNames.size()]));\n    }\n    \n    \n    public void setupServers() throws IOException {        \n        setupServer(1);\n        setupServer(2);\n        setupServer(3);\n        setupServer(4);\n        setupServer(5);\n    }\n\n    HashMap<Long,QuorumServer> peers = null;\n    public void setupServer(int i) throws IOException {\n        int tickTime = 2000;\n        int initLimit = 3;\n        int syncLimit = 3;\n        \n        if(peers == null){\n            peers = new HashMap<Long,QuorumServer>();\n\n            peers.put(Long.valueOf(1), new QuorumServer(1, \"127.0.0.1\", port1 + 1000,\n                                                        portLE1 + 1000,\n                LearnerType.PARTICIPANT));\n            peers.put(Long.valueOf(2), new QuorumServer(2, \"127.0.0.1\", port2 + 1000,\n                                                        portLE2 + 1000,\n                LearnerType.PARTICIPANT));\n            peers.put(Long.valueOf(3), new QuorumServer(3, \"127.0.0.1\", port3 + 1000,\n                                                        portLE3 + 1000,\n                LearnerType.PARTICIPANT));\n            peers.put(Long.valueOf(4), new QuorumServer(4, \"127.0.0.1\", port4 + 1000,\n                                                        portLE4 + 1000,\n                LearnerType.PARTICIPANT));\n            peers.put(Long.valueOf(5), new QuorumServer(5, \"127.0.0.1\", port5 + 1000,\n                                                        portLE5 + 1000,\n                LearnerType.PARTICIPANT));\n        }\n        \n        switch(i){\n        case 1:\n            LOG.info(\"creating QuorumPeer 1 port \" + port1);\n            s1 = new QuorumPeer(peers, s1dir, s1dir, port1, 3, 1, tickTime, initLimit, syncLimit);\n            Assert.assertEquals(port1, s1.getClientPort());\n            break;\n        case 2:\n            LOG.info(\"creating QuorumPeer 2 port \" + port2);\n            s2 = new QuorumPeer(peers, s2dir, s2dir, port2, 3, 2, tickTime, initLimit, syncLimit);\n            Assert.assertEquals(port2, s2.getClientPort());\n            break;\n        case 3:  \n            LOG.info(\"creating QuorumPeer 3 port \" + port3);\n            s3 = new QuorumPeer(peers, s3dir, s3dir, port3, 3, 3, tickTime, initLimit, syncLimit);\n            Assert.assertEquals(port3, s3.getClientPort());\n            break;\n        case 4:\n            LOG.info(\"creating QuorumPeer 4 port \" + port4);\n            s4 = new QuorumPeer(peers, s4dir, s4dir, port4, 3, 4, tickTime, initLimit, syncLimit);\n            Assert.assertEquals(port4, s4.getClientPort());\n            break;\n        case 5:\n            LOG.info(\"creating QuorumPeer 5 port \" + port5);\n            s5 = new QuorumPeer(peers, s5dir, s5dir, port5, 3, 5, tickTime, initLimit, syncLimit);\n            Assert.assertEquals(port5, s5.getClientPort());\n        }\n    }\n    \n    @Override\n    public void tearDown() throws Exception {\n        LOG.info(\"TearDown started\");\n        \n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == true) {\n            LOG.info(\"fdcount after test is: \"\n                    + osMbean.getOpenFileDescriptorCount());\n        }\n\n        shutdownServers();\n\n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(hp,\n                                           ClientBase.CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is no longer accepting client connections\");\n        }\n\n        JMXEnv.tearDown();\n    }\n    public void shutdownServers() {\n        shutdown(s1);\n        shutdown(s2);\n        shutdown(s3);\n        shutdown(s4);\n        shutdown(s5);\n    }\n\n    public static void shutdown(QuorumPeer qp) {\n        try {\n            LOG.info(\"Shutting down quorum peer \" + qp.getName());\n            qp.shutdown();\n            Election e = qp.getElectionAlg();\n            if (e != null) {\n                LOG.info(\"Shutting down leader election \" + qp.getName());\n                e.shutdown();\n            } else {\n                LOG.info(\"No election available to shutdown \" + qp.getName());\n            }\n            LOG.info(\"Waiting for \" + qp.getName() + \" to exit thread\");\n            long readTimeout = qp.getTickTime() * qp.getInitLimit();\n            long connectTimeout = qp.getTickTime() * qp.getSyncLimit();\n            long maxTimeout = Math.max(readTimeout, connectTimeout);\n            maxTimeout = Math.max(maxTimeout, ClientBase.CONNECTION_TIMEOUT);\n            qp.join(maxTimeout * 2);\n            if (qp.isAlive()) {\n                Assert.fail(\"QP failed to shutdown in \" + (maxTimeout * 2) + \" seconds: \" + qp.getName());\n            }\n        } catch (InterruptedException e) {\n            LOG.debug(\"QP interrupted: \" + qp.getName(), e);\n        }\n    }\n\n    protected TestableZooKeeper createClient()\n        throws IOException, InterruptedException\n    {\n        return createClient(hostPort);\n    }\n\n    protected TestableZooKeeper createClient(String hp)\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createClient(watcher, hp);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumHammerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class QuorumHammerTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(QuorumHammerTest.class);\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    protected final QuorumBase qb = new QuorumBase();\n    protected final ClientHammerTest cht = new ClientHammerTest();\n\n    @Before\n    public void setUp() throws Exception {\n        qb.setUp();\n        cht.hostPort = qb.hostPort;\n        cht.setUpAll();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        cht.tearDownAll();\n        qb.tearDown();\n    }\n\n    @Test\n    public void testHammerBasic() throws Throwable {\n        cht.testHammerBasic();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumQuotaTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.Quotas;\nimport org.apache.zookeeper.StatsTrack;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooKeeperMain;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class QuorumQuotaTest extends QuorumBase {\n    private static final Logger LOG =\n        LoggerFactory.getLogger(QuorumQuotaTest.class);\n\n    @Test\n    public void testQuotaWithQuorum() throws Exception {\n        ZooKeeper zk = createClient();\n        zk.setData(\"/\", \"some\".getBytes(), -1);\n        zk.create(\"/a\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        int i = 0;\n        for (i=0; i < 300;i++) {\n            zk.create(\"/a/\" + i, \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n        ZooKeeperMain.createQuota(zk, \"/a\", 1000L, 5000);\n        String statPath = Quotas.quotaZookeeper + \"/a\"+ \"/\" + Quotas.statNode;\n        byte[] data = zk.getData(statPath, false, new Stat());\n        StatsTrack st = new StatsTrack(new String(data));\n        Assert.assertTrue(\"bytes are set\", st.getBytes() == 1204L);\n        Assert.assertTrue(\"num count is set\", st.getCount() == 301);\n        for (i=300; i < 600; i++) {\n            zk.create(\"/a/\" + i, \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n        }\n        data = zk.getData(statPath, false, new Stat());\n        st = new StatsTrack(new String(data));\n        Assert.assertTrue(\"bytes are set\", st.getBytes() == 2404L);\n        Assert.assertTrue(\"num count is set\", st.getCount() == 601);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Op;\nimport org.apache.zookeeper.OpResult;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.quorum.Leader;\nimport org.apache.zookeeper.server.quorum.LearnerHandler;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class QuorumTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumTest.class);\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    private final QuorumBase qb = new QuorumBase();\n    private final ClientTest ct = new ClientTest();\n\n    @Before\n    public void setUp() throws Exception {\n        qb.setUp();\n        ct.hostPort = qb.hostPort;\n        ct.setUpAll();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        ct.tearDownAll();\n        qb.tearDown();\n    }\n\n    @Test\n    public void testDeleteWithChildren() throws Exception {\n        ct.testDeleteWithChildren();\n    }\n\n    @Test\n    public void testPing() throws Exception {\n        ct.testPing();\n    }\n\n    @Test\n    public void testSequentialNodeNames()\n        throws IOException, InterruptedException, KeeperException\n    {\n        ct.testSequentialNodeNames();\n    }\n\n    @Test\n    public void testACLs() throws Exception {\n        ct.testACLs();\n    }\n\n    @Test\n    public void testClientwithoutWatcherObj() throws IOException,\n            InterruptedException, KeeperException\n    {\n        ct.testClientwithoutWatcherObj();\n    }\n\n    @Test\n    public void testClientWithWatcherObj() throws IOException,\n            InterruptedException, KeeperException\n    {\n        ct.testClientWithWatcherObj();\n    }\n\n    @Test\n    public void testGetView() {\n        Assert.assertEquals(5,qb.s1.getView().size());\n        Assert.assertEquals(5,qb.s2.getView().size());\n        Assert.assertEquals(5,qb.s3.getView().size());\n        Assert.assertEquals(5,qb.s4.getView().size());\n        Assert.assertEquals(5,qb.s5.getView().size());\n    }\n\n    @Test\n    public void testViewContains() {\n        // Test view contains self\n        Assert.assertTrue(qb.s1.viewContains(qb.s1.getId()));\n\n        // Test view contains other servers\n        Assert.assertTrue(qb.s1.viewContains(qb.s2.getId()));\n\n        // Test view does not contain non-existant servers\n        Assert.assertFalse(qb.s1.viewContains(-1L));\n    }\n\n    volatile int counter = 0;\n    volatile int errors = 0;\n    @Test\n    public void testLeaderShutdown() throws IOException, InterruptedException, KeeperException {\n        ZooKeeper zk = new DisconnectableZooKeeper(qb.hostPort, ClientBase.CONNECTION_TIMEOUT, new Watcher() {\n            public void process(WatchedEvent event) {\n        }});\n        zk.create(\"/blah\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.create(\"/blah/blah\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Leader leader = qb.s1.leader;\n        if (leader == null) leader = qb.s2.leader;\n        if (leader == null) leader = qb.s3.leader;\n        if (leader == null) leader = qb.s4.leader;\n        if (leader == null) leader = qb.s5.leader;\n        Assert.assertNotNull(leader);\n        for(int i = 0; i < 5000; i++) {\n            zk.setData(\"/blah/blah\", new byte[0], -1, new AsyncCallback.StatCallback() {\n                public void processResult(int rc, String path, Object ctx,\n                        Stat stat) {\n                    counter++;\n                    if (rc != 0) {\n                        errors++;\n                    }\n                }\n            }, null);\n        }\n        for(LearnerHandler f : leader.getForwardingFollowers()) {\n            f.getSocket().shutdownInput();\n        }\n        for(int i = 0; i < 5000; i++) {\n            zk.setData(\"/blah/blah\", new byte[0], -1, new AsyncCallback.StatCallback() {\n                public void processResult(int rc, String path, Object ctx,\n                        Stat stat) {\n                    counter++;\n                    if (rc != 0) {\n                        errors++;\n                    }\n                }\n            }, null);\n        }\n        // check if all the followers are alive\n        Assert.assertTrue(qb.s1.isAlive());\n        Assert.assertTrue(qb.s2.isAlive());\n        Assert.assertTrue(qb.s3.isAlive());\n        Assert.assertTrue(qb.s4.isAlive());\n        Assert.assertTrue(qb.s5.isAlive());\n        zk.close();\n    }\n\n    @Test\n    public void testMultipleWatcherObjs() throws IOException,\n            InterruptedException, KeeperException\n    {\n        ct.testMutipleWatcherObjs();\n    }\n\n    /**\n     * Make sure that we can change sessions\n     *  from follower to leader.\n     *\n     * @throws IOException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    @Test\n    public void testSessionMoved() throws Exception {\n        String hostPorts[] = qb.hostPort.split(\",\");\n        DisconnectableZooKeeper zk = new DisconnectableZooKeeper(hostPorts[0],\n                ClientBase.CONNECTION_TIMEOUT, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/sessionMoveTest\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n        // we want to loop through the list twice\n        for(int i = 0; i < hostPorts.length*2; i++) {\n            zk.dontReconnect();\n            // This should stomp the zk handle\n            DisconnectableZooKeeper zknew =\n                new DisconnectableZooKeeper(hostPorts[(i+1)%hostPorts.length],\n                    ClientBase.CONNECTION_TIMEOUT,\n                    new Watcher() {public void process(WatchedEvent event) {\n                    }},\n                    zk.getSessionId(),\n                    zk.getSessionPasswd());\n            zknew.setData(\"/\", new byte[1], -1);\n            final int result[] = new int[1];\n            result[0] = Integer.MAX_VALUE;\n            zknew.sync(\"/\", new AsyncCallback.VoidCallback() {\n                    public void processResult(int rc, String path, Object ctx) {\n                        synchronized(result) { result[0] = rc; result.notify(); }\n                    }\n                }, null);\n            synchronized(result) {\n                if(result[0] == Integer.MAX_VALUE) {\n                    result.wait(5000);\n                }\n            }\n            LOG.info(hostPorts[(i+1)%hostPorts.length] + \" Sync returned \" + result[0]);\n            Assert.assertTrue(result[0] == KeeperException.Code.OK.intValue());\n            try {\n                zk.setData(\"/\", new byte[1], -1);\n                Assert.fail(\"Should have lost the connection\");\n            } catch(KeeperException.ConnectionLossException e) {\n            }\n            zk = zknew;\n        }\n        zk.close();\n    }\n\n    private static class DiscoWatcher implements Watcher {\n        volatile boolean zkDisco = false;\n        public void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.Disconnected) {\n                zkDisco = true;\n            }\n        }\n    }\n\n    /**\n     * Connect to two different servers with two different handles using the same session and\n     * make sure we cannot do any changes.\n     */\n    @Test\n    @Ignore\n    public void testSessionMove() throws Exception {\n        String hps[] = qb.hostPort.split(\",\");\n        DiscoWatcher oldWatcher = new DiscoWatcher();\n        DisconnectableZooKeeper zk = new DisconnectableZooKeeper(hps[0],\n                ClientBase.CONNECTION_TIMEOUT, oldWatcher);\n        zk.create(\"/t1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n        zk.dontReconnect();\n        // This should stomp the zk handle\n        DiscoWatcher watcher = new DiscoWatcher();\n        DisconnectableZooKeeper zknew = new DisconnectableZooKeeper(hps[1],\n                ClientBase.CONNECTION_TIMEOUT, watcher, zk.getSessionId(),\n                zk.getSessionPasswd());\n        zknew.create(\"/t2\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n        try {\n            zk.create(\"/t3\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n            Assert.fail(\"Should have lost the connection\");\n        } catch(KeeperException.ConnectionLossException e) {\n            // wait up to 30 seconds for the disco to be delivered\n            for (int i = 0; i < 30; i++) {\n                if (oldWatcher.zkDisco) {\n                    break;\n                }\n                Thread.sleep(1000);\n            }\n            Assert.assertTrue(oldWatcher.zkDisco);\n        }\n\n        ArrayList<ZooKeeper> toClose = new ArrayList<ZooKeeper>();\n        toClose.add(zknew);\n        // Let's just make sure it can still move\n        for(int i = 0; i < 10; i++) {\n            zknew.dontReconnect();\n            zknew = new DisconnectableZooKeeper(hps[1],\n                    ClientBase.CONNECTION_TIMEOUT, new DiscoWatcher(),\n                    zk.getSessionId(), zk.getSessionPasswd());\n            toClose.add(zknew);\n            zknew.create(\"/t-\"+i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n        }\n        for (ZooKeeper z: toClose) {\n            z.close();\n        }\n        zk.close();\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumUtil.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.server.quorum.Election;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.server.util.OSMXBean;\nimport org.junit.Assert;\n\n/**\n * Utility for quorum testing. Setups 2n+1 peers and allows to start/stop all\n * peers, particular peer, n peers etc.\n */\npublic class QuorumUtil {\n\n    // TODO partitioning of peers and clients\n\n    // TODO refactor QuorumBase to be special case of this\n\n    private static final Logger LOG = LoggerFactory.getLogger(QuorumUtil.class);\n\n    public class PeerStruct {\n        public int id;\n        public QuorumPeer peer;\n        public File dataDir;\n        public int clientPort;\n    }\n\n    private final Map<Long, QuorumServer> peersView = new HashMap<Long, QuorumServer>();\n\n    private final Map<Integer, PeerStruct> peers = new HashMap<Integer, PeerStruct>();\n\n    public final int N;\n\n    public final int ALL;\n\n    private String hostPort;\n\n    private int tickTime;\n\n    private int initLimit;\n\n    private int syncLimit;\n\n    private int electionAlg;\n\n    /**\n     * Initializes 2n+1 quorum peers which will form a ZooKeeper ensemble.\n     *\n     * @param n\n     *            number of peers in the ensemble will be 2n+1\n     */\n    public QuorumUtil(int n, int syncLimit) throws RuntimeException {\n        try {\n            ClientBase.setupTestEnv();\n            JMXEnv.setUp();\n\n            N = n;\n            ALL = 2 * N + 1;\n            tickTime = 2000;\n            initLimit = 3;\n            this.syncLimit = syncLimit;\n            electionAlg = 3;\n            hostPort = \"\";\n\n            for (int i = 1; i <= ALL; ++i) {\n                PeerStruct ps = new PeerStruct();\n                ps.id = i;\n                ps.dataDir = ClientBase.createTmpDir();\n                ps.clientPort = PortAssignment.unique();\n                peers.put(i, ps);\n\n                peersView.put(Long.valueOf(i),\n                              new QuorumServer(i, \"127.0.0.1\", ps.clientPort + 1000,\n                                               PortAssignment.unique() + 1000,\n                                               LearnerType.PARTICIPANT));\n                hostPort += \"127.0.0.1:\" + ps.clientPort + ((i == ALL) ? \"\" : \",\");\n            }\n            for (int i = 1; i <= ALL; ++i) {\n                PeerStruct ps = peers.get(i);\n                LOG.info(\"Creating QuorumPeer \" + i + \"; public port \" + ps.clientPort);\n                ps.peer = new QuorumPeer(peersView, ps.dataDir, ps.dataDir, ps.clientPort,\n                        electionAlg, ps.id, tickTime, initLimit, syncLimit);\n                Assert.assertEquals(ps.clientPort, ps.peer.getClientPort());\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public QuorumUtil(int n) throws RuntimeException {\n        this(n, 3);\n    }\n\n    public PeerStruct getPeer(int id) {\n        return peers.get(id);\n    }\n\n    public void startAll() throws IOException {\n        shutdownAll();\n        for (int i = 1; i <= ALL; ++i) {\n            start(i);\n            LOG.info(\"Started QuorumPeer \" + i);\n        }\n\n        LOG.info(\"Checking ports \" + hostPort);\n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"waiting for server up\", ClientBase.waitForServerUp(hp,\n                    ClientBase.CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is accepting client connections\");\n        }\n\n        // interesting to see what's there...\n        try {\n            JMXEnv.dump();\n            // make sure we have all servers listed\n            Set<String> ensureNames = new LinkedHashSet<String>();\n            for (int i = 1; i <= ALL; ++i) {\n                ensureNames.add(\"InMemoryDataTree\");\n            }\n            for (int i = 1; i <= ALL; ++i) {\n                ensureNames\n                        .add(\"name0=ReplicatedServer_id\" + i + \",name1=replica.\" + i + \",name2=\");\n            }\n            for (int i = 1; i <= ALL; ++i) {\n                for (int j = 1; j <= ALL; ++j) {\n                    ensureNames.add(\"name0=ReplicatedServer_id\" + i + \",name1=replica.\" + j);\n                }\n            }\n            for (int i = 1; i <= ALL; ++i) {\n                ensureNames.add(\"name0=ReplicatedServer_id\" + i);\n            }\n            JMXEnv.ensureAll(ensureNames.toArray(new String[ensureNames.size()]));\n        } catch (IOException e) {\n            LOG.warn(\"IOException during JMXEnv operation\", e);\n        } catch (InterruptedException e) {\n            LOG.warn(\"InterruptedException during JMXEnv operation\", e);\n        }\n    }\n\n    /**\n     * Start first N+1 peers.\n     */\n    public void startQuorum() throws IOException {\n        shutdownAll();\n        for (int i = 1; i <= N + 1; ++i) {\n            start(i);\n        }\n        for (int i = 1; i <= N + 1; ++i) {\n            Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                    + getPeer(i).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        }\n    }\n\n    public void start(int id) throws IOException {\n        PeerStruct ps = getPeer(id);\n        LOG.info(\"Creating QuorumPeer \" + ps.id + \"; public port \" + ps.clientPort);\n        ps.peer = new QuorumPeer(peersView, ps.dataDir, ps.dataDir, ps.clientPort, electionAlg,\n                ps.id, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(ps.clientPort, ps.peer.getClientPort());\n\n        ps.peer.start();    \n    }\n    \n    public void restart(int id) throws IOException {\n        start(id);\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + getPeer(id).clientPort, ClientBase.CONNECTION_TIMEOUT));\n    }\n    \n    public void startThenShutdown(int id) throws IOException {\n        PeerStruct ps = getPeer(id);\n        LOG.info(\"Creating QuorumPeer \" + ps.id + \"; public port \" + ps.clientPort);\n        ps.peer = new QuorumPeer(peersView, ps.dataDir, ps.dataDir, ps.clientPort, electionAlg,\n                ps.id, tickTime, initLimit, syncLimit);\n        Assert.assertEquals(ps.clientPort, ps.peer.getClientPort());\n\n        ps.peer.start();\n        Assert.assertTrue(\"Waiting for server up\", ClientBase.waitForServerUp(\"127.0.0.1:\"\n                + getPeer(id).clientPort, ClientBase.CONNECTION_TIMEOUT));\n        shutdown(id);\n    }\n\n    public void shutdownAll() {\n        for (int i = 1; i <= ALL; ++i) {\n            shutdown(i);\n        }\n        for (String hp : hostPort.split(\",\")) {\n            Assert.assertTrue(\"Waiting for server down\", ClientBase.waitForServerDown(hp,\n                    ClientBase.CONNECTION_TIMEOUT));\n            LOG.info(hp + \" is no longer accepting client connections\");\n        }\n    }\n\n    public void shutdown(int id) {\n        QuorumPeer qp = getPeer(id).peer;\n        try {\n            LOG.info(\"Shutting down quorum peer \" + qp.getName());\n            qp.shutdown();\n            Election e = qp.getElectionAlg();\n            if (e != null) {\n                LOG.info(\"Shutting down leader election \" + qp.getName());\n                e.shutdown();\n            } else {\n                LOG.info(\"No election available to shutdown \" + qp.getName());\n            }\n            LOG.info(\"Waiting for \" + qp.getName() + \" to exit thread\");\n            qp.join(30000);\n            if (qp.isAlive()) {\n                Assert.fail(\"QP failed to shutdown in 30 seconds: \" + qp.getName());\n            }\n        } catch (InterruptedException e) {\n            LOG.debug(\"QP interrupted: \" + qp.getName(), e);\n        }\n    }\n\n    public String getConnString() {\n        return hostPort;\n    }\n\n    public void tearDown() throws Exception {\n        LOG.info(\"TearDown started\");\n\n        OSMXBean osMbean = new OSMXBean();\n        if (osMbean.getUnix() == true) {    \n            LOG.info(\"fdcount after test is: \" + osMbean.getOpenFileDescriptorCount());\n        }\n\n        shutdownAll();\n        JMXEnv.tearDown();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/QuorumZxidSyncTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class QuorumZxidSyncTest extends ZKTestCase {\n    QuorumBase qb = new QuorumBase();\n\n    @Before\n    public void setUp() throws Exception {\n        qb.setUp();\n    }\n\n    /**\n     * find out what happens when a follower connects to leader that is behind\n     */\n    @Test\n    public void testBehindLeader() throws Exception {\n        // crank up the epoch numbers\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ZooKeeper zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/0\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/2\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        deleteFiles(qb.s1dir);\n        deleteFiles(qb.s2dir);\n        deleteFiles(qb.s3dir);\n        deleteFiles(qb.s4dir);\n        qb.setupServers();\n        qb.s1.start();\n        qb.s2.start();\n        qb.s3.start();\n        qb.s4.start();\n        Assert.assertTrue(\"Servers didn't come up\", ClientBase.waitForServerUp(qb.hostPort, 10000));\n        qb.s5.start();\n        String hostPort = \"127.0.0.1:\" + qb.s5.getClientPort();\n        Assert.assertFalse(\"Servers came up, but shouldn't have since it's ahead of leader\",\n                ClientBase.waitForServerUp(hostPort, 10000));\n    }\n\n    private void deleteFiles(File f) {\n        File v = new File(f, \"version-2\");\n        for(File c: v.listFiles()) {\n            c.delete();\n        }\n    }\n\n    /**\n     * find out what happens when the latest state is in the snapshots not\n     * the logs.\n     */\n    @Test\n    public void testLateLogs() throws Exception {\n        // crank up the epoch numbers\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ZooKeeper zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/0\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/1\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        qb.shutdownServers();\n        deleteLogs(qb.s1dir);\n        deleteLogs(qb.s2dir);\n        deleteLogs(qb.s3dir);\n        deleteLogs(qb.s4dir);\n        deleteLogs(qb.s5dir);\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        zk.create(\"/2\", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdownServers();\n        qb.startServers();\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        boolean saw2 = false;\n        for(String child: zk.getChildren(\"/\", false)) {\n            if (child.equals(\"2\")) {\n                saw2 = true;\n            }\n        }\n        zk.close();\n        Assert.assertTrue(\"Didn't see /2 (went back in time)\", saw2);\n    }\n\n    private void deleteLogs(File f) {\n        File v = new File(f, \"version-2\");\n        for(File c: v.listFiles()) {\n            if (c.getName().startsWith(\"log\")) {\n                c.delete();\n            }\n        }\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        qb.tearDown();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ReadOnlyModeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.LineNumberReader;\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport junit.framework.Assert;\n\nimport org.apache.log4j.Layout;\nimport org.apache.log4j.Level;\nimport org.apache.log4j.Logger;\nimport org.apache.log4j.WriterAppender;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.KeeperException.NotReadOnlyException;\nimport org.apache.zookeeper.Transaction;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooKeeper.States;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.LoggerFactory;\n\npublic class ReadOnlyModeTest extends ZKTestCase {\n    private static final org.slf4j.Logger LOG = LoggerFactory\n            .getLogger(ReadOnlyModeTest.class);\n    private static int CONNECTION_TIMEOUT = QuorumBase.CONNECTION_TIMEOUT;\n    private QuorumUtil qu = new QuorumUtil(1);\n\n    @Before\n    public void setUp() throws Exception {\n        System.setProperty(\"readonlymode.enabled\", \"true\");\n        qu.startQuorum();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        System.setProperty(\"readonlymode.enabled\", \"false\");\n        qu.tearDown();\n    }\n\n    /**\n     * Test write operations using multi request.\n     */\n    @Test(timeout = 90000)\n    public void testMultiTransaction() throws Exception {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,\n                watcher, true);\n        watcher.waitForConnected(CONNECTION_TIMEOUT); // ensure zk got connected\n\n        final String data = \"Data to be read in RO mode\";\n        final String node1 = \"/tnode1\";\n        final String node2 = \"/tnode2\";\n        zk.create(node1, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        watcher.reset();\n        qu.shutdown(2);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        Assert.assertEquals(\"Should be in r-o mode\", States.CONNECTEDREADONLY,\n                zk.getState());\n\n        // read operation during r/o mode\n        String remoteData = new String(zk.getData(node1, false, null));\n        Assert.assertEquals(\"Failed to read data in r-o mode\", data, remoteData);\n\n        try {\n            Transaction transaction = zk.transaction();\n            transaction.setData(node1, \"no way\".getBytes(), -1);\n            transaction.create(node2, data.getBytes(),\n                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            transaction.commit();\n            Assert.fail(\"Write operation using multi-transaction\"\n                    + \" api has succeeded during RO mode\");\n        } catch (NotReadOnlyException e) {\n            // ok\n        }\n\n        Assert.assertNull(\"Should have created the znode:\" + node2,\n                zk.exists(node2, false));\n    }\n\n    /**\n     * Basic test of read-only client functionality. Tries to read and write\n     * during read-only mode, then regains a quorum and tries to write again.\n     */\n    @Test(timeout = 90000)\n    public void testReadOnlyClient() throws Exception {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,\n                watcher, true);\n        watcher.waitForConnected(CONNECTION_TIMEOUT); // ensure zk got connected\n\n        final String data = \"Data to be read in RO mode\";\n        final String node = \"/tnode\";\n        zk.create(node, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        watcher.reset();\n        qu.shutdown(2);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n\n        // read operation during r/o mode\n        String remoteData = new String(zk.getData(node, false, null));\n        Assert.assertEquals(data, remoteData);\n\n        try {\n            zk.setData(node, \"no way\".getBytes(), -1);\n            Assert.fail(\"Write operation has succeeded during RO mode\");\n        } catch (NotReadOnlyException e) {\n            // ok\n        }\n\n        watcher.reset();\n        qu.start(2);\n        Assert.assertTrue(\"waiting for server up\", ClientBase.waitForServerUp(\n                \"127.0.0.1:\" + qu.getPeer(2).clientPort, CONNECTION_TIMEOUT));\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        zk.setData(node, \"We're in the quorum now\".getBytes(), -1);\n\n        zk.close();\n    }\n\n    /**\n     * Ensures that upon connection to a read-only server client receives\n     * ConnectedReadOnly state notification.\n     */\n    @Test(timeout = 90000)\n    public void testConnectionEvents() throws Exception {\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,\n                watcher, true);\n        boolean success = false;\n        for (int i = 0; i < 30; i++) {\n            try {\n                zk.create(\"/test\", \"test\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n                success=true;\n                break;\n            } catch(KeeperException.ConnectionLossException e) {\n                Thread.sleep(1000);               \n            }            \n        }\n        Assert.assertTrue(\"Did not succeed in connecting in 30s\", success);\n        Assert.assertFalse(\"The connection should not be read-only yet\", watcher.readOnlyConnected);\n\n        // kill peer and wait no more than 5 seconds for read-only server\n        // to be started (which should take one tickTime (2 seconds))\n        qu.shutdown(2);\n        long start = Time.currentElapsedTime();\n        while (!(zk.getState() == States.CONNECTEDREADONLY)) {\n            Thread.sleep(200);\n            // FIXME this was originally 5 seconds, but realistically, on random/slow/virt hosts, there is no way to guarantee this\n            Assert.assertTrue(\"Can't connect to the server\",\n                              Time.currentElapsedTime() - start < 30000);\n        }\n\n        watcher.waitForReadOnlyConnected(5000);\n        zk.close();\n    }\n\n    /**\n     * Tests a situation when client firstly connects to a read-only server and\n     * then connects to a majority server. Transition should be transparent for\n     * the user.\n     */\n    @Test(timeout = 90000)\n    public void testSessionEstablishment() throws Exception {\n        qu.shutdown(2);\n\n        CountdownWatcher watcher = new CountdownWatcher();\n        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,\n                watcher, true);\n        watcher.waitForConnected(CONNECTION_TIMEOUT);\n        Assert.assertSame(\"should be in r/o mode\", States.CONNECTEDREADONLY, zk\n                .getState());\n        long fakeId = zk.getSessionId();\n        LOG.info(\"Connected as r/o mode with state {} and session id {}\",\n                zk.getState(), fakeId);\n\n        watcher.reset();\n        qu.start(2);\n        Assert.assertTrue(\"waiting for server up\", ClientBase.waitForServerUp(\n                \"127.0.0.1:\" + qu.getPeer(2).clientPort, CONNECTION_TIMEOUT));\n        LOG.info(\"Server 127.0.0.1:{} is up\", qu.getPeer(2).clientPort);\n        // ZOOKEEPER-2722: wait until we can connect to a read-write server after the quorum\n        // is formed. Otherwise, it is possible that client first connects to a read-only server,\n        // then drops the connection because of shutting down of the read-only server caused\n        // by leader election / quorum forming between the read-only server and the newly started\n        // server. If we happen to execute the zk.create after the read-only server is shutdown and\n        // before the quorum is formed, we will get a ConnectLossException.\n        watcher.waitForSyncConnected(CONNECTION_TIMEOUT);\n        Assert.assertEquals(\"Should be in read-write mode\", States.CONNECTED,\n                zk.getState());\n        LOG.info(\"Connected as rw mode with state {} and session id {}\",\n                zk.getState(), zk.getSessionId());\n        zk.create(\"/test\", \"test\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        Assert.assertFalse(\"fake session and real session have same id\", zk\n                .getSessionId() == fakeId);\n        zk.close();\n    }\n\n    /**\n     * Ensures that client seeks for r/w servers while it's connected to r/o\n     * server.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @Test(timeout = 90000)\n    public void testSeekForRwServer() throws Exception {\n\n        // setup the logger to capture all logs\n        Layout layout = Logger.getRootLogger().getAppender(\"CONSOLE\")\n                .getLayout();\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        WriterAppender appender = new WriterAppender(layout, os);\n        appender.setImmediateFlush(true);\n        appender.setThreshold(Level.INFO);\n        Logger zlogger = Logger.getLogger(\"org.apache.zookeeper\");\n        zlogger.addAppender(appender);\n\n        try {\n            qu.shutdown(2);\n            CountdownWatcher watcher = new CountdownWatcher();\n            ZooKeeper zk = new ZooKeeper(qu.getConnString(),\n                    CONNECTION_TIMEOUT, watcher, true);\n            watcher.waitForConnected(CONNECTION_TIMEOUT);\n\n            // if we don't suspend a peer it will rejoin a quorum\n            qu.getPeer(1).peer.suspend();\n\n            // start two servers to form a quorum; client should detect this and\n            // connect to one of them\n            watcher.reset();\n            qu.start(2);\n            qu.start(3);\n            ClientBase.waitForServerUp(qu.getConnString(), 2000);\n            watcher.waitForConnected(CONNECTION_TIMEOUT);\n            zk.create(\"/test\", \"test\".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.PERSISTENT);\n\n            // resume poor fellow\n            qu.getPeer(1).peer.resume();\n        } finally {\n            zlogger.removeAppender(appender);\n        }\n\n        os.close();\n        LineNumberReader r = new LineNumberReader(new StringReader(os\n                .toString()));\n        String line;\n        Pattern p = Pattern.compile(\".*Majority server found.*\");\n        boolean found = false;\n        while ((line = r.readLine()) != null) {\n            if (p.matcher(line).matches()) {\n                found = true;\n                break;\n            }\n        }\n        Assert.assertTrue(\n                \"Majority server wasn't found while connected to r/o server\",\n                found);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/RecoveryTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class RecoveryTest extends ZKTestCase implements Watcher {\n    protected static final Logger LOG = LoggerFactory.getLogger(RecoveryTest.class);\n\n    private static final String HOSTPORT =\n        \"127.0.0.1:\" + PortAssignment.unique();\n\n    private volatile CountDownLatch startSignal;\n\n    /**\n     * Verify that if a server goes down that clients will reconnect\n     * automatically after the server is restarted. Note that this requires the\n     * server to restart within the connection timeout period.\n     *\n     * Also note that the client latches are used to eliminate any chance\n     * of spurrious connectionloss exceptions on the read ops. Specifically\n     * a sync operation will throw this exception if the server goes down\n     * (as recognized by the client) during the operation. If the operation\n     * occurs after the server is down, but before the client recognizes\n     * that the server is down (ping) then the op will throw connectionloss.\n     */\n    @Test\n    public void testRecovery() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n\n        int oldSnapCount = SyncRequestProcessor.getSnapCount();\n        SyncRequestProcessor.setSnapCount(1000);\n        try {\n            final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n            ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n            f.startup(zks);\n            LOG.info(\"starting up the the server, waiting\");\n\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(HOSTPORT,\n                                       CONNECTION_TIMEOUT));\n\n            startSignal = new CountDownLatch(1);\n            ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n            startSignal.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n            Assert.assertTrue(\"count == 0\", startSignal.getCount() == 0);\n            String path;\n            LOG.info(\"starting creating nodes\");\n            for (int i = 0; i < 10; i++) {\n                path = \"/\" + i;\n                zk.create(path,\n                          (path + \"!\").getBytes(),\n                          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                for (int j = 0; j < 10; j++) {\n                    String subpath = path + \"/\" + j;\n                    zk.create(subpath, (subpath + \"!\").getBytes(),\n                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                    for (int k = 0; k < 20; k++) {\n                        String subsubpath = subpath + \"/\" + k;\n                        zk.create(subsubpath, (subsubpath + \"!\").getBytes(),\n                                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                    }\n                }\n            }\n\n            f.shutdown();\n            zks.shutdown();\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(HOSTPORT,\n                                          CONNECTION_TIMEOUT));\n\n            zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n            f = ServerCnxnFactory.createFactory(PORT, -1);\n\n            startSignal = new CountDownLatch(1);\n\n            f.startup(zks);\n\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(HOSTPORT,\n                                           CONNECTION_TIMEOUT));\n\n            startSignal.await(CONNECTION_TIMEOUT,\n                    TimeUnit.MILLISECONDS);\n            Assert.assertTrue(\"count == 0\", startSignal.getCount() == 0);\n\n            Stat stat = new Stat();\n            for (int i = 0; i < 10; i++) {\n                path = \"/\" + i;\n                LOG.info(\"Checking \" + path);\n                Assert.assertEquals(new String(zk.getData(path, false, stat)), path\n                        + \"!\");\n                for (int j = 0; j < 10; j++) {\n                    String subpath = path + \"/\" + j;\n                    Assert.assertEquals(new String(zk.getData(subpath, false, stat)),\n                            subpath + \"!\");\n                    for (int k = 0; k < 20; k++) {\n                        String subsubpath = subpath + \"/\" + k;\n                        Assert.assertEquals(new String(zk.getData(subsubpath, false,\n                                stat)), subsubpath + \"!\");\n                    }\n                }\n            }\n            f.shutdown();\n            zks.shutdown();\n\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(HOSTPORT,\n                                          ClientBase.CONNECTION_TIMEOUT));\n\n            zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n            f = ServerCnxnFactory.createFactory(PORT, -1);\n\n            startSignal = new CountDownLatch(1);\n\n            f.startup(zks);\n\n            Assert.assertTrue(\"waiting for server up\",\n                       ClientBase.waitForServerUp(HOSTPORT,\n                               CONNECTION_TIMEOUT));\n\n            startSignal.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);\n            Assert.assertTrue(\"count == 0\", startSignal.getCount() == 0);\n\n            stat = new Stat();\n            LOG.info(\"Check 2\");\n            for (int i = 0; i < 10; i++) {\n                path = \"/\" + i;\n                Assert.assertEquals(new String(zk.getData(path, false, stat)),\n                             path + \"!\");\n                for (int j = 0; j < 10; j++) {\n                    String subpath = path + \"/\" + j;\n                    Assert.assertEquals(new String(zk.getData(subpath, false, stat)),\n                            subpath + \"!\");\n                    for (int k = 0; k < 20; k++) {\n                        String subsubpath = subpath + \"/\" + k;\n                        Assert.assertEquals(new String(zk.getData(subsubpath, false,\n                                stat)), subsubpath + \"!\");\n                    }\n                }\n            }\n            zk.close();\n\n            f.shutdown();\n            zks.shutdown();\n\n            Assert.assertTrue(\"waiting for server down\",\n                       ClientBase.waitForServerDown(HOSTPORT,\n                                                    CONNECTION_TIMEOUT));\n        } finally {\n            SyncRequestProcessor.setSnapCount(oldSnapCount);\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatcherEvent)\n     */\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \" + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected\n                && startSignal != null && startSignal.getCount() > 0)\n        {\n            startSignal.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/RepeatStartupTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class RepeatStartupTest extends ZKTestCase {\n\n    /** bring up 5 quorum peers and then shut them down\n     * and then bring one of the nodes as server\n     *\n     * @throws Exception might be thrown here\n     */\n    @Test\n    public void testFail() throws Exception {\n        QuorumBase qb = new QuorumBase();\n        qb.setUp();\n\n        System.out.println(\"Comment: the servers are at \" + qb.hostPort);\n        ZooKeeper zk = qb.createClient();\n        zk.create(\"/test\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        zk.close();\n        qb.shutdown(qb.s1);\n        qb.shutdown(qb.s2);\n        qb.shutdown(qb.s3);\n        qb.shutdown(qb.s4);\n        qb.shutdown(qb.s5);\n        String hp = qb.hostPort.split(\",\")[0];\n        ZooKeeperServer zks = new ZooKeeperServer(qb.s1.getTxnFactory().getSnapDir(),\n                qb.s1.getTxnFactory().getDataDir(), 3000);\n        final int PORT = Integer.parseInt(hp.split(\":\")[1]);\n        ServerCnxnFactory factory = ServerCnxnFactory.createFactory(PORT, -1);\n\n        factory.startup(zks);\n        System.out.println(\"Comment: starting factory\");\n        Assert.assertTrue(\"waiting for server up\",\n                   ClientBase.waitForServerUp(\"127.0.0.1:\" + PORT,\n                           QuorumTest.CONNECTION_TIMEOUT));\n        factory.shutdown();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(\"127.0.0.1:\" + PORT,\n                                                QuorumTest.CONNECTION_TIMEOUT));\n        System.out.println(\"Comment: shutting down standalone\");\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/RestoreCommittedLogTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.LinkedList;\n\nimport org.apache.log4j.Logger;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.quorum.Leader.Proposal;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/** After a replica starts, it should load commits in its committedLog list. \n *  This test checks if committedLog != 0 after replica restarted.\n */\npublic class RestoreCommittedLogTest extends ZKTestCase implements  Watcher {\n    private static final Logger LOG = Logger.getLogger(RestoreCommittedLogTest.class);\n    private static String HOSTPORT = \"127.0.0.1:\" + PortAssignment.unique();\n    private static final int CONNECTION_TIMEOUT = 3000;\n    /**\n     * test the purge\n     * @throws Exception an exception might be thrown here\n     */\n    @Test\n    public void testRestoreCommittedLog() throws Exception {\n        File tmpDir = ClientBase.createTmpDir();\n        ClientBase.setupTestEnv();\n        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        SyncRequestProcessor.setSnapCount(100);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        Assert.assertTrue(\"waiting for server being up \",\n                ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        try {\n            for (int i = 0; i< 2000; i++) {\n                zk.create(\"/invalidsnap-\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT);\n            }\n        } finally {\n            zk.close();\n        }\n        f.shutdown();\n        zks.shutdown();\n        Assert.assertTrue(\"waiting for server to shutdown\",\n                ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));\n\n        // start server again\n        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);\n        zks.startdata();\n        LinkedList<Proposal> committedLog = zks.getZKDatabase().getCommittedLog();\n        int logsize = committedLog.size();\n        LOG.info(\"committedLog size = \" + logsize);\n        Assert.assertTrue(\"log size != 0\", (logsize != 0));\n        zks.shutdown();\n    }\n\n    public void process(WatchedEvent event) {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthDesignatedClientTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class SaslAuthDesignatedClientTest extends ClientBase {\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"MyZookeeperClient\");\n\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n\n            fwriter.write(\"\" +\n                \"Server {\\n\" +\n                \"          org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"          user_myuser=\\\"mypassword\\\";\\n\" +\n                \"};\\n\" +\n                \"Client {\\n\" + /* this 'Client' section has an incorrect password, but we're not configured\n                                  to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to \n                                  use the 'MyZookeeperClient' section below, which has the correct password).*/\n                \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"       username=\\\"myuser\\\"\\n\" +\n                \"       password=\\\"wrongpassword\\\";\\n\" +\n                \"};\" +\n                \"MyZookeeperClient {\\n\" +\n                \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"       username=\\\"myuser\\\"\\n\" +\n                \"       password=\\\"mypassword\\\";\\n\" +\n                \"};\" + \"\\n\");\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",saslConfFile.getAbsolutePath());\n        }\n        catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file : test will fail now.\n        }\n    }\n\n    @Test\n    public void testAuth() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            Thread.sleep(1000);\n        } catch (KeeperException e) {\n          Assert.fail(\"test failed :\" + e);\n        }\n        finally {\n            zk.close();\n        }\n    }\n\n    @Test\n    public void testSaslConfig() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.getChildren(\"/\", false);\n            Assert.assertFalse(zk.getSaslClient().\n                clientTunneledAuthenticationInProgress());\n            Assert.assertEquals(zk.getSaslClient().getSaslState(),\n                ZooKeeperSaslClient.SaslState.COMPLETE);\n            Assert.assertNotNull(\n                javax.security.auth.login.Configuration.getConfiguration().\n                    getAppConfigurationEntry(\"MyZookeeperClient\"));\n            Assert.assertSame(zk.getSaslClient().getLoginContext(),\n                \"MyZookeeperClient\");\n        } catch (KeeperException e) {\n            Assert.fail(\"test failed :\" + e);\n        } finally {\n            zk.close();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthDesignatedServerTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.server.ZooKeeperSaslServer;\nimport org.apache.zookeeper.JaasConfiguration;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class SaslAuthDesignatedServerTest extends ClientBase {\n    public static int AUTHENTICATION_TIMEOUT = 30000;\n\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        System.setProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, \"MyZookeeperServer\");\n\n        JaasConfiguration conf = new JaasConfiguration();\n\n        /* this 'Server' section has an incorrect password, but we're not configured\n         * to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...)\n         * to use the 'MyZookeeperServer' section below, which has the correct password).\n         */\n        conf.addSection(\"Server\", \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n                        \"user_myuser\", \"wrongpassword\");\n\n        conf.addSection(\"MyZookeeperServer\", \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n                        \"user_myuser\", \"mypassword\");\n\n        conf.addSection(\"Client\", \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n                        \"username\", \"myuser\", \"password\", \"mypassword\");\n\n        javax.security.auth.login.Configuration.setConfiguration(conf);\n    }\n\n    private AtomicInteger authFailed = new AtomicInteger(0);\n\n    private class MyWatcher extends CountdownWatcher {\n        volatile CountDownLatch authCompleted;\n\n        @Override\n        synchronized public void reset() {\n            authCompleted = new CountDownLatch(1);\n            super.reset();\n        }\n\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                authFailed.incrementAndGet();\n                authCompleted.countDown();\n            } else if (event.getState() == KeeperState.SaslAuthenticated) {\n                authCompleted.countDown();\n            } else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testAuth() throws Exception {\n        MyWatcher watcher = new MyWatcher();\n        ZooKeeper zk = createClient(watcher);\n        watcher.authCompleted.await(AUTHENTICATION_TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertEquals(authFailed.get(), 0);\n\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n        } catch (KeeperException e) {\n          Assert.fail(\"test failed :\" + e);\n        }\n        finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthFailDesignatedClientTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class SaslAuthFailDesignatedClientTest extends ClientBase {\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"MyZookeeperClient\");\n\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n\n            fwriter.write(\"\" +\n                \"Server {\\n\" +\n                \"          org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"          user_myuser=\\\"mypassword\\\";\\n\" +\n                \"};\\n\" +\n                \"Client {\\n\" + /* this 'Client' section has the correct password, but we're not configured\n                                  to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to \n                                  use the 'MyZookeeperClient' section, which has an incorrect password).*/\n                \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"       username=\\\"myuser\\\"\\n\" +\n                \"       password=\\\"mypassword\\\";\\n\" +\n                \"};\" +\n                \"MyZookeeperClient {\\n\" +\n                \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"       username=\\\"myuser\\\"\\n\" +\n                \"       password=\\\"wrongpassword\\\";\\n\" +\n                \"};\" + \"\\n\");\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",saslConfFile.getAbsolutePath());\n        }\n        catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file : test will fail now.\n        }\n    }\n\n    private AtomicInteger authFailed = new AtomicInteger(0);\n\n    private class MyWatcher extends CountdownWatcher {\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                authFailed.incrementAndGet();\n            }\n            else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testAuth() throws Exception {\n        // Cannot use createClient here because server may close session before \n        // JMXEnv.ensureAll is called which will fail the test case\n        CountdownWatcher watcher = new CountdownWatcher();\n        TestableZooKeeper zk = new TestableZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);\n        if (!watcher.clientConnected.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS))\n        {\n            Assert.fail(\"Unable to connect to server\");\n        }\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            Assert.fail(\"Should have gotten exception.\");\n        } catch (KeeperException e) {\n            // ok, exception as expected.\n            LOG.info(\"Got exception as expected: \" + e);\n        }\n        finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthFailNotifyTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Test;\nimport org.junit.Assert;\n\npublic class SaslAuthFailNotifyTest extends ClientBase {\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        System.setProperty(\"zookeeper.allowSaslFailedClients\",\"true\");\n\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n\n            fwriter.write(\"\" +\n                    \"Server {\\n\" +\n                    \"          org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                    \"          user_super=\\\"test\\\";\\n\" +\n                    \"};\\n\" +\n                    \"Client {\\n\" +\n                    \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                    \"       username=\\\"super\\\"\\n\" +\n                    \"       password=\\\"test1\\\";\\n\" + // NOTE: wrong password ('test' != 'test1') : this is to test SASL authentication failure.\n                    \"};\" + \"\\n\");\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",saslConfFile.getAbsolutePath());\n        }\n        catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file.\n        }\n    }\n\n    private AtomicInteger authFailed = new AtomicInteger(0);\n    \n    @Override\n    protected TestableZooKeeper createClient(String hp)\n    throws IOException, InterruptedException\n    {\n        MyWatcher watcher = new MyWatcher();\n        return createClient(watcher, hp);\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                synchronized(authFailed) {\n                    authFailed.incrementAndGet();\n                    authFailed.notify();\n                }\n            }\n            else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testBadSaslAuthNotifiesWatch() throws Exception {\n        ZooKeeper zk = createClient();\n        // wait for authFailed event from client's EventThread.\n        synchronized(authFailed) {\n            authFailed.wait();\n        }\n        Assert.assertEquals(authFailed.get(),1);\n        zk.close();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthFailTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Test;\nimport org.junit.Assert;\n\npublic class SaslAuthFailTest extends ClientBase {\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        System.setProperty(\"zookeeper.allowSaslFailedClients\",\"true\");\n\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n\n            fwriter.write(\"\" +\n                    \"Server {\\n\" +\n                    \"          org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                    \"          user_super=\\\"test\\\";\\n\" +\n                    \"};\\n\" +\n                    \"Client {\\n\" +\n                    \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                    \"       username=\\\"super\\\"\\n\" +\n                    \"       password=\\\"test1\\\";\\n\" + // NOTE: wrong password ('test' != 'test1') : this is to test SASL authentication failure.\n                    \"};\" + \"\\n\");\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",saslConfFile.getAbsolutePath());\n        }\n        catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file.\n        }\n    }\n    \n    @Test\n    public void testAuthFail() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            Assert.fail(\"Should have gotten exception.\");\n        } catch(Exception e ) {\n            // ok, exception as expected.\n            LOG.info(\"Got exception as expected: \" + e);\n        } finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslAuthMissingClientConfigTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class SaslAuthMissingClientConfigTest extends ClientBase {\n    static {\n        System.setProperty(\"zookeeper.authProvider.1\",\"org.apache.zookeeper.server.auth.SASLAuthenticationProvider\");\n        // This configuration section 'MyZookeeperClient', is missing from the JAAS configuration.\n        // As a result, SASL authentication should fail, which is tested by this test (testAuth()).\n        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, \"MyZookeeperClient\");\n\n        try {\n            File tmpDir = createTmpDir();\n            File saslConfFile = new File(tmpDir, \"jaas.conf\");\n            FileWriter fwriter = new FileWriter(saslConfFile);\n\n            fwriter.write(\"\" +\n                \"Server {\\n\" +\n                \"          org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"          user_myuser=\\\"mypassword\\\";\\n\" +\n                \"};\\n\" +\n                \"Client {\\n\" + /* this 'Client' section has the correct password, but we're not configured\n                                  to  use it - we're configured instead by the above\n                                  System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to\n                                  use the (nonexistent) 'MyZookeeperClient' section. */\n                \"       org.apache.zookeeper.server.auth.DigestLoginModule required\\n\" +\n                \"       username=\\\"myuser\\\"\\n\" +\n                \"       password=\\\"mypassword\\\";\\n\" +\n                \"};\\n\");\n            fwriter.close();\n            System.setProperty(\"java.security.auth.login.config\",saslConfFile.getAbsolutePath());\n        }\n        catch (IOException e) {\n            // could not create tmp directory to hold JAAS conf file : test will fail now.\n        }\n    }\n\n    private AtomicInteger authFailed = new AtomicInteger(0);\n\n    private class MyWatcher extends CountdownWatcher {\n        @Override\n        public synchronized void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.AuthFailed) {\n                authFailed.incrementAndGet();\n            }\n            else {\n                super.process(event);\n            }\n        }\n    }\n\n    @Test\n    public void testAuth() throws Exception {\n        ZooKeeper zk = createClient();\n        try {\n            zk.create(\"/path1\", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);\n            Assert.fail(\"Should have gotten exception.\");\n        } catch (KeeperException e) {\n            // ok, exception as expected.\n            LOG.info(\"Got exception as expected: \" + e);\n        }\n        finally {\n            zk.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SaslClientTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.client.ZooKeeperSaslClient;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Arrays;\n\npublic class SaslClientTest extends ZKTestCase {\n\n    private String existingPropertyValue = null;\n\n    @Before\n    public void setUp() {\n        existingPropertyValue = System.getProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY);\n    }\n\n    @After\n    public void tearDown() {\n        // Restore the System property if it was set previously\n        if (existingPropertyValue != null) {\n            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, existingPropertyValue);\n        }\n    }\n\n    @Test\n    public void testSaslClientDisabled() {\n        System.clearProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY);\n        Assert.assertTrue(\"SASL client disabled\", ZooKeeperSaslClient.isEnabled());\n\n        for (String value : Arrays.asList(\"true\", \"TRUE\")) {\n            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, value);\n            Assert.assertTrue(\"SASL client disabled\", ZooKeeperSaslClient.isEnabled());\n        }\n\n        for (String value : Arrays.asList(\"false\", \"FALSE\")) {\n            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, value);\n            Assert.assertFalse(\"SASL client disabled\", ZooKeeperSaslClient.isEnabled());\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SessionInvalidationTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\n\nimport junit.framework.Assert;\n\nimport org.apache.jute.BinaryOutputArchive;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooDefs.OpCode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.proto.ConnectRequest;\nimport org.apache.zookeeper.proto.CreateRequest;\nimport org.apache.zookeeper.proto.RequestHeader;\nimport org.junit.Test;\n\npublic class SessionInvalidationTest extends ClientBase {\n    /**\n     * Test solution for ZOOKEEPER-1208. Verify that operations are not\n     * accepted after a close session.\n     * \n     * We're using our own marshalling here in order to force an operation\n     * after the session is closed (ZooKeeper.class will not allow this). Also\n     * by filling the pipe with operations it increases the likelyhood that\n     * the server will process the create before FinalRequestProcessor\n     * removes the session from the tracker.\n     */\n    @Test\n    public void testCreateAfterCloseShouldFail() throws Exception {\n        for (int i = 0; i < 10; i++) {\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);\n\n            // open a connection\n            boa.writeInt(44, \"len\");\n            ConnectRequest conReq = new ConnectRequest(0, 0, 30000, 0, new byte[16]);\n            conReq.serialize(boa, \"connect\");\n\n            // close connection\n            boa.writeInt(8, \"len\");\n            RequestHeader h = new RequestHeader(1, ZooDefs.OpCode.closeSession);\n            h.serialize(boa, \"header\");\n\n            // create ephemeral znode\n            boa.writeInt(52, \"len\"); // We'll fill this in later\n            RequestHeader header = new RequestHeader(2, OpCode.create);\n            header.serialize(boa, \"header\");\n            CreateRequest createReq = new CreateRequest(\"/foo\" + i, new byte[0],\n                    Ids.OPEN_ACL_UNSAFE, 1);\n            createReq.serialize(boa, \"request\");\n            baos.close();\n            \n            System.out.println(\"Length:\" + baos.toByteArray().length);\n            \n            String hp[] = hostPort.split(\":\");\n            Socket sock = new Socket(hp[0], Integer.parseInt(hp[1]));\n            InputStream resultStream = null;\n            try {\n                OutputStream outstream = sock.getOutputStream();\n                byte[] data = baos.toByteArray();\n                outstream.write(data);\n                outstream.flush();\n                \n                resultStream = sock.getInputStream();\n                byte[] b = new byte[10000];\n                int len;\n                while ((len = resultStream.read(b)) >= 0) {\n                    // got results\n                    System.out.println(\"gotlen:\" + len);\n                }\n            } finally {\n                if (resultStream != null) {\n                    resultStream.close();\n                }\n                sock.close();\n            }\n        }\n        \n        ZooKeeper zk = createClient();\n        Assert.assertEquals(1, zk.getChildren(\"/\", false).size());\n\n        zk.close();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SessionTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\npublic class SessionTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(SessionTest.class);\n\n    private static final String HOSTPORT = \"127.0.0.1:\" +\n            PortAssignment.unique();\n    \n    private ServerCnxnFactory serverFactory;\n    private ZooKeeperServer zs;\n\n    private CountDownLatch startSignal;\n\n    File tmpDir;\n\n    private final int TICK_TIME = 3000;\n\n    @Before\n    public void setUp() throws Exception {\n        if (tmpDir == null) {\n            tmpDir = ClientBase.createTmpDir();\n        }\n\n        ClientBase.setupTestEnv();\n        zs = new ZooKeeperServer(tmpDir, tmpDir, TICK_TIME);\n\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        serverFactory = ServerCnxnFactory.createFactory(PORT, -1);\n        serverFactory.startup(zs);\n\n        Assert.assertTrue(\"waiting for server up\",\n                   ClientBase.waitForServerUp(HOSTPORT,\n                                              CONNECTION_TIMEOUT));\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        serverFactory.shutdown();\n        zs.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(HOSTPORT,\n                                                CONNECTION_TIMEOUT));\n    }\n\n    private static class CountdownWatcher implements Watcher {\n        volatile CountDownLatch clientConnected = new CountDownLatch(1);\n\n        public void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.SyncConnected) {\n                clientConnected.countDown();\n            }\n        }\n    }\n\n    private DisconnectableZooKeeper createClient()\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createClient(CONNECTION_TIMEOUT, watcher);\n    }\n\n    private DisconnectableZooKeeper createClient(int timeout)\n        throws IOException, InterruptedException\n    {\n        CountdownWatcher watcher = new CountdownWatcher();\n        return createClient(timeout, watcher);\n    }\n\n    private DisconnectableZooKeeper createClient(int timeout,\n            CountdownWatcher watcher)\n        throws IOException, InterruptedException\n    {\n        DisconnectableZooKeeper zk =\n                new DisconnectableZooKeeper(HOSTPORT, timeout, watcher);\n        if(!watcher.clientConnected.await(timeout, TimeUnit.MILLISECONDS)) {\n            Assert.fail(\"Unable to connect to server\");\n        }\n\n        return zk;\n    }\n\n// FIXME this test is Assert.failing due to client close race condition fixing in separate patch for ZOOKEEPER-63\n//    /**\n//     * this test checks to see if the sessionid that was created for the\n//     * first zookeeper client can be reused for the second one immidiately\n//     * after the first client closes and the new client resues them.\n//     * @throws IOException\n//     * @throws InterruptedException\n//     * @throws KeeperException\n//     */\n//    public void testSessionReuse() throws IOException, InterruptedException {\n//        ZooKeeper zk = createClient();\n//\n//        long sessionId = zk.getSessionId();\n//        byte[] passwd = zk.getSessionPasswd();\n//        zk.close();\n//\n//        zk.close();\n//\n//        LOG.info(\"Closed first session\");\n//\n//        startSignal = new CountDownLatch(1);\n//        zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this,\n//                sessionId, passwd);\n//        startSignal.await();\n//\n//        LOG.info(\"Opened reuse\");\n//\n//        Assert.assertEquals(sessionId, zk.getSessionId());\n//\n//        zk.close();\n//    }\n\n    private class MyWatcher implements Watcher {\n        private String name;\n        public MyWatcher(String name) {\n            this.name = name;\n        }\n        public void process(WatchedEvent event) {\n            LOG.info(name + \" event:\" + event.getState() + \" \"\n                    + event.getType() + \" \" + event.getPath());\n            if (event.getState() == KeeperState.SyncConnected\n                    && startSignal != null && startSignal.getCount() > 0)\n            {\n                startSignal.countDown();\n            }\n        }\n    }\n\n    /**\n     * This test verifies that when the session id is reused, and the original\n     * client is disconnected, but not session closed, that the server\n     * will remove ephemeral nodes created by the original session.\n     */\n    @Test\n    public void testSession()\n        throws IOException, InterruptedException, KeeperException\n    {\n        DisconnectableZooKeeper zk = createClient();\n        zk.create(\"/e\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.EPHEMERAL);\n        LOG.info(\"zk with session id 0x\" + Long.toHexString(zk.getSessionId())\n                + \" was destroyed!\");\n\n        // disconnect the client by killing the socket, not sending the\n        // session disconnect to the server as usual. This allows the test\n        // to verify disconnect handling\n        zk.disconnect();\n\n        Stat stat = new Stat();\n        startSignal = new CountDownLatch(1);\n        zk = new DisconnectableZooKeeper(HOSTPORT, CONNECTION_TIMEOUT,\n                new MyWatcher(\"testSession\"), zk.getSessionId(),\n                zk.getSessionPasswd());\n        startSignal.await();\n\n        LOG.info(\"zk with session id 0x\" + Long.toHexString(zk.getSessionId())\n                 + \" was created!\");\n        zk.getData(\"/e\", false, stat);\n        LOG.info(\"After get data /e\");\n        zk.close();\n\n        zk = createClient();\n        Assert.assertEquals(null, zk.exists(\"/e\", false));\n        LOG.info(\"before close zk with session id 0x\"\n                + Long.toHexString(zk.getSessionId()) + \"!\");\n        zk.close();\n        try {\n            zk.getData(\"/e\", false, stat);\n            Assert.fail(\"Should have received a SessionExpiredException\");\n        } catch(KeeperException.SessionExpiredException e) {}\n        \n        AsyncCallback.DataCallback cb = new AsyncCallback.DataCallback() {\n            String status = \"not done\";\n            public void processResult(int rc, String p, Object c, byte[] b, Stat s) {\n                synchronized(this) { status = KeeperException.Code.get(rc).toString(); this.notify(); }\n            }\n           public String toString() { return status; }\n        };\n        zk.getData(\"/e\", false, cb, null);\n        synchronized(cb) {\n            if (cb.toString().equals(\"not done\")) {\n                cb.wait(1000);\n            }\n        }\n        Assert.assertEquals(KeeperException.Code.SESSIONEXPIRED.toString(), cb.toString());        \n    }\n\n    private List<Thread> findThreads(String name) {\n        int threadCount = Thread.activeCount();\n        Thread threads[] = new Thread[threadCount*2];\n        threadCount = Thread.enumerate(threads);\n        ArrayList<Thread> list = new ArrayList<Thread>();\n        for(int i = 0; i < threadCount; i++) {\n            if (threads[i].getName().indexOf(name) != -1) {\n                list.add(threads[i]);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * Make sure ephemerals get cleaned up when a session times out.\n     */\n    @Test\n    public void testSessionTimeout() throws Exception {\n        final int TIMEOUT = 5000;\n        List<Thread> etBefore = findThreads(\"EventThread\");\n        List<Thread> stBefore = findThreads(\"SendThread\");\n        DisconnectableZooKeeper zk = createClient(TIMEOUT);\n        zk.create(\"/stest\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n\n        // Find the new event and send threads\n        List<Thread> etAfter = findThreads(\"EventThread\");\n        List<Thread> stAfter = findThreads(\"SendThread\");\n        Thread eventThread = null;\n        Thread sendThread = null;\n        for(Thread t: etAfter) {\n            if (!etBefore.contains(t)) {\n                eventThread = t;\n                break;\n            }\n        }\n        for(Thread t: stAfter) {\n            if (!stBefore.contains(t)) {\n                sendThread = t;\n                break;\n            }\n        }\n        sendThread.suspend();\n        //zk.disconnect();\n\n        Thread.sleep(TIMEOUT*2);\n        sendThread.resume();\n        eventThread.join(TIMEOUT);\n        Assert.assertFalse(\"EventThread is still running\", eventThread.isAlive());\n\n        zk = createClient(TIMEOUT);\n        zk.create(\"/stest\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n        tearDown();\n        zk.close();\n        zk.disconnect();\n        setUp();\n\n        zk = createClient(TIMEOUT);\n        Assert.assertTrue(zk.exists(\"/stest\", false) != null);\n        Thread.sleep(TIMEOUT*2);\n        Assert.assertTrue(zk.exists(\"/stest\", false) == null);\n        zk.close();\n    }\n\n    /**\n     * Make sure that we cannot have two connections with the same\n     * session id.\n     *\n     * @throws IOException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    @Test\n    public void testSessionMove() throws Exception {\n        String hostPorts[] = HOSTPORT.split(\",\");\n        DisconnectableZooKeeper zk = new DisconnectableZooKeeper(hostPorts[0],\n                CONNECTION_TIMEOUT, new MyWatcher(\"0\"));\n        zk.create(\"/sessionMoveTest\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n        // we want to loop through the list twice\n        for(int i = 0; i < hostPorts.length*2; i++) {\n            zk.dontReconnect();\n            // This should stomp the zk handle\n            DisconnectableZooKeeper zknew = new DisconnectableZooKeeper(\n                    hostPorts[(i+1)%hostPorts.length],\n                    CONNECTION_TIMEOUT,\n                    new MyWatcher(Integer.toString(i+1)),\n                    zk.getSessionId(),\n                    zk.getSessionPasswd());\n            final int result[] = new int[1];\n            result[0] = Integer.MAX_VALUE;\n            zknew.sync(\"/\", new AsyncCallback.VoidCallback() {\n                    public void processResult(int rc, String path, Object ctx) {\n                        synchronized(result) { result[0] = rc; result.notify(); }\n                    }\n                }, null);\n            synchronized(result) {\n                if(result[0] == Integer.MAX_VALUE) {\n                    result.wait(5000);\n                }\n            }\n            LOG.info(hostPorts[(i+1)%hostPorts.length] + \" Sync returned \" + result[0]);\n            Assert.assertTrue(result[0] == KeeperException.Code.OK.intValue());\n            zknew.setData(\"/\", new byte[1], -1);\n            try {\n                zk.setData(\"/\", new byte[1], -1);\n                Assert.fail(\"Should have lost the connection\");\n            } catch(KeeperException.ConnectionLossException e) {\n                LOG.info(\"Got connection loss exception as expected\");\n            }\n            //zk.close();\n            zk = zknew;\n        }\n        zk.close();\n    }\n    /**\n     * This test makes sure that duplicate state changes are not communicated\n     * to the client watcher. For example we should not notify state as\n     * \"disconnected\" if the watch has already been disconnected. In general\n     * we don't consider a dup state notification if the event type is\n     * not \"None\" (ie non-None communicates an event).\n     */\n    @Test\n    public void testSessionStateNoDupStateReporting()\n        throws IOException, InterruptedException, KeeperException\n    {\n        final int TIMEOUT = 3000;\n        DupWatcher watcher = new DupWatcher();\n        ZooKeeper zk = createClient(TIMEOUT, watcher);\n\n        // shutdown the server\n        serverFactory.shutdown();\n\n        try {\n            Thread.sleep(10000);\n        } catch (InterruptedException e) {\n            // ignore\n        }\n\n        // verify that the size is just 2 - ie connect then disconnect\n        // if the client attempts reconnect and we are not handling current\n        // state correctly (ie eventing on duplicate disconnects) then we'll\n        // see a disconnect for each Assert.failed connection attempt\n        Assert.assertEquals(2, watcher.states.size());\n\n        zk.close();\n    }\n\n    /**\n     * Verify access to the negotiated session timeout.\n     */\n    @Test\n    public void testSessionTimeoutAccess() throws Exception {\n        // validate typical case - requested == negotiated\n        DisconnectableZooKeeper zk = createClient(TICK_TIME * 4);\n        Assert.assertEquals(TICK_TIME * 4, zk.getSessionTimeout());\n        // make sure tostring works in both cases\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n\n        // validate lower limit\n        zk = createClient(TICK_TIME);\n        Assert.assertEquals(TICK_TIME * 2, zk.getSessionTimeout());\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n\n        // validate upper limit\n        zk = createClient(TICK_TIME * 30);\n        Assert.assertEquals(TICK_TIME * 20, zk.getSessionTimeout());\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n    }\n\n    private class DupWatcher extends CountdownWatcher {\n        public LinkedList<WatchedEvent> states = new LinkedList<WatchedEvent>();\n        public void process(WatchedEvent event) {\n            super.process(event);\n            if (event.getType() == EventType.None) {\n                states.add(event);\n            }\n        }\n    }\n\n    @Test\n    public void testMinMaxSessionTimeout() throws Exception {\n        // override the defaults\n        final int MINSESS = 20000;\n        final int MAXSESS = 240000;\n        {\n            ZooKeeperServer zs = ClientBase.getServer(serverFactory);\n            zs.setMinSessionTimeout(MINSESS);\n            zs.setMaxSessionTimeout(MAXSESS);\n        }\n\n        // validate typical case - requested == negotiated\n        int timeout = 120000;\n        DisconnectableZooKeeper zk = createClient(timeout);\n        Assert.assertEquals(timeout, zk.getSessionTimeout());\n        // make sure tostring works in both cases\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n\n        // validate lower limit\n        zk = createClient(MINSESS/2);\n        Assert.assertEquals(MINSESS, zk.getSessionTimeout());\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n\n        // validate upper limit\n        zk = createClient(MAXSESS * 2);\n        Assert.assertEquals(MAXSESS, zk.getSessionTimeout());\n        LOG.info(zk.toString());\n        zk.close();\n        LOG.info(zk.toString());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SledgeHammer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\n\npublic class SledgeHammer extends Thread implements Watcher {\n    ZooKeeper zk;\n\n    int count;\n\n    int readsPerWrite;\n\n    public SledgeHammer(String hosts, int count, int readsPerWrite)\n            throws IOException {\n        zk = new ZooKeeper(hosts, 10000, this);\n        this.count = count;\n        this.readsPerWrite = readsPerWrite;\n    }\n\n    public void run() {\n        try {\n            Stat stat = new Stat();\n            String path = zk.create(\"/hammers/hammer-\", new byte[0],\n                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n            byte tag[] = (path + \" was here!\").getBytes();\n            synchronized (this) {\n                String startPath = \"/hammers/start\";\n                System.out.println(\"Waiting for \" + startPath);\n                while (zk.exists(startPath, true) == null) {\n                    wait();\n                }\n                System.out.println(\"Running\");\n            }\n            for (int i = 0; i < count; i++) {\n                try {\n                    System.out.print(i + \"\\r\");\n                    List<String> childs =\n                        zk.getChildren(\"/hammers\", false);\n                    Collections.shuffle(childs);\n                    for (String s : childs) {\n                        if (s.startsWith(\"hammer-\")) {\n                            s = \"/hammers/\" + s;\n                            zk.setData(s, tag, -1);\n                            for (int j = 0; j < readsPerWrite; j++) {\n                                zk.getData(s, false, stat);\n                            }\n                            break;\n                        }\n                    }\n                } catch (KeeperException.ConnectionLossException e) {\n                    // ignore connection loss\n                } catch (KeeperException e) {\n                    e.printStackTrace();\n                }\n            }\n            System.out.println();\n            zk.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * @param args\n     * @throws IOException\n     * @throws KeeperException\n     * @throws NumberFormatException\n     */\n    public static void main(String[] args) throws NumberFormatException,\n            IOException {\n        if (args.length != 3) {\n            System.err\n                    .println(\"USAGE: SledgeHammer zookeeper_server reps reads_per_rep\");\n            System.exit(3);\n        }\n        SledgeHammer h = new SledgeHammer(args[0], Integer.parseInt(args[1]),\n                Integer.parseInt(args[2]));\n        h.start();\n        System.exit(0);\n    }\n\n    public void process(WatchedEvent event) {\n        synchronized (this) {\n            notifyAll();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/StandaloneTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.server.quorum.QuorumPeerTestBase;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Standalone server tests.\n */\npublic class StandaloneTest extends QuorumPeerTestBase implements Watcher{\n    protected static final Logger LOG =\n        LoggerFactory.getLogger(StandaloneTest.class);    \n      \n    /**\n     * Ensure that a single standalone server comes up when misconfigured\n     * with a single server.# line in the configuration. This handles the\n     * case of HBase, which configures zoo.cfg in this way. Maintain b/w\n     * compatibility.\n     * TODO remove in a future version (4.0.0 hopefully)\n     */\n    @Test\n    public void testStandaloneQuorum() throws Exception {\n        ClientBase.setupTestEnv();\n        final int CLIENT_PORT_QP1 = PortAssignment.unique();        \n        \n        String quorumCfgSection =\n            \"server.1=127.0.0.1:\" + (PortAssignment.unique())\n            + \":\" + (PortAssignment.unique()) + \"\\n\";\n                    \n        MainThread q1 = new MainThread(1, CLIENT_PORT_QP1, quorumCfgSection);\n        q1.start();\n        try {\n            Assert.assertTrue(\"waiting for server 1 being up\",\n                    ClientBase.waitForServerUp(\"127.0.0.1:\" + CLIENT_PORT_QP1,\n                            CONNECTION_TIMEOUT));\n        } finally {\n            q1.shutdown();\n        }\n    }    \n    \n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/StatTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class StatTest extends ClientBase {\n    private ZooKeeper zk;\n\n    @Override\n    public void setUp() throws Exception {\n        super.setUp();\n\n        zk = createClient();\n    }\n\n    @Override\n    public void tearDown() throws Exception {\n        super.tearDown();\n\n        zk.close();\n    }\n\n    /**\n     * Create a new Stat, fill in dummy values trying to catch Assert.failure\n     * to copy in client or server code.\n     *\n     * @return a new stat with dummy values\n     */\n    private Stat newStat() {\n        Stat stat = new Stat();\n\n        stat.setAversion(100);\n        stat.setCtime(100);\n        stat.setCversion(100);\n        stat.setCzxid(100);\n        stat.setDataLength(100);\n        stat.setEphemeralOwner(100);\n        stat.setMtime(100);\n        stat.setMzxid(100);\n        stat.setNumChildren(100);\n        stat.setPzxid(100);\n        stat.setVersion(100);\n\n        return stat;\n    }\n\n    @Test\n    public void testBasic()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        Stat stat;\n\n        stat = newStat();\n        zk.getData(name, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid(), stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(0, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(0, stat.getEphemeralOwner());\n        Assert.assertEquals(name.length(), stat.getDataLength());\n        Assert.assertEquals(0, stat.getNumChildren());\n    }\n\n    @Test\n    public void testChild()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        String childname = name + \"/bar\";\n        zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n\n        Stat stat;\n\n        stat = newStat();\n        zk.getData(name, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid() + 1, stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(1, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(0, stat.getEphemeralOwner());\n        Assert.assertEquals(name.length(), stat.getDataLength());\n        Assert.assertEquals(1, stat.getNumChildren());\n\n        stat = newStat();\n        zk.getData(childname, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid(), stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(0, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(zk.getSessionId(), stat.getEphemeralOwner());\n        Assert.assertEquals(childname.length(), stat.getDataLength());\n        Assert.assertEquals(0, stat.getNumChildren());\n    }\n\n    @Test\n    public void testChildren()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        for(int i = 0; i < 10; i++) {\n            String childname = name + \"/bar\" + i;\n            zk.create(childname, childname.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                    CreateMode.EPHEMERAL);\n\n            Stat stat;\n\n            stat = newStat();\n            zk.getData(name, false, stat);\n\n            Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n            Assert.assertEquals(stat.getCzxid() + i + 1, stat.getPzxid());\n            Assert.assertEquals(stat.getCtime(), stat.getMtime());\n            Assert.assertEquals(i + 1, stat.getCversion());\n            Assert.assertEquals(0, stat.getVersion());\n            Assert.assertEquals(0, stat.getAversion());\n            Assert.assertEquals(0, stat.getEphemeralOwner());\n            Assert.assertEquals(name.length(), stat.getDataLength());\n            Assert.assertEquals(i + 1, stat.getNumChildren());\n        }\n    }\n\n    @Test\n    public void testDataSizeChange()\n        throws IOException, KeeperException, InterruptedException\n    {\n        String name = \"/foo\";\n        zk.create(name, name.getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        Stat stat;\n\n        stat = newStat();\n        zk.getData(name, false, stat);\n\n        Assert.assertEquals(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid(), stat.getPzxid());\n        Assert.assertEquals(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(0, stat.getCversion());\n        Assert.assertEquals(0, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(0, stat.getEphemeralOwner());\n        Assert.assertEquals(name.length(), stat.getDataLength());\n        Assert.assertEquals(0, stat.getNumChildren());\n\n        zk.setData(name, (name + name).getBytes(), -1);\n\n        stat = newStat();\n        zk.getData(name, false, stat);\n\n        Assert.assertNotSame(stat.getCzxid(), stat.getMzxid());\n        Assert.assertEquals(stat.getCzxid(), stat.getPzxid());\n        Assert.assertNotSame(stat.getCtime(), stat.getMtime());\n        Assert.assertEquals(0, stat.getCversion());\n        Assert.assertEquals(1, stat.getVersion());\n        Assert.assertEquals(0, stat.getAversion());\n        Assert.assertEquals(0, stat.getEphemeralOwner());\n        Assert.assertEquals(name.length() * 2, stat.getDataLength());\n        Assert.assertEquals(0, stat.getNumChildren());\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/StaticHostProviderTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotSame;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.client.HostProvider;\nimport org.apache.zookeeper.client.StaticHostProvider;\nimport org.apache.zookeeper.common.Time;\nimport org.junit.Test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Random;\n\npublic class StaticHostProviderTest extends ZKTestCase {\n    private static final Logger LOG = LoggerFactory.getLogger(StaticHostProviderTest.class);\n    \n    @Test\n    public void testNextGoesRound() {\n        HostProvider hostProvider = getHostProvider((byte) 2);\n        InetSocketAddress first = hostProvider.next(0);\n        assertTrue(first instanceof InetSocketAddress);\n        hostProvider.next(0);\n        assertEquals(first, hostProvider.next(0));\n    }\n\n    @Test\n    public void testNextGoesRoundAndSleeps() {\n        byte size = 2;\n        HostProvider hostProvider = getHostProvider(size);\n        while (size > 0) {\n            hostProvider.next(0);\n            --size;\n        }\n        long start = Time.currentElapsedTime();\n        hostProvider.next(1000);\n        long stop = Time.currentElapsedTime();\n        assertTrue(900 <= stop - start);\n    }\n\n    @Test\n    public void testNextDoesNotSleepForZero() {\n        byte size = 2;\n        HostProvider hostProvider = getHostProvider(size);\n        while (size > 0) {\n            hostProvider.next(0);\n            --size;\n        }\n        long start = Time.currentElapsedTime();\n        hostProvider.next(0);\n        long stop = Time.currentElapsedTime();\n        assertTrue(5 > stop - start);\n    }\n\n    @Test\n    public void testTwoConsequitiveCallsToNextReturnDifferentElement()\n            throws UnknownHostException {\n        HostProvider hostProvider = getHostProvider((byte) 2);\n        assertNotSame(hostProvider.next(0), hostProvider.next(0));\n    }\n\n    @Test\n    public void testOnConnectDoesNotReset() {\n        HostProvider hostProvider = getHostProvider((byte) 2);\n        InetSocketAddress first = hostProvider.next(0);\n        hostProvider.onConnected();\n        InetSocketAddress second = hostProvider.next(0);\n        assertNotSame(first, second);\n    }\n\n    @Test\n    public void testLiteralIPNoReverseNS() throws Exception {\n        byte size = 30;\n        HostProvider hostProvider = getHostProviderUnresolved(size);\n        for (int i = 0; i < size; i++) {\n            InetSocketAddress next = hostProvider.next(0);\n            assertTrue(next instanceof InetSocketAddress);\n            assertTrue(!next.isUnresolved());\n            assertTrue(\"Did not match \"+ next.toString(), !next.toString().startsWith(\"/\"));\n            // Do NOT trigger the reverse name service lookup.\n            String hostname = next.getHostName();\n            // In this case, the hostname equals literal IP address.\n            hostname.equals(next.getAddress().getHostAddress());\n        }\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testTwoInvalidHostAddresses() {\n        ArrayList<InetSocketAddress> list = new ArrayList<InetSocketAddress>();\n        list.add(new InetSocketAddress(\"a\", 2181));\n        list.add(new InetSocketAddress(\"b\", 2181));\n        new StaticHostProvider(list);\n    }\n\n    public void testOneInvalidHostAddresses() {\n        Collection<InetSocketAddress> addr = getUnresolvedServerAddresses((byte) 1);\n        addr.add(new InetSocketAddress(\"a\", 2181));\n\n        StaticHostProvider sp = new StaticHostProvider(addr);\n        InetSocketAddress n1 = sp.next(0);\n        InetSocketAddress n2 = sp.next(0);\n\n        assertEquals(n2, n1);\n    }\n\n    private StaticHostProvider getHostProviderUnresolved(byte size) {\n        return new StaticHostProvider(getUnresolvedServerAddresses(size));\n    }\n\n    private Collection<InetSocketAddress> getUnresolvedServerAddresses(byte size) {\n        ArrayList<InetSocketAddress> list = new ArrayList<InetSocketAddress>(size);\n        while (size > 0) {\n            list.add(InetSocketAddress.createUnresolved(\"10.10.10.\" + size, 1234 + size));\n            --size;\n        }\n        return list;\n    }\n    \n    private StaticHostProvider getHostProvider(byte size) {\n        ArrayList<InetSocketAddress> list = new ArrayList<InetSocketAddress>(\n                size);\n        while (size > 0) {\n            try {\n                list.add(new InetSocketAddress(InetAddress.getByAddress(new byte[]{10, 10, 10, size}), 1234 + size));\n            } catch (UnknownHostException e) {\n                LOG.error(\"Exception while resolving address\", e);\n                fail(\"Failed to resolve address\");\n            }\n            --size;\n        }\n        return new StaticHostProvider(list);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/SyncCallTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.Children2Callback;\nimport org.apache.zookeeper.AsyncCallback.ChildrenCallback;\nimport org.apache.zookeeper.AsyncCallback.StringCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class SyncCallTest extends ClientBase\n    implements ChildrenCallback, Children2Callback, StringCallback, VoidCallback\n{\n    private CountDownLatch opsCount;\n    \n    List<Integer> results = new LinkedList<Integer>();\n    Integer limit = 100 + 1 + 100 + 100;\n    \n    @Test\n    public void testSync() throws Exception {\n        try {\n            LOG.info(\"Starting ZK:\" + (new Date()).toString());\n            opsCount = new CountDownLatch(limit);\n            ZooKeeper zk = createClient();\n            \n            LOG.info(\"Beginning test:\" + (new Date()).toString());\n            for(int i = 0; i < 100; i++)\n                zk.create(\"/test\" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.PERSISTENT, this, results);\n            zk.sync(\"/test\", this, results);\n            for(int i = 0; i < 100; i++)\n                zk.delete(\"/test\" + i, 0, this, results);\n            for(int i = 0; i < 100; i++)\n                zk.getChildren(\"/\", new NullWatcher(), (ChildrenCallback)this,\n                        results);\n            for(int i = 0; i < 100; i++)\n                zk.getChildren(\"/\", new NullWatcher(), (Children2Callback)this,\n                        results);\n            LOG.info(\"Submitted all operations:\" + (new Date()).toString());\n            \n            if(!opsCount.await(10000, TimeUnit.MILLISECONDS))\n                Assert.fail(\"Haven't received all confirmations\" + opsCount.getCount());\n\n            for(int i = 0; i < limit ; i++){\n                Assert.assertEquals(0, (int) results.get(i));\n            }\n            \n        } catch (IOException e) {\n            System.out.println(e.toString());\n        } \n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx,\n            List<String> children) { \n        ((List<Integer>)ctx).add(rc);\n        opsCount.countDown();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx,\n            List<String> children, Stat stat) { \n        ((List<Integer>)ctx).add(rc);\n        opsCount.countDown();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx, String name){\n        ((List<Integer>) ctx).add(rc);\n        opsCount.countDown();\n    \n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void processResult(int rc, String path, Object ctx){\n        ((List<Integer>) ctx).add(rc);    \n        opsCount.countDown();\n    \n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/TestHammer.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.common.Time;\n\npublic class TestHammer implements VoidCallback {\n\n    /**\n     * @param args\n     */\n    static int REPS = 50000;\n    public static void main(String[] args) {\n            long startTime = Time.currentElapsedTime();\n            ZooKeeper zk = null;\n            try {\n                zk = new ZooKeeper(args[0], 10000, null);\n            } catch (IOException e1) {\n                // TODO Auto-generated catch block\n                e1.printStackTrace();\n                throw new RuntimeException(e1);\n            }\n            for(int i = 0; i < REPS; i++) {\n                try {\n                    String name = zk.create(\"/testFile-\", new byte[16], Ids.OPEN_ACL_UNSAFE,\n                        CreateMode.EPHEMERAL_SEQUENTIAL);\n                    zk.delete(name, -1, new TestHammer(), null);\n                } catch(Exception e) {\n                    i--;\n                    e.printStackTrace();\n                }\n            }\n            System.out.println(\"creates/sec=\" + (REPS*1000/(Time.currentElapsedTime()-startTime)));\n    }\n\n    public void processResult(int rc, String path, Object ctx) {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/TestUtils.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\n\nimport org.junit.Assert;\n\n/**\n * This class contains test utility methods\n */\npublic class TestUtils {\n\n    /**\n     * deletes a folder recursively\n     *\n     * @param file\n     *            folder to be deleted\n     * @param failOnError\n     *            if true file deletion success is ensured\n     */\n    public static boolean deleteFileRecursively(File file,\n            final boolean failOnError) {\n        if (file != null) {\n            if (file.isDirectory()) {\n                File[] files = file.listFiles();\n                int size = files.length;\n                for (int i = 0; i < size; i++) {\n                    File f = files[i];\n                    boolean deleted = deleteFileRecursively(files[i], failOnError);\n                    if(!deleted && failOnError)\n                    {\n                        Assert.fail(\"file '\" + f.getAbsolutePath()+\"' deletion failed\");\n                    }\n                }\n            }\n            return file.delete();\n        }\n        return true;\n    }\n\n    public static boolean deleteFileRecursively(File file) {\n        return deleteFileRecursively(file, false);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/TruncateTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\n\nimport junit.framework.Assert;\n\nimport org.apache.jute.Record;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.Request;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.ZKDatabase;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.persistence.FileTxnLog;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.persistence.TxnLog.TxnIterator;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;\nimport org.apache.zookeeper.txn.SetDataTxn;\nimport org.apache.zookeeper.txn.TxnHeader;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TruncateTest extends ZKTestCase {\n\tprivate static final Logger LOG = LoggerFactory.getLogger(TruncateTest.class);\n    File dataDir1, dataDir2, dataDir3;\n    final int baseHostPort = PortAssignment.unique();\n    \n    @Before\n    public void setUp() throws IOException {\n        dataDir1 = ClientBase.createTmpDir();\n        dataDir2 = ClientBase.createTmpDir();\n        dataDir3 = ClientBase.createTmpDir();\n    }\n    \n    @After\n    public void tearDown() {\n        ClientBase.recursiveDelete(dataDir1);\n        ClientBase.recursiveDelete(dataDir2);\n        ClientBase.recursiveDelete(dataDir3);\n    }\n    \n    volatile boolean connected;\n    Watcher nullWatcher = new Watcher() {\n        @Override\n        public void process(WatchedEvent event) {\n            connected = event.getState() == Watcher.Event.KeeperState.SyncConnected;\n        }\n    };\n\n    @Test\n    public void testTruncationStreamReset() throws Exception {\n        File tmpdir = ClientBase.createTmpDir();\n        FileTxnSnapLog snaplog = new FileTxnSnapLog(tmpdir, tmpdir);\n        ZKDatabase zkdb = new ZKDatabase(snaplog);\n\n        for (int i = 1; i <= 100; i++) {\n            append(zkdb, i);\n        }\n\n        zkdb.truncateLog(1);\n\n        append(zkdb, 200);\n\n        zkdb.close();\n\n        // verify that the truncation and subsequent append were processed\n        // correctly\n        FileTxnLog txnlog = new FileTxnLog(new File(tmpdir, \"version-2\"));\n        TxnIterator iter = txnlog.read(1);\n\n        TxnHeader hdr = iter.getHeader();\n        Record txn = iter.getTxn();\n        Assert.assertEquals(1, hdr.getZxid());\n        Assert.assertTrue(txn instanceof SetDataTxn);\n\n        iter.next();\n\n        hdr = iter.getHeader();\n        txn = iter.getTxn();\n        Assert.assertEquals(200, hdr.getZxid());\n        Assert.assertTrue(txn instanceof SetDataTxn);\n        iter.close();\n        ClientBase.recursiveDelete(tmpdir);\n    }\n\n    private void append(ZKDatabase zkdb, int i) throws IOException {\n        TxnHeader hdr = new TxnHeader(1, 1, i, 1, ZooDefs.OpCode.setData);\n        Record txn = new SetDataTxn(\"/foo\" + i, new byte[0], 1);\n        Request req = new Request(null, 0, 0, 0, null, null);\n        req.hdr = hdr;\n        req.txn = txn;\n\n        zkdb.append(req);\n        zkdb.commit();\n    }\n\n    \n    @Test\n    public void testTruncationNullLog() throws Exception {\n        File tmpdir = ClientBase.createTmpDir();\n        FileTxnSnapLog snaplog = new FileTxnSnapLog(tmpdir, tmpdir);\n        ZKDatabase zkdb = new ZKDatabase(snaplog);\n\n        for (int i = 1; i <= 100; i++) {\n            append(zkdb, i);\n        }\n        zkdb.close();\n        File[] logs = snaplog.getDataDir().listFiles();\n        for(int i = 0; i < logs.length; i++) {\n            LOG.debug(\"Deleting: {}\", logs[i].getName());\n            Assert.assertTrue(\"Failed to delete log file: \" + logs[i].getName(), logs[i].delete());\n        }\n        try {\n            zkdb.truncateLog(1);\n            Assert.assertTrue(\"Should not get here\", false);\n        }\n        catch(IOException e) {\n            Assert.assertTrue(\"Should have received an IOException\", true);\n        }\n        catch(NullPointerException npe) {\n            Assert.fail(\"This should not throw NPE!\");\n        }\n \n        ClientBase.recursiveDelete(tmpdir);\n    }\n    \n    @Test\n    public void testTruncate() throws IOException, InterruptedException, KeeperException {\n        // Prime the server that is going to come in late with 50 txns\n        String hostPort = \"127.0.0.1:\" + baseHostPort;\n        int maxCnxns = 100;\n        ServerCnxnFactory factory = ClientBase.createNewServerInstance(null,\n                hostPort, maxCnxns);\n        ClientBase.startServerInstance(dataDir1, factory, hostPort);\n        ClientBase.shutdownServerInstance(factory, hostPort);\n\n        // standalone starts with 0 epoch while quorum starts with 1\n        File origfile = new File(new File(dataDir1, \"version-2\"), \"snapshot.0\");\n        File newfile = new File(new File(dataDir1, \"version-2\"), \"snapshot.100000000\");\n        origfile.renameTo(newfile);\n\n        factory = ClientBase.createNewServerInstance(null, hostPort, maxCnxns);\n        ClientBase.startServerInstance(dataDir1, factory, hostPort);\n\n        ZooKeeper zk = new ZooKeeper(hostPort, 15000, nullWatcher);\n        for(int i = 0; i < 50; i++) {\n            zk.create(\"/\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n        \n        ZKDatabase zkDb;\n        {\n            ZooKeeperServer zs = ClientBase.getServer(factory);\n    \n            zkDb = zs.getZKDatabase();\n        }\n        factory.shutdown();\n        try {\n            zkDb.close();\n        } catch (IOException ie) {\n            LOG.warn(\"Error closing logs \", ie);\n        }\n        int tickTime = 2000;\n        int initLimit = 3;\n        int syncLimit = 3;\n        int port1 = baseHostPort+1;\n        int port2 = baseHostPort+2;\n        int port3 = baseHostPort+3;\n        \n        // Start up two of the quorum and add 10 txns\n        HashMap<Long,QuorumServer> peers = new HashMap<Long,QuorumServer>();\n        peers.put(Long.valueOf(1), new QuorumServer(1, \"127.0.0.1\", port1 + 1000, 0, null));\n        peers.put(Long.valueOf(2), new QuorumServer(2, \"127.0.0.1\", port2 + 1000, 0, null));\n        peers.put(Long.valueOf(3), new QuorumServer(3, \"127.0.0.1\", port3 + 1000, 0, null));\n\n        QuorumPeer s2 = new QuorumPeer(peers, dataDir2, dataDir2, port2, 0, 2, tickTime, initLimit, syncLimit);\n        s2.start();\n        QuorumPeer s3 = new QuorumPeer(peers, dataDir3, dataDir3, port3, 0, 3, tickTime, initLimit, syncLimit);\n        s3.start();\n        connected = false;\n        zk = new ZooKeeper(\"127.0.0.1:\" + port2, 15000, nullWatcher);\n        while(!connected) {\n            Thread.sleep(1000);\n        }\n        for(int i = 0; i < 10; i++) {\n            zk.create(\"/\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        }\n        zk.close();\n        \n        final ZooKeeper zk2 = new ZooKeeper(\"127.0.0.1:\" + port2, 15000, nullWatcher);\n        zk2.getData(\"/9\", false, new Stat());\n        try {\n            zk2.getData(\"/10\", false, new Stat());\n            Assert.fail(\"Should have gotten an error\");\n        } catch(KeeperException.NoNodeException e) {\n            // this is what we want\n        }\n        QuorumPeer s1 = new QuorumPeer(peers, dataDir1, dataDir1, port1, 0, 1, tickTime, initLimit, syncLimit);\n        s1.start();\n\n        connected = false;\n        ZooKeeper zk1 = new ZooKeeper(\"127.0.0.1:\" + port1, 15000, nullWatcher);\n        while(!connected) {\n            Thread.sleep(1000);\n        }\n        zk1.getData(\"/9\", false, new Stat());\n        try {\n            // /10 wont work because the session expiration\n            // will match the zxid for /10 and so we wont\n            // actually truncate the zxid for /10 creation\n            // due to an artifact of switching the xid of the standalone\n            // /11 is the last entry in the log for the xid\n            // as a result /12 is the first of the truncated znodes to check for\n            zk1.getData(\"/12\", false, new Stat());\n            Assert.fail(\"Should have gotten an error\");\n        } catch(KeeperException.NoNodeException e) {\n            // this is what we want\n        }\n        zk1.close();\n        QuorumBase.shutdown(s1);\n        QuorumBase.shutdown(s2);\n        QuorumBase.shutdown(s3);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/UpgradeTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.PortAssignment;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ServerCnxnFactory;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.apache.zookeeper.server.upgrade.UpgradeMain;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class UpgradeTest extends ZKTestCase implements Watcher {\n    private final static Logger LOG = LoggerFactory.getLogger(UpgradeTest.class);\n\n    private static String HOSTPORT = \"127.0.0.1:\" + PortAssignment.unique();\n    private static final File testData = new File(\n            System.getProperty(\"test.data.dir\", \"build/test/data\"));\n    private CountDownLatch startSignal;\n\n    /**\n     * test the upgrade\n     * @throws Exception\n     */\n    @Test\n    public void testUpgrade() throws Exception {\n        File upgradeDir = new File(testData, \"upgrade\");\n        UpgradeMain upgrade = new UpgradeMain(upgradeDir, upgradeDir);\n        upgrade.runUpgrade();\n        ZooKeeperServer zks = new ZooKeeperServer(upgradeDir, upgradeDir, 3000);\n        SyncRequestProcessor.setSnapCount(1000);\n        final int PORT = Integer.parseInt(HOSTPORT.split(\":\")[1]);\n        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);\n        f.startup(zks);\n        LOG.info(\"starting up the zookeeper server .. waiting\");\n        Assert.assertTrue(\"waiting for server being up\",\n                ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));\n        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);\n        Stat stat = zk.exists(\"/\", false);\n        List<String> children = zk.getChildren(\"/\", false);\n        Collections.sort(children);\n        for (int i = 0; i < 10; i++) {\n            Assert.assertTrue(\"data tree sanity check\",\n                    (\"test-\" + i).equals(children.get(i)));\n        }\n        //try creating one node\n        zk.create(\"/upgrade\", \"upgrade\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        // check if its there\n        if (zk.exists(\"/upgrade\", false) == null) {\n            Assert.assertTrue(false);\n        }\n\n        zk.close();\n\n        // bring down the server\n        f.shutdown();\n        Assert.assertTrue(\"waiting for server down\",\n                   ClientBase.waitForServerDown(HOSTPORT,\n                           ClientBase.CONNECTION_TIMEOUT));\n\n    }\n\n    public void process(WatchedEvent event) {\n        LOG.info(\"Event:\" + event.getState() + \" \" + event.getType() + \" \" + event.getPath());\n        if (event.getState() == KeeperState.SyncConnected\n                && startSignal != null && startSignal.getCount() > 0)\n        {\n            startSignal.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/WatchEventWhenAutoReset.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.test.ClientBase.CountdownWatcher;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport junit.framework.TestCase;\n\npublic class WatchEventWhenAutoReset extends TestCase {\n    protected static final Logger LOG = LoggerFactory\n            .getLogger(WatchEventWhenAutoReset.class);\n\n    // waiting time for expected condition\n    private static final int TIMEOUT = 30000;\n\n    static public class EventsWatcher extends CountdownWatcher {\n        private LinkedBlockingQueue<WatchedEvent> dataEvents = new LinkedBlockingQueue<WatchedEvent>();\n\n        @Override\n        public void process(WatchedEvent event) {\n            super.process(event);\n            try {\n                if (event.getType() != Event.EventType.None) {\n                    dataEvents.put(event);\n                }\n            } catch (InterruptedException e) {\n                LOG.warn(\"ignoring interrupt during EventsWatcher process\");\n            }\n        }\n\n        public void assertEvent(long timeout, EventType eventType) {\n            try {\n                WatchedEvent event = dataEvents.poll(timeout,\n                        TimeUnit.MILLISECONDS);\n                Assert.assertNotNull(\"do not receive a \" + eventType, event);\n                Assert.assertEquals(eventType, event.getType());\n            } catch (InterruptedException e) {\n                LOG.warn(\"ignoring interrupt during EventsWatcher assertEvent\");\n            }\n        }\n    }\n\n    private ZooKeeper createClient(QuorumUtil qu, int id, EventsWatcher watcher)\n            throws IOException {\n        String hostPort = \"127.0.0.1:\" + qu.getPeer(id).clientPort;\n        ZooKeeper zk = new ZooKeeper(hostPort, TIMEOUT, watcher);\n        try {\n            watcher.waitForConnected(TIMEOUT);\n        } catch (InterruptedException e) {\n            // ignoring the interrupt\n        } catch (TimeoutException e) {\n            fail(\"can not connect to \" + hostPort);\n        }\n        return zk;\n    }\n\n    private ZooKeeper createClient(QuorumUtil qu, int id) throws IOException {\n        return createClient(qu, id, new EventsWatcher());\n    }\n\n    @Test\n    public void testNodeDataChanged() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        EventsWatcher watcher = new EventsWatcher();\n        ZooKeeper zk1 = createClient(qu, 1, watcher);\n        ZooKeeper zk2 = createClient(qu, 2);\n\n        String path = \"/test-changed\";\n\n        zk1.create(path, new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.getData(path, watcher, null);\n        qu.shutdown(1);\n        zk2.delete(path, -1);\n        zk2.create(path, new byte[2], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT);\n        watcher.assertEvent(TIMEOUT, EventType.NodeDataChanged);\n\n        zk1.exists(path, watcher);\n        qu.shutdown(1);\n        zk2.delete(path, -1);\n        zk2.create(path, new byte[2], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeDataChanged);\n\n        qu.shutdownAll();\n    }\n\n    @Test\n    public void testNodeCreated() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        EventsWatcher watcher = new EventsWatcher();\n        ZooKeeper zk1 = createClient(qu, 1, watcher);\n        ZooKeeper zk2 = createClient(qu, 2);\n\n        String path = \"/test1-created\";\n\n        zk1.exists(path, watcher);\n        qu.shutdown(1);\n        zk2.create(path, new byte[2], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeCreated);\n\n        qu.shutdownAll();\n    }\n\n    @Test\n    public void testNodeDeleted() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        EventsWatcher watcher = new EventsWatcher();\n        ZooKeeper zk1 = createClient(qu, 1, watcher);\n        ZooKeeper zk2 = createClient(qu, 2);\n\n        String path = \"/test-deleted\";\n\n        zk1.create(path, new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.getData(path, watcher, null);\n        qu.shutdown(1);\n        zk2.delete(path, -1);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeDeleted);\n\n        zk1.create(path, new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.exists(path, watcher);\n        qu.shutdown(1);\n        zk2.delete(path, -1);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeDeleted);\n\n        zk1.create(path, new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.getChildren(path, watcher);\n        qu.shutdown(1);\n        zk2.delete(path, -1);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeDeleted);\n\n        qu.shutdownAll();\n    }\n\n    @Test\n    public void testNodeChildrenChanged() throws Exception {\n        QuorumUtil qu = new QuorumUtil(1);\n        qu.startAll();\n\n        EventsWatcher watcher = new EventsWatcher();\n        ZooKeeper zk1 = createClient(qu, 1, watcher);\n        ZooKeeper zk2 = createClient(qu, 2);\n\n        String path = \"/test-children-changed\";\n\n        zk1.create(path, new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk1.getChildren(path, watcher);\n        qu.shutdown(1);\n        zk2.create(path + \"/children-1\", new byte[2],\n                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        qu.start(1);\n        watcher.waitForConnected(TIMEOUT * 1000L);\n        watcher.assertEvent(TIMEOUT, EventType.NodeChildrenChanged);\n\n        qu.shutdownAll();\n    }\n}\n\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/WatchedEventTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.util.EnumSet;\n\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.proto.WatcherEvent;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class WatchedEventTest extends ZKTestCase {\n    \n    @Test\n    public void testCreatingWatchedEvent() {\n        // EventWatch is a simple, immutable type, so all we need to do\n       // is make sure we can create all possible combinations of values.\n\n        EnumSet<EventType> allTypes = EnumSet.allOf(EventType.class);\n       EnumSet<KeeperState> allStates = EnumSet.allOf(KeeperState.class);\n       WatchedEvent we;\n\n        for(EventType et : allTypes) {\n           for(KeeperState ks : allStates) {\n               we = new WatchedEvent(et, ks, \"blah\");\n               Assert.assertEquals(et, we.getType());\n               Assert.assertEquals(ks, we.getState());\n               Assert.assertEquals(\"blah\", we.getPath());\n           }\n            \n        }\n    }\n\n    @Test\n    public void testCreatingWatchedEventFromWrapper() {\n        // Make sure we can handle any type of correct wrapper\n\n        EnumSet<EventType> allTypes = EnumSet.allOf(EventType.class);\n       EnumSet<KeeperState> allStates = EnumSet.allOf(KeeperState.class);\n       WatchedEvent we;\n       WatcherEvent wep;\n\n        for(EventType et : allTypes) {\n           for(KeeperState ks : allStates) {\n               wep = new WatcherEvent(et.getIntValue(), ks.getIntValue(), \"blah\");\n               we = new WatchedEvent(wep);\n               Assert.assertEquals(et, we.getType());\n               Assert.assertEquals(ks, we.getState());\n               Assert.assertEquals(\"blah\", we.getPath());\n           }\n        }\n    }\n\n    @Test\n    public void testCreatingWatchedEventFromInvalidWrapper() {\n        // Make sure we can't convert from an invalid wrapper\n\n       try {\n           WatcherEvent wep = new WatcherEvent(-2342, -252352, \"foo\");\n           WatchedEvent we = new WatchedEvent(wep);\n           Assert.fail(\"Was able to create WatchedEvent from bad wrapper\");\n       } catch (RuntimeException re) {\n           // we're good\n       }\n    }\n\n   @Test\n   public void testConvertingToEventWrapper() {\n       WatchedEvent we = new WatchedEvent(EventType.NodeCreated, KeeperState.Expired, \"blah\");\n       WatcherEvent wew = we.getWrapper();\n       \n       Assert.assertEquals(EventType.NodeCreated.getIntValue(), wew.getType());\n       Assert.assertEquals(KeeperState.Expired.getIntValue(), wew.getState());\n       Assert.assertEquals(\"blah\", wew.getPath());\n   }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/WatcherFuncTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class WatcherFuncTest extends ClientBase {\n    private static class SimpleWatcher implements Watcher {\n        private LinkedBlockingQueue<WatchedEvent> events =\n            new LinkedBlockingQueue<WatchedEvent>();\n        private CountDownLatch latch;\n\n        public SimpleWatcher(CountDownLatch latch) {\n            this.latch = latch;\n        }\n\n        public void process(WatchedEvent event) {\n            if (event.getState() == KeeperState.SyncConnected) {\n                if (latch != null) {\n                    latch.countDown();\n                }\n            }\n\n            if (event.getType() == EventType.None) {\n                return;\n            }\n            try {\n                events.put(event);\n            } catch (InterruptedException e) {\n                Assert.assertTrue(\"interruption unexpected\", false);\n            }\n        }\n        public void verify(List<EventType> expected) throws InterruptedException{\n            WatchedEvent event;\n            int count = 0;\n            while (count < expected.size()\n                    && (event = events.poll(30, TimeUnit.SECONDS)) != null)\n            {\n                Assert.assertEquals(expected.get(count), event.getType());\n                count++;\n            }\n            Assert.assertEquals(expected.size(), count);\n            events.clear();\n        }\n    }\n    private SimpleWatcher client_dwatch;\n    private volatile CountDownLatch client_latch;\n    private ZooKeeper client;\n    private SimpleWatcher lsnr_dwatch;\n    private volatile CountDownLatch lsnr_latch;\n    private ZooKeeper lsnr;\n\n    private List<EventType> expected;\n\n    @Override\n    public void setUp() throws Exception {\n        super.setUp();\n\n        client_latch = new CountDownLatch(1);\n        client_dwatch = new SimpleWatcher(client_latch);\n        client = createClient(client_dwatch, client_latch);\n\n        lsnr_latch = new CountDownLatch(1);\n        lsnr_dwatch = new SimpleWatcher(lsnr_latch);\n        lsnr = createClient(lsnr_dwatch, lsnr_latch);\n\n        expected = new ArrayList<EventType>();\n    }\n\n    @Override\n    public void tearDown() throws Exception {\n        client.close();\n        lsnr.close();\n        super.tearDown();\n    }\n\n    protected ZooKeeper createClient(Watcher watcher, CountDownLatch latch)\n        throws IOException, InterruptedException\n    {\n        ZooKeeper zk = new ZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);\n        if(!latch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)){\n            Assert.fail(\"Unable to connect to server\");\n        }\n        return zk;\n    }\n\n    private void verify() throws InterruptedException {\n        lsnr_dwatch.verify(expected);\n        expected.clear();\n    }\n\n    @Test\n    public void testExistsSync()\n        throws IOException, InterruptedException, KeeperException\n    {\n        Assert.assertNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNull(lsnr.exists(\"/foo/bar\", true));\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        expected.add(EventType.NodeCreated);\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        expected.add(EventType.NodeCreated);\n\n        verify();\n\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", true));\n\n        try {\n            Assert.assertNull(lsnr.exists(\"/car\", true));\n            client.setData(\"/car\", \"missing\".getBytes(), -1);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/car\", e.getPath());\n        }\n\n        try {\n            Assert.assertNull(lsnr.exists(\"/foo/car\", true));\n            client.setData(\"/foo/car\", \"missing\".getBytes(), -1);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo/car\", e.getPath());\n        }\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n\n        verify();\n\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", true));\n\n        client.delete(\"/foo/bar\", -1);\n        expected.add(EventType.NodeDeleted);\n        client.delete(\"/foo\", -1);\n        expected.add(EventType.NodeDeleted);\n\n        verify();\n    }\n\n    @Test\n    public void testGetDataSync()\n        throws IOException, InterruptedException, KeeperException\n    {\n        try {\n            lsnr.getData(\"/foo\", true, null);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo\", e.getPath());\n        }\n        try {\n            lsnr.getData(\"/foo/bar\", true, null);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo/bar\", e.getPath());\n        }\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getData(\"/foo\", true, null));\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", true, null));\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n\n        verify();\n\n        Assert.assertNotNull(lsnr.getData(\"/foo\", true, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", true, null));\n\n        client.delete(\"/foo/bar\", -1);\n        expected.add(EventType.NodeDeleted);\n        client.delete(\"/foo\", -1);\n        expected.add(EventType.NodeDeleted);\n\n        verify();\n    }\n\n    @Test\n    public void testGetChildrenSync()\n        throws IOException, InterruptedException, KeeperException\n    {\n        try {\n            lsnr.getChildren(\"/foo\", true);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo\", e.getPath());\n        }\n        try {\n            lsnr.getChildren(\"/foo/bar\", true);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo/bar\", e.getPath());\n        }\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", true));\n\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        expected.add(EventType.NodeChildrenChanged); // /foo\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", true));\n\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n\n\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", true));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", true));\n\n        client.delete(\"/foo/bar\", -1);\n        expected.add(EventType.NodeDeleted); // /foo/bar childwatch\n        expected.add(EventType.NodeChildrenChanged); // /foo\n        client.delete(\"/foo\", -1);\n        expected.add(EventType.NodeDeleted);\n\n        verify();\n    }\n\n    @Test\n    public void testExistsSyncWObj()\n        throws IOException, InterruptedException, KeeperException\n    {\n        SimpleWatcher w1 = new SimpleWatcher(null);\n        SimpleWatcher w2 = new SimpleWatcher(null);\n        SimpleWatcher w3 = new SimpleWatcher(null);\n        SimpleWatcher w4 = new SimpleWatcher(null);\n\n        List<EventType> e2 = new ArrayList<EventType>();\n\n        Assert.assertNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNull(lsnr.exists(\"/foo\", w1));\n\n        Assert.assertNull(lsnr.exists(\"/foo/bar\", w2));\n        Assert.assertNull(lsnr.exists(\"/foo/bar\", w3));\n        Assert.assertNull(lsnr.exists(\"/foo/bar\", w3));\n        Assert.assertNull(lsnr.exists(\"/foo/bar\", w4));\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        expected.add(EventType.NodeCreated);\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        e2.add(EventType.NodeCreated);\n\n        lsnr_dwatch.verify(expected);\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n\n        // default not registered\n        Assert.assertNotNull(lsnr.exists(\"/foo\", w1));\n\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w3));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w4));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w4));\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n        e2.add(EventType.NodeDataChanged);\n\n        lsnr_dwatch.verify(new ArrayList<EventType>()); // not reg so should = 0\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNotNull(lsnr.exists(\"/foo\", w1));\n        Assert.assertNotNull(lsnr.exists(\"/foo\", w1));\n\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w3));\n        Assert.assertNotNull(lsnr.exists(\"/foo/bar\", w4));\n\n        client.delete(\"/foo/bar\", -1);\n        expected.add(EventType.NodeDeleted);\n        client.delete(\"/foo\", -1);\n        e2.add(EventType.NodeDeleted);\n\n        lsnr_dwatch.verify(expected);\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n\n    }\n\n    @Test\n    public void testGetDataSyncWObj()\n        throws IOException, InterruptedException, KeeperException\n    {\n        SimpleWatcher w1 = new SimpleWatcher(null);\n        SimpleWatcher w2 = new SimpleWatcher(null);\n        SimpleWatcher w3 = new SimpleWatcher(null);\n        SimpleWatcher w4 = new SimpleWatcher(null);\n\n        List<EventType> e2 = new ArrayList<EventType>();\n\n        try {\n            lsnr.getData(\"/foo\", w1, null);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo\", e.getPath());\n        }\n        try {\n            lsnr.getData(\"/foo/bar\", w2, null);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo/bar\", e.getPath());\n        }\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getData(\"/foo\", true, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo\", w1, null));\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w2, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w3, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w4, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w4, null));\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        expected.add(EventType.NodeDataChanged);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n        e2.add(EventType.NodeDataChanged);\n\n        lsnr_dwatch.verify(expected);\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n\n        Assert.assertNotNull(lsnr.getData(\"/foo\", true, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo\", w1, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w2, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w3, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w3, null));\n        Assert.assertNotNull(lsnr.getData(\"/foo/bar\", w4, null));\n\n        client.delete(\"/foo/bar\", -1);\n        expected.add(EventType.NodeDeleted);\n        client.delete(\"/foo\", -1);\n        e2.add(EventType.NodeDeleted);\n\n        lsnr_dwatch.verify(expected);\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n    }\n\n    @Test\n    public void testGetChildrenSyncWObj()\n        throws IOException, InterruptedException, KeeperException\n    {\n        SimpleWatcher w1 = new SimpleWatcher(null);\n        SimpleWatcher w2 = new SimpleWatcher(null);\n        SimpleWatcher w3 = new SimpleWatcher(null);\n        SimpleWatcher w4 = new SimpleWatcher(null);\n\n        List<EventType> e2 = new ArrayList<EventType>();\n\n        try {\n            lsnr.getChildren(\"/foo\", true);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo\", e.getPath());\n        }\n        try {\n            lsnr.getChildren(\"/foo/bar\", true);\n            Assert.fail();\n        } catch (KeeperException e) {\n            Assert.assertEquals(KeeperException.Code.NONODE, e.code());\n            Assert.assertEquals(\"/foo/bar\", e.getPath());\n        }\n\n        client.create(\"/foo\", \"parent\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", true));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", w1));\n\n        client.create(\"/foo/bar\", \"child\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n        expected.add(EventType.NodeChildrenChanged); // /foo\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w3));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w4));\n\n\n        client.setData(\"/foo\", \"parent\".getBytes(), -1);\n        client.setData(\"/foo/bar\", \"child\".getBytes(), -1);\n\n\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNotNull(lsnr.exists(\"/foo\", w1));\n        Assert.assertNotNull(lsnr.exists(\"/foo\", true));\n        Assert.assertNotNull(lsnr.exists(\"/foo\", w1));\n\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", true));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo\", w1));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w2));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w3));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w4));\n        Assert.assertNotNull(lsnr.getChildren(\"/foo/bar\", w4));\n\n        client.delete(\"/foo/bar\", -1);\n        e2.add(EventType.NodeDeleted); // /foo/bar childwatch\n        expected.add(EventType.NodeChildrenChanged); // /foo\n        client.delete(\"/foo\", -1);\n        expected.add(EventType.NodeDeleted);\n\n        lsnr_dwatch.verify(expected);\n        w1.verify(expected);\n        w2.verify(e2);\n        w3.verify(e2);\n        w4.verify(e2);\n        expected.clear();\n        e2.clear();\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/WatcherTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.ClientCnxn;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.TestableZooKeeper;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.AsyncCallback.StatCallback;\nimport org.apache.zookeeper.AsyncCallback.VoidCallback;\nimport org.apache.zookeeper.Watcher.Event;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class WatcherTest extends ClientBase {\n    protected static final Logger LOG = LoggerFactory.getLogger(WatcherTest.class);\n\n    private long timeOfLastWatcherInvocation;\n\n    private final class MyStatCallback implements StatCallback {\n        int rc;\n        public void processResult(int rc, String path, Object ctx, Stat stat) {\n            ((int[])ctx)[0]++;\n            this.rc = rc;\n        }\n    }\n\n    private class MyWatcher extends CountdownWatcher {\n        LinkedBlockingQueue<WatchedEvent> events =\n            new LinkedBlockingQueue<WatchedEvent>();\n\n        public void process(WatchedEvent event) {\n            super.process(event);\n            if (event.getType() != Event.EventType.None) {\n                timeOfLastWatcherInvocation = System.currentTimeMillis();\n                try {\n                    events.put(event);\n                } catch (InterruptedException e) {\n                    LOG.warn(\"ignoring interrupt during event.put\");\n                }\n            }\n        }\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        super.setUp();\n        // Reset to default value since some test cases set this to true.\n        // Needed for JDK7 since unit test can run is random order\n        ClientCnxn.setDisableAutoResetWatch(false);\n    }\n\n    /**\n     * Verify that we get all of the events we expect to get. This particular\n     * case verifies that we see all of the data events on a particular node.\n     * There was a bug (ZOOKEEPER-137) that resulted in events being dropped\n     * in some cases (timing).\n     *\n     * @throws IOException\n     * @throws InterruptedException\n     * @throws KeeperException\n     */\n    @Test\n    public void testWatcherCorrectness()\n        throws IOException, InterruptedException, KeeperException\n    {\n        ZooKeeper zk = null;\n        try {\n            MyWatcher watcher = new MyWatcher();\n            zk = createClient(watcher, hostPort);\n\n            StatCallback scb = new StatCallback() {\n                public void processResult(int rc, String path, Object ctx,\n                        Stat stat) {\n                    // don't do anything\n                }\n            };\n            VoidCallback vcb = new VoidCallback() {\n                public void processResult(int rc, String path, Object ctx) {\n                    // don't do anything\n                }\n            };\n\n            String names[] = new String[10];\n            for (int i = 0; i < names.length; i++) {\n                String name = zk.create(\"/tc-\", \"initialvalue\".getBytes(),\n                        Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                names[i] = name;\n\n                Stat stat = new Stat();\n                zk.getData(name, watcher, stat);\n                zk.setData(name, \"new\".getBytes(), stat.getVersion(), scb, null);\n                stat = zk.exists(name, watcher);\n                zk.delete(name, stat.getVersion(), vcb, null);\n            }\n\n            for (int i = 0; i < names.length; i++) {\n                String name = names[i];\n                WatchedEvent event = watcher.events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(name, event.getPath());\n                Assert.assertEquals(Event.EventType.NodeDataChanged, event.getType());\n                Assert.assertEquals(Event.KeeperState.SyncConnected, event.getState());\n                event = watcher.events.poll(10, TimeUnit.SECONDS);\n                Assert.assertEquals(name, event.getPath());\n                Assert.assertEquals(Event.EventType.NodeDeleted, event.getType());\n                Assert.assertEquals(Event.KeeperState.SyncConnected, event.getState());\n            }\n        } finally {\n            if (zk != null) {\n                zk.close();\n            }\n        }\n    }\n\n    @Test\n    public void testWatcherCount() \n    throws IOException, InterruptedException, KeeperException {\n        ZooKeeper zk1 = null, zk2 = null;\n        try {\n            MyWatcher w1 = new MyWatcher();\n            zk1 = createClient(w1, hostPort);\n\n            MyWatcher w2 = new MyWatcher();\n            zk2 = createClient(w2, hostPort);\n\n            Stat stat = new Stat();\n            zk1.create(\"/watch-count-test\", \"value\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n            zk1.create(\"/watch-count-test-2\", \"value\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n\n            zk1.getData(\"/watch-count-test\", w1, stat);\n            zk1.getData(\"/watch-count-test-2\", w1, stat);\n            zk2.getData(\"/watch-count-test\", w2, stat);\n\n            Assert.assertEquals(ClientBase.getServer(serverFactory)\n                    .getZKDatabase().getDataTree().getWatchCount(), 3);\n\n        } finally {\n            if(zk1 != null) {\n                zk1.close();\n            }\n            if(zk2 != null) {\n                zk2.close();\n            }\n        }\n\n    }\n\n    final static int COUNT = 100;\n    /**\n     * This test checks that watches for pending requests do not get triggered,\n     * but watches set by previous requests do.\n     *\n     * @throws Exception\n     */\n    @Test\n    public void testWatchAutoResetWithPending() throws Exception {\n       MyWatcher watches[] = new MyWatcher[COUNT];\n       MyStatCallback cbs[] = new MyStatCallback[COUNT];\n       MyWatcher watcher = new MyWatcher();\n       int count[] = new int[1];\n       TestableZooKeeper zk = createClient(watcher, hostPort, 6000);\n       ZooKeeper zk2 = createClient(watcher, hostPort, 5000);\n       zk2.create(\"/test\", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n       for(int i = 0; i < COUNT/2; i++) {\n           watches[i] = new MyWatcher();\n           cbs[i] = new MyStatCallback();\n           zk.exists(\"/test\", watches[i], cbs[i], count);\n       }\n       zk.exists(\"/test\", false);\n       Assert.assertTrue(\"Failed to pause the connection!\", zk.pauseCnxn(3000));\n       zk2.close();\n       stopServer();\n       watches[0].waitForDisconnected(60000);\n       for(int i = COUNT/2; i < COUNT; i++) {\n           watches[i] = new MyWatcher();\n           cbs[i] = new MyStatCallback();\n           zk.exists(\"/test\", watches[i], cbs[i], count);\n       }\n       startServer();\n       watches[COUNT/2-1].waitForConnected(60000);\n       Assert.assertEquals(null, zk.exists(\"/test\", false));\n       waitForAllWatchers();\n       for(int i = 0; i < COUNT/2; i++) {\n           Assert.assertEquals(\"For \" + i, 1, watches[i].events.size());\n       }\n       for(int i = COUNT/2; i < COUNT; i++) {\n           if (cbs[i].rc == 0) {\n               Assert.assertEquals(\"For \" +i, 1, watches[i].events.size());\n           } else {\n               Assert.assertEquals(\"For \" +i, 0, watches[i].events.size());\n           }\n       }\n       Assert.assertEquals(COUNT, count[0]);\n       zk.close();\n    }\n\n    /**\n     * Wait until no watcher has been fired in the last second to ensure that all watches\n     * that are waiting to be fired have been fired\n     * @throws Exception\n     */\n    private void waitForAllWatchers() throws Exception {\n        timeOfLastWatcherInvocation = System.currentTimeMillis();\n        while (System.currentTimeMillis() - timeOfLastWatcherInvocation < 1000) {\n            Thread.sleep(1000);\n        }\n    }\n    \n    final int TIMEOUT = 5000;\n\n    @Test\n    public void testWatcherAutoResetWithGlobal() throws Exception {\n        ZooKeeper zk = null;\n        MyWatcher watcher = new MyWatcher();\n        zk = createClient(watcher, hostPort, TIMEOUT);\n        testWatcherAutoReset(zk, watcher, watcher);\n        zk.close();\n    }\n\n    @Test\n    public void testWatcherAutoResetWithLocal() throws Exception {\n        ZooKeeper zk = null;\n        MyWatcher watcher = new MyWatcher();\n        zk = createClient(watcher, hostPort, TIMEOUT);\n        testWatcherAutoReset(zk, watcher, new MyWatcher());\n        zk.close();\n    }\n\n    @Test\n    public void testWatcherAutoResetDisabledWithGlobal() throws Exception {\n        ClientCnxn.setDisableAutoResetWatch(true);\n        testWatcherAutoResetWithGlobal();\n    }\n\n    @Test\n    public void testWatcherAutoResetDisabledWithLocal() throws Exception {\n        ClientCnxn.setDisableAutoResetWatch(true);\n        testWatcherAutoResetWithLocal();\n    }\n\n    private void testWatcherAutoReset(ZooKeeper zk, MyWatcher globalWatcher,\n            MyWatcher localWatcher) throws Exception {\n        boolean isGlobal = (localWatcher == globalWatcher);\n        // First test to see if the watch survives across reconnects\n        zk.create(\"/watchtest\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        zk.create(\"/watchtest/child\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.EPHEMERAL);\n        if (isGlobal) {\n            zk.getChildren(\"/watchtest\", true);\n            zk.getData(\"/watchtest/child\", true, new Stat());\n            zk.exists(\"/watchtest/child2\", true);\n        } else {\n            zk.getChildren(\"/watchtest\", localWatcher);\n            zk.getData(\"/watchtest/child\", localWatcher, new Stat());\n            zk.exists(\"/watchtest/child2\", localWatcher);\n        }\n\n        Assert.assertTrue(localWatcher.events.isEmpty());\n\n        stopServer();\n        globalWatcher.waitForDisconnected(3000);\n        localWatcher.waitForDisconnected(500);\n        startServer();\n        globalWatcher.waitForConnected(3000);\n        if (!isGlobal && !ClientCnxn.getDisableAutoResetWatch()) {\n            localWatcher.waitForConnected(500);\n        }\n\n        Assert.assertTrue(localWatcher.events.isEmpty());\n        zk.setData(\"/watchtest/child\", new byte[1], -1);\n        zk.create(\"/watchtest/child2\", new byte[0], Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        WatchedEvent e;\n        if (!ClientCnxn.getDisableAutoResetWatch()) {\n            e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n            Assert.assertEquals(e.getPath(), EventType.NodeDataChanged, e.getType());\n            Assert.assertEquals(\"/watchtest/child\", e.getPath());\n        } else {\n            // we'll catch this later if it does happen after timeout, so\n            // why waste the time on poll\n        }\n\n        if (!ClientCnxn.getDisableAutoResetWatch()) {\n            e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n            // The create will trigger the get children and the exist\n            // watches\n            Assert.assertEquals(EventType.NodeCreated, e.getType());\n            Assert.assertEquals(\"/watchtest/child2\", e.getPath());\n        } else {\n            // we'll catch this later if it does happen after timeout, so\n            // why waste the time on poll\n        }\n\n        if (!ClientCnxn.getDisableAutoResetWatch()) {\n            e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n            Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n            Assert.assertEquals(\"/watchtest\", e.getPath());\n        } else {\n            // we'll catch this later if it does happen after timeout, so\n            // why waste the time on poll\n        }\n\n        Assert.assertTrue(localWatcher.events.isEmpty()); // ensure no late arrivals\n        stopServer();\n        globalWatcher.waitForDisconnected(TIMEOUT);\n        try {\n            try {\n                localWatcher.waitForDisconnected(500);\n                if (!isGlobal && !ClientCnxn.getDisableAutoResetWatch()) {\n                    Assert.fail(\"Got an event when I shouldn't have\");\n                }\n            } catch(TimeoutException toe) {\n                if (ClientCnxn.getDisableAutoResetWatch()) {\n                    Assert.fail(\"Didn't get an event when I should have\");\n                }\n                // Else what we are expecting since there are no outstanding watches\n            }\n        } catch (Exception e1) {\n            LOG.error(\"bad\", e1);\n            throw new RuntimeException(e1);\n        }\n        startServer();\n        globalWatcher.waitForConnected(TIMEOUT);\n\n        if (isGlobal) {\n            zk.getChildren(\"/watchtest\", true);\n            zk.getData(\"/watchtest/child\", true, new Stat());\n            zk.exists(\"/watchtest/child2\", true);\n        } else {\n            zk.getChildren(\"/watchtest\", localWatcher);\n            zk.getData(\"/watchtest/child\", localWatcher, new Stat());\n            zk.exists(\"/watchtest/child2\", localWatcher);\n        }\n\n        // Do trigger an event to make sure that we do not get\n        // it later\n        zk.delete(\"/watchtest/child2\", -1);\n\n        e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertEquals(EventType.NodeDeleted, e.getType());\n        Assert.assertEquals(\"/watchtest/child2\", e.getPath());\n\n        e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n        Assert.assertEquals(EventType.NodeChildrenChanged, e.getType());\n        Assert.assertEquals(\"/watchtest\", e.getPath());\n\n        Assert.assertTrue(localWatcher.events.isEmpty());\n\n        stopServer();\n        globalWatcher.waitForDisconnected(TIMEOUT);\n        localWatcher.waitForDisconnected(500);\n        startServer();\n        globalWatcher.waitForConnected(TIMEOUT);\n        if (!isGlobal && !ClientCnxn.getDisableAutoResetWatch()) {\n            localWatcher.waitForConnected(500);\n        }\n\n        zk.delete(\"/watchtest/child\", -1);\n        zk.delete(\"/watchtest\", -1);\n\n        if (!ClientCnxn.getDisableAutoResetWatch()) {\n            e = localWatcher.events.poll(TIMEOUT, TimeUnit.MILLISECONDS);\n            Assert.assertEquals(EventType.NodeDeleted, e.getType());\n            Assert.assertEquals(\"/watchtest/child\", e.getPath());\n        } else {\n            // we'll catch this later if it does happen after timeout, so\n            // why waste the time on poll\n        }\n\n        // Make sure nothing is straggling!\n        Thread.sleep(1000);\n        Assert.assertTrue(localWatcher.events.isEmpty());\n\n    }\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ZkDatabaseCorruptionTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.util.Arrays;\n\nimport org.apache.zookeeper.AsyncCallback;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.server.SyncRequestProcessor;\nimport org.apache.zookeeper.server.persistence.FileTxnSnapLog;\nimport org.apache.zookeeper.server.quorum.QuorumPeer;\nimport org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ZkDatabaseCorruptionTest extends ZKTestCase {\n    protected static final Logger LOG = LoggerFactory.getLogger(ZkDatabaseCorruptionTest.class);\n    public static final long CONNECTION_TIMEOUT = ClientTest.CONNECTION_TIMEOUT;\n\n    private final QuorumBase qb = new QuorumBase();\n\n    @Before\n    public void setUp() throws Exception {\n        LOG.info(\"STARTING quorum \" + getClass().getName());\n        qb.setUp();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        LOG.info(\"STOPPING quorum \" + getClass().getName());\n    }\n\n    private void corruptFile(File f) throws IOException {\n        RandomAccessFile outFile = new RandomAccessFile(f, \"rw\");\n        outFile.write(\"fail servers\".getBytes());\n        outFile.close();\n    }\n\n    private void corruptAllSnapshots(File snapDir) throws IOException {\n        File[] listFiles = snapDir.listFiles();\n        for (File f: listFiles) {\n            if (f.getName().startsWith(\"snapshot\")) {\n                corruptFile(f);\n            }\n        }\n    }\n\n    private class NoopStringCallback implements AsyncCallback.StringCallback {\n        @Override\n        public void processResult(int rc, String path, Object ctx,\n                                  String name) {\n        }\n    }\n\n    @Test\n    public void testCorruption() throws Exception {\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ClientBase.waitForServerUp(qb.hostPort, 10000);\n        ZooKeeper zk = new ZooKeeper(qb.hostPort, 10000, new Watcher() {\n            public void process(WatchedEvent event) {\n            }});\n        SyncRequestProcessor.setSnapCount(100);\n        for (int i = 0; i < 2000; i++) {\n            zk.create(\"/0-\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                      CreateMode.PERSISTENT, new NoopStringCallback(), null);\n        }\n        zk.close();\n\n        long leaderSid = 1;\n        QuorumPeer leader = null;\n        //find out who is the leader and kill it\n        for (QuorumPeer quorumPeer : Arrays.asList(qb.s1, qb.s2, qb.s3, qb.s4, qb.s5)) {\n            if (quorumPeer.getPeerState() == ServerState.LEADING) {\n                leader = quorumPeer;\n                break;\n            }\n            ++leaderSid;\n        }\n\n        Assert.assertNotNull(\"Cannot find the leader.\", leader);\n        leader.shutdown();\n\n        // now corrupt the leader's database\n        FileTxnSnapLog snapLog = leader.getTxnFactory();\n        File snapDir= snapLog.getSnapDir();\n        //corrupt all the snapshot in the snapshot directory\n        corruptAllSnapshots(snapDir);\n        qb.shutdownServers();\n        qb.setupServers();\n\n        if (leaderSid != 1)qb.s1.start(); else leader = qb.s1;\n        if (leaderSid != 2)qb.s2.start(); else leader = qb.s2;\n        if (leaderSid != 3)qb.s3.start(); else leader = qb.s3;\n        if (leaderSid != 4)qb.s4.start(); else leader = qb.s4;\n        if (leaderSid != 5)qb.s5.start(); else leader = qb.s5;\n\n        try {\n            leader.start();\n            Assert.assertTrue(false);\n        } catch(RuntimeException re) {\n            LOG.info(\"Got an error: expected\", re);\n        }\n        //wait for servers to be up\n        String[] list = qb.hostPort.split(\",\");\n        for (int i = 0; i < 5; i++) {\n            if(leaderSid != (i + 1)) {\n                String hp = list[i];\n                Assert.assertTrue(\"waiting for server up\",\n                        ClientBase.waitForServerUp(hp,\n                                CONNECTION_TIMEOUT));\n                LOG.info(\"{} is accepting client connections\", hp);\n            } else {\n                LOG.info(\"Skipping the leader\");\n            }\n        }\n\n        zk = qb.createClient();\n        SyncRequestProcessor.setSnapCount(100);\n        for (int i = 2000; i < 4000; i++) {\n            zk.create(\"/0-\" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,\n                      CreateMode.PERSISTENT, new NoopStringCallback(), null);\n        }\n        zk.close();\n\n        if (leaderSid != 1)QuorumBase.shutdown(qb.s1);\n        if (leaderSid != 2)QuorumBase.shutdown(qb.s2);\n        if (leaderSid != 3)QuorumBase.shutdown(qb.s3);\n        if (leaderSid != 4)QuorumBase.shutdown(qb.s4);\n        if (leaderSid != 5)QuorumBase.shutdown(qb.s5);\n    }\n\n\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ZooKeeperQuotaTest.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.Quotas;\nimport org.apache.zookeeper.StatsTrack;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.ZooKeeperMain;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.server.ZooKeeperServer;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ZooKeeperQuotaTest extends ClientBase {\n\n\n    private static final Logger LOG = LoggerFactory.getLogger(\n            ZooKeeperQuotaTest.class);\n\n    @Test\n    public void testQuota() throws IOException,\n        InterruptedException, KeeperException, Exception {\n        final ZooKeeper zk = createClient();\n        final String path = \"/a/b/v\";\n        // making sure setdata works on /\n        zk.setData(\"/\", \"some\".getBytes(), -1);\n        zk.create(\"/a\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n\n        zk.create(\"/a/b/v/d\", \"some\".getBytes(), Ids.OPEN_ACL_UNSAFE,\n                CreateMode.PERSISTENT);\n        ZooKeeperMain.createQuota(zk, path, 5L, 10);\n\n        // see if its set\n        String absolutePath = Quotas.quotaZookeeper + path + \"/\" + Quotas.limitNode;\n        byte[] data = zk.getData(absolutePath, false, new Stat());\n        StatsTrack st = new StatsTrack(new String(data));\n        Assert.assertTrue(\"bytes are set\", st.getBytes() == 5L);\n        Assert.assertTrue(\"num count is set\", st.getCount() == 10);\n\n        String statPath = Quotas.quotaZookeeper + path + \"/\" + Quotas.statNode;\n        byte[] qdata = zk.getData(statPath, false, new Stat());\n        StatsTrack qst = new StatsTrack(new String(qdata));\n        Assert.assertTrue(\"bytes are set\", qst.getBytes() == 8L);\n        Assert.assertTrue(\"count is set\", qst.getCount() == 2);\n\n        //force server to restart and load from snapshot, not txn log\n        stopServer();\n        startServer();\n        stopServer();\n        startServer();\n        ZooKeeperServer server = getServer(serverFactory);\n        Assert.assertNotNull(\"Quota is still set\",\n            server.getZKDatabase().getDataTree().getMaxPrefixWithQuota(path) != null);\n    }\n}\n"
  },
  {
    "path": "src/java/test/org/apache/zookeeper/test/ZooKeeperTestClient.java",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.test;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZKTestCase;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.KeeperException.Code;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.common.Time;\nimport org.apache.zookeeper.data.Stat;\nimport org.junit.Assert;\n\npublic class ZooKeeperTestClient extends ZKTestCase implements Watcher {\n  protected String hostPort = \"127.0.0.1:22801\";\n\n  protected static final String dirOnZK = \"/test_dir\";\n\n  protected String testDirOnZK = dirOnZK + \"/\" + Time.currentElapsedTime();\n\n  LinkedBlockingQueue<WatchedEvent> events = new LinkedBlockingQueue<WatchedEvent>();\n\n  private WatchedEvent getEvent(int numTries) throws InterruptedException {\n    WatchedEvent event = null;\n    for (int i = 0; i < numTries; i++) {\n      System.out.println(\"i = \" + i);\n      event = events.poll(10, TimeUnit.SECONDS);\n      if (event != null) {\n        break;\n      }\n      Thread.sleep(5000);\n    }\n    return event;\n\n  }\n\n  private void deleteZKDir(ZooKeeper zk, String nodeName)\n          throws IOException, InterruptedException, KeeperException {\n\n    Stat stat = zk.exists(nodeName, false);\n    if (stat == null) {\n      return;\n    }\n\n    List<String> children1 = zk.getChildren(nodeName, false);\n    List<String> c2 = zk.getChildren(nodeName, false, stat);\n\n    if (!children1.equals(c2)) {\n        Assert.fail(\"children lists from getChildren()/getChildren2() do not match\");\n    }\n\n    if (!stat.equals(stat)) {\n        Assert.fail(\"stats from exists()/getChildren2() do not match\");\n    }\n\n    if (children1.size() == 0) {\n      zk.delete(nodeName, -1);\n      return;\n    }\n    for (String n : children1) {\n      deleteZKDir(zk, n);\n    }\n  }\n\n  private void checkRoot() throws IOException,\n      InterruptedException {\n    ZooKeeper zk = new ZooKeeper(hostPort, 10000, this);\n\n    try {\n      zk.create(dirOnZK, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n    } catch (KeeperException.NodeExistsException ke) {\n        // expected, sort of\n    } catch (KeeperException ke) {\n        Assert.fail(\"Unexpected exception code for create \" + dirOnZK + \": \"\n            + ke.getMessage());\n    }\n\n    try {\n      zk.create(testDirOnZK, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n    } catch (KeeperException.NodeExistsException ke) {\n        // expected, sort of\n    } catch (KeeperException ke) {\n        Assert.fail(\"Unexpected exception code for create \" + testDirOnZK + \": \"\n            + ke.getMessage());\n    }\n\n    zk.close();\n  }\n\n  private void enode_test_1() throws IOException,\n          InterruptedException, KeeperException {\n    checkRoot();\n    String parentName = testDirOnZK;\n    String nodeName = parentName + \"/enode_abc\";\n    ZooKeeper zk = new ZooKeeper(hostPort, 10000, this);\n\n    Stat stat = zk.exists(parentName, false);\n    if (stat == null) {\n      try {\n        zk.create(parentName, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n      } catch (KeeperException ke) {\n        Assert.fail(\"Creating node \" + parentName + ke.getMessage());\n      }\n    }\n\n    try {\n      zk.create(nodeName, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NODEEXISTS;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for createin: \" + ke.getMessage());\n      }\n    }\n\n    stat = zk.exists(nodeName, false);\n    if (stat == null) {\n      Assert.fail(\"node \" + nodeName + \" should exist\");\n    }\n    System.out.println(\"Closing client with sessionid: 0x\"\n            + Long.toHexString(zk.getSessionId()));\n    zk.close();\n    zk = new ZooKeeper(hostPort, 10000, this);\n\n    for (int i = 0; i < 10; i++) {\n      System.out.println(\"i = \" + i);\n      stat = zk.exists(nodeName, false);\n      if (stat != null) {\n        System.out.println(\"node \" + nodeName\n            + \" should not exist after reconnection close\");\n      } else {\n        System.out.println(\"node \" + nodeName\n            + \" is gone after reconnection close!\");\n        break;\n      }\n      Thread.sleep(5000);\n    }\n    deleteZKDir(zk, nodeName);\n    zk.close();\n\n  }\n\n  private void enode_test_2() throws IOException,\n          InterruptedException, KeeperException {\n    checkRoot();\n    String parentName = testDirOnZK;\n    String nodeName = parentName + \"/enode_abc\";\n    ZooKeeper zk = new ZooKeeper(hostPort, 10000, this);\n    ZooKeeper zk_1 = new ZooKeeper(hostPort, 10000, this);\n\n    Stat stat_parent = zk_1.exists(parentName, false);\n    if (stat_parent == null) {\n      try {\n        zk.create(parentName, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n      } catch (KeeperException ke) {\n        Assert.fail(\"Creating node \" + parentName + ke.getMessage());\n      }\n    }\n\n    Stat stat_node = zk_1.exists(nodeName, false);\n    if (stat_node != null) {\n\n      try {\n        zk.delete(nodeName, -1);\n      } catch (KeeperException ke) {\n        Code code = ke.code();\n        boolean valid = code == KeeperException.Code.NONODE\n            || code == KeeperException.Code.NOTEMPTY;\n        if (!valid) {\n          Assert.fail(\"Unexpected exception code for delete: \" + ke.getMessage());\n        }\n      }\n    }\n\n    List<String> firstGen1 = zk_1.getChildren(parentName, true);\n    Stat stat = new Stat();\n    List<String> firstGen2 = zk_1.getChildren(parentName, true, stat);\n\n    if (!firstGen1.equals(firstGen2)) {\n        Assert.fail(\"children lists from getChildren()/getChildren2() do not match\");\n    }\n\n    if (!stat_parent.equals(stat)) {\n        Assert.fail(\"stat from exists()/getChildren() do not match\");\n    }\n\n    try {\n      zk.create(nodeName, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NODEEXISTS;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for createin: \" + ke.getMessage());\n      }\n    }\n\n    Thread.sleep(5000);\n    WatchedEvent event = events.poll(10, TimeUnit.SECONDS);\n    if (event == null) {\n      throw new IOException(\"No event was delivered promptly\");\n    }\n    if (event.getType() != EventType.NodeChildrenChanged\n        || !event.getPath().equalsIgnoreCase(parentName)) {\n      Assert.fail(\"Unexpected event was delivered: \" + event.toString());\n    }\n\n    stat_node = zk_1.exists(nodeName, false);\n    if (stat_node == null) {\n      Assert.fail(\"node \" + nodeName + \" should exist\");\n    }\n\n    try {\n      zk.delete(parentName, -1);\n      Assert.fail(\"Should be impossible to delete a non-empty node \" + parentName);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NOTEMPTY;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for delete: \" + code);\n      }\n    }\n\n    try {\n      zk.create(nodeName + \"/def\", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);\n      Assert.fail(\"Should be impossible to create child off Ephemeral node \" + nodeName);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NOCHILDRENFOREPHEMERALS;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for createin: \" + code);\n      }\n    }\n\n    try {\n      List<String> children1 = zk.getChildren(nodeName, false);\n      List<String> children2 = zk.getChildren(nodeName, false, null);\n\n      if (!children1.equals(children2)) {\n          Assert.fail(\"children lists from getChildren()/getChildren2() does not match\");\n      }\n\n      if (children1.size() > 0) {\n        Assert.fail(\"ephemeral node \" + nodeName + \" should not have children\");\n      }\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NONODE;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for createin: \" + code);\n      }\n    }\n    firstGen1 = zk_1.getChildren(parentName, true);\n    firstGen2 = zk_1.getChildren(parentName, true, null);\n\n    if (!firstGen1.equals(firstGen2)) {\n        Assert.fail(\"children list from getChildren()/getChildren2() does not match\");\n    }\n\n    stat_node = zk_1.exists(nodeName, true);\n    if (stat_node == null) {\n      Assert.fail(\"node \" + nodeName + \" should exist\");\n    }\n    System.out.println(\"session id of zk: \" + zk.getSessionId());\n    System.out.println(\"session id of zk_1: \" + zk_1.getSessionId());\n    zk.close();\n\n    Stat no_stat = zk_1.exists(\"nosuchnode\", false);\n\n    event = this.getEvent(10);\n    if (event == null) {\n      throw new Error(\"First event was not delivered promptly\");\n    }\n    if (!((event.getType() == EventType.NodeChildrenChanged &&\n           event.getPath().equalsIgnoreCase(parentName)) ||\n         (event.getType() == EventType.NodeDeleted &&\n           event.getPath().equalsIgnoreCase(nodeName)))) {\n      System.out.print(parentName + \" \"\n          + EventType.NodeChildrenChanged + \" \" + nodeName + \" \" + EventType.NodeDeleted);\n      Assert.fail(\"Unexpected first event was delivered: \" + event.toString());\n    }\n\n    event = this.getEvent(10);\n\n    if (event == null) {\n      throw new Error(\"Second event was not delivered promptly\");\n    }\n    if (!((event.getType() == EventType.NodeChildrenChanged &&\n        event.getPath().equalsIgnoreCase(parentName)) ||\n      (event.getType() == EventType.NodeDeleted &&\n        event.getPath().equalsIgnoreCase(nodeName)))) {\n      System.out.print(parentName + \" \"\n          + EventType.NodeChildrenChanged + \" \" + nodeName + \" \" + EventType.NodeDeleted);\n      Assert.fail(\"Unexpected second event was delivered: \" + event.toString());\n    }\n\n    firstGen1 = zk_1.getChildren(parentName, false);\n    stat_node = zk_1.exists(nodeName, false);\n    if (stat_node != null) {\n      Assert.fail(\"node \" + nodeName + \" should have been deleted\");\n    }\n    if (firstGen1.contains(nodeName)) {\n      Assert.fail(\"node \" + nodeName + \" should not be a children\");\n    }\n    deleteZKDir(zk_1, nodeName);\n    zk_1.close();\n  }\n\n  private void delete_create_get_set_test_1() throws\n          IOException, InterruptedException, KeeperException {\n    checkRoot();\n    ZooKeeper zk = new ZooKeeper(hostPort, 10000, this);\n    String parentName = testDirOnZK;\n    String nodeName = parentName + \"/benwashere\";\n    try {\n      zk.delete(nodeName, -1);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NONODE\n          || code == KeeperException.Code.NOTEMPTY;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for delete: \" + ke.getMessage());\n      }\n    }\n    try {\n      zk.create(nodeName, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NODEEXISTS;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for create: \" + ke.getMessage());\n      }\n    }\n    try {\n      zk.setData(nodeName, \"hi\".getBytes(), 5700);\n      Assert.fail(\"Should have gotten BadVersion exception\");\n    } catch (KeeperException ke) {\n      if (ke.code() != Code.BADVERSION) {\n        Assert.fail(\"Should have gotten BadVersion exception\");\n      }\n    }\n    zk.setData(nodeName, \"hi\".getBytes(), -1);\n    Stat st = new Stat();\n    byte[] bytes = zk.getData(nodeName, false, st);\n    String retrieved = new String(bytes);\n    if (!\"hi\".equals(retrieved)) {\n      Assert.fail(\"The retrieved data [\" + retrieved\n          + \"] is differented than the expected [hi]\");\n    }\n    try {\n      zk.delete(nodeName, 6800);\n      Assert.fail(\"Should have gotten BadVersion exception\");\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NOTEMPTY\n          || code == KeeperException.Code.BADVERSION;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for delete: \" + ke.getMessage());\n      }\n    }\n    try {\n      zk.delete(nodeName, -1);\n    } catch (KeeperException ke) {\n      Code code = ke.code();\n      boolean valid = code == KeeperException.Code.NOTEMPTY;\n      if (!valid) {\n        Assert.fail(\"Unexpected exception code for delete: \" + code);\n      }\n    }\n    deleteZKDir(zk, nodeName);\n    zk.close();\n  }\n\n  public void my_test_1() throws IOException,\n          InterruptedException, KeeperException {\n    enode_test_1();\n    enode_test_2();\n    delete_create_get_set_test_1();\n  }\n\n  synchronized public void process(WatchedEvent event) {\n    try {\n      System.out.println(\"Got an event \" + event.toString());\n      events.put(event);\n    } catch (InterruptedException e) {\n      e.printStackTrace();\n    }\n  }\n\n  public static void main(String[] args) {\n    ZooKeeperTestClient zktc = new ZooKeeperTestClient();\n    try {\n      zktc.my_test_1();\n    } catch (Exception e) {\n      e.printStackTrace();\n    }\n  }\n}\n"
  },
  {
    "path": "src/lastRevision.bat",
    "content": "echo off\r\nrem Licensed to the Apache Software Foundation (ASF) under one\r\nrem or more contributor license agreements.  See the NOTICE file\r\nrem distributed with this work for additional information\r\nrem regarding copyright ownership.  The ASF licenses this file\r\nrem to you under the Apache License, Version 2.0 (the\r\nrem \"License\"); you may not use this file except in compliance\r\nrem with the License.  You may obtain a copy of the License at\r\nrem\r\nrem     http://www.apache.org/licenses/LICENSE-2.0\r\nrem\r\nrem Unless required by applicable law or agreed to in writing, software\r\nrem distributed under the License is distributed on an \"AS IS\" BASIS,\r\nrem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nrem See the License for the specific language governing permissions and\r\nrem limitations under the License.\r\n\r\nrem Find the current revision, store it in a file, for DOS\r\n\r\nfor /f \"delims=\" %%i in ('git rev-parse HEAD') do set rev=%%i\r\n       echo lastRevision=%rev% > %1\r\n)\r\n"
  },
  {
    "path": "src/lastRevision.sh",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Find the current revision, store it in a file\nFILE=$1\nLASTREV=`git rev-parse HEAD`\n\necho \"lastRevision=${LASTREV}\" > $FILE\n"
  },
  {
    "path": "src/packages/deb/init.d/zookeeper",
    "content": "#! /usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n### BEGIN INIT INFO\n# Provides:\t\tzookeeper\n# Required-Start:\t$remote_fs $syslog\n# Required-Stop:\t$remote_fs $syslog\n# Default-Start:\t2 3 4 5\n# Default-Stop:\t\t\n# Short-Description:\tApache ZooKeeper server\n### END INIT INFO\n\nset -e\n\n# /etc/init.d/zookeeper: start and stop the Apache ZooKeeper daemon\n\numask 022\n\n. /usr/libexec/zkEnv.sh\n\n. /lib/lsb/init-functions\n\nZOOPIDDIR=/var/lib/zookeeper/data\nZOOPIDFILE=${ZOOPIDDIR}/zookeeper_server.pid\n\ncheck_privsep_dir() {\n    # Create the PrivSep empty dir if necessary\n    if [ ! -d ${ZOOPIDDIR} ]; then\n\tmkdir -p ${ZOOPIDDIR}\n        chown zookeeper:hadoop ${ZOOPIDDIR}\n\tchmod 0775 ${ZOOPIDDIR} \n    fi\n}\n\n# Are we running from init?\nrun_by_init() {\n    ([ \"$previous\" ] && [ \"$runlevel\" ]) || [ \"$runlevel\" = S ]\n}\n\ncheck_for_no_start() {\n    # forget it if we're trying to start, and /etc/zookeeper/zookeeper_not_to_be_run exists\n    if [ -e /etc/zookeeper/zookeeper_not_to_be_run ]; then \n\tif [ \"$1\" = log_end_msg ]; then\n\t    log_end_msg 0\n\tfi\n\tif ! run_by_init; then\n\t    log_action_msg \"Apache ZooKeeper server not in use (/etc/zookeeper/zookeeper_not_to_be_run)\"\n\tfi\n\texit 0\n    fi\n}\n\nexport PATH=\"${PATH:+$PATH:}/usr/sbin:/usr/bin\"\n\ncase \"$1\" in\n  start)\n\tcheck_for_no_start\n\tcheck_privsep_dir\n\tlog_daemon_msg \"Starting Apache ZooKeeper server\" \"zookeeper\"\n\tif start-stop-daemon --start --quiet --oknodo --pidfile ${ZOOPIDFILE} -c zookeeper -x ${ZOOKEEPER_PREFIX}/sbin/zkServer.sh start; then\n\t    log_end_msg 0\n\telse\n\t    log_end_msg 1\n\tfi\n\t;;\n  stop)\n\tlog_daemon_msg \"Stopping Apache ZooKeeper server\" \"zookeeper\"\n\tif start-stop-daemon --stop --quiet --oknodo --pidfile ${ZOOPIDFILE}; then\n\t    log_end_msg 0\n\telse\n\t    log_end_msg 1\n\tfi\n\t;;\n\n  restart)\n\tcheck_privsep_dir\n\tlog_daemon_msg \"Restarting Apache ZooKeeper server\" \"zookeeper\"\n\tstart-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile ${ZOOPIDFILE}\n\tcheck_for_no_start log_end_msg\n\tif start-stop-daemon --start --quiet --oknodo --pidfile ${ZOOPIDFILE} -c zookeeper -x ${ZOOKEEPER_PREFIX}/sbin/zkServer.sh start; then\n\t    log_end_msg 0\n\telse\n\t    log_end_msg 1\n\tfi\n\t;;\n\n  try-restart)\n\tcheck_privsep_dir\n\tlog_daemon_msg \"Restarting Apache ZooKeeper server\" \"zookeeper\"\n\tset +e\n\tstart-stop-daemon --stop --quiet --retry 30 --pidfile ${ZOOPIDFILE}\n\tRET=\"$?\"\n\tset -e\n\tcase $RET in\n\t    0)\n\t\t# old daemon stopped\n\t\tcheck_for_no_start log_end_msg\n\t\tif start-stop-daemon --start --quiet --oknodo --pidfile ${ZOOPIDFILE} -c zookeeper -x ${ZOOKEEPER_PREFIX}/sbin/zkServer.sh start; then\n\t\t    log_end_msg 0\n\t\telse\n\t\t    log_end_msg 1\n\t\tfi\n\t\t;;\n\t    1)\n\t\t# daemon not running\n\t\tlog_progress_msg \"(not running)\"\n\t\tlog_end_msg 0\n\t\t;;\n\t    *)\n\t\t# failed to stop\n\t\tlog_progress_msg \"(failed to stop)\"\n\t\tlog_end_msg 1\n\t\t;;\n\tesac\n\t;;\n\n  status)\n\tstatus_of_proc -p ${ZOOPIDFILE} ${JAVA_HOME}/bin/java zookeeper && exit 0 || exit $?\n\t;;\n\n  *)\n\tlog_action_msg \"Usage: /etc/init.d/zookeeper {start|stop|restart|try-restart|status}\"\n\texit 1\nesac\n\nexit 0\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/conffile",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n/etc/zookeeper\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/control",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nPackage: zookeeper\nVersion: @version@\nSection: misc\nPriority: optional\nArchitecture: all\nDepends: sun-java6-jre\nMaintainer: Apache Software Foundation <dev@zookeeper.apache.org>\nDescription: ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.\nDistribution: development\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/postinst",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nbash /usr/sbin/update-zookeeper-env.sh \\\n  --prefix=/usr \\\n  --conf-dir=/etc/zookeeper \\\n  --log-dir=/var/log/zookeeper \\\n  --pid-dir=/var/run/zookeeper \\\n  --var-dir=/var/lib/zookeeper\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/postrm",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n/usr/sbin/userdel zookeeper 2> /dev/null >/dev/null\nexit 0\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/preinst",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ngetent group hadoop 2>/dev/null >/dev/null || /usr/sbin/groupadd -r hadoop\n\n/usr/sbin/useradd --comment \"ZooKeeper\" --shell /bin/bash -M -r --groups hadoop --home /usr/share/zookeeper zookeeper 2> /dev/null || :\n"
  },
  {
    "path": "src/packages/deb/zookeeper.control/prerm",
    "content": "#!/bin/sh\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n/etc/init.d/zookeeper stop 2>/dev/null >/dev/null\nbash /usr/sbin/update-zookeeper-env.sh \\\n  --prefix=/usr \\\n  --conf-dir=/etc/zookeeper \\\n  --log-dir=/var/log/zookeeper \\\n  --pid-dir=/var/run/zookeeper \\\n  --uninstal\n"
  },
  {
    "path": "src/packages/rpm/init.d/zookeeper",
    "content": "#!/bin/bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# \n# ZooKeeper\n# \n# chkconfig: 2345 89 9 \n# description: zookeeper\n\nsource /etc/rc.d/init.d/functions\nsource /usr/libexec/zkEnv.sh\n\nRETVAL=0\nPIDFILE=\"${ZOOPIDFILE}\"\ndesc=\"ZooKeeper daemon\"\n\nstart() {\n  echo -n $\"Starting $desc (zookeeper): \"\n  daemon --user zookeeper zkServer.sh start\n  RETVAL=$?\n  echo\n  [ $RETVAL -eq 0 ] && touch /var/lock/subsys/zookeeper\n  return $RETVAL\n}\n\nstop() {\n  echo -n $\"Stopping $desc (zookeeper): \"\n  daemon --user zookeeper zkServer.sh stop\n  RETVAL=$?\n  sleep 5\n  echo\n  [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/zookeeper $PIDFILE\n}\n\nrestart() {\n  stop\n  start\n}\n\ncheckstatus(){\n  status -p $PIDFILE ${JAVA_HOME}/bin/java\n  RETVAL=$?\n}\n\ncondrestart(){\n  [ -e /var/lock/subsys/zookeeper ] && restart || :\n}\n\ncase \"$1\" in\n  start)\n    start\n    ;;\n  stop)\n    stop\n    ;;\n  status)\n    checkstatus\n    ;;\n  restart)\n    restart\n    ;;\n  condrestart)\n    condrestart\n    ;;\n  *)\n    echo $\"Usage: $0 {start|stop|status|restart|condrestart}\"\n    exit 1\nesac\n\nexit $RETVAL\n"
  },
  {
    "path": "src/packages/rpm/spec/zookeeper.spec",
    "content": "#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n\n#\n# RPM Spec file for ZooKeeper version @version@\n#\n\n%define name         zookeeper\n%define version      @version@\n%define release      @package.release@\n\n# Installation Locations\n%define _prefix      @package.prefix@\n%define _bin_dir     %{_prefix}/bin\n%define _conf_dir    @package.conf.dir@\n%define _include_dir %{_prefix}/include\n%define _lib_dir     %{_prefix}/lib\n%define _lib64_dir   %{_prefix}/lib64\n%define _libexec_dir %{_prefix}/libexec\n%define _log_dir     @package.log.dir@\n%define _man_dir     %{_prefix}/man\n%define _pid_dir     @package.pid.dir@\n%define _sbin_dir    %{_prefix}/sbin\n%define _share_dir   %{_prefix}/share/zookeeper\n%define _src_dir     %{_prefix}/src\n%define _var_dir     @package.var.dir@\n\n# Build time settings\n%define _build_dir    @package.build.dir@\n%define _final_name   @final.name@\n%define _c_lib        @c.lib@\n%define debug_package %{nil}\n\n# Disable brp-java-repack-jars for aspect J\n%define __os_install_post    \\\n    /usr/lib/rpm/redhat/brp-compress \\\n    %{!?__debug_package:/usr/lib/rpm/redhat/brp-strip %{__strip}} \\\n    /usr/lib/rpm/redhat/brp-strip-static-archive %{__strip} \\\n    /usr/lib/rpm/redhat/brp-strip-comment-note %{__strip} %{__objdump} \\\n    /usr/lib/rpm/brp-python-bytecompile %{nil}\n\n# RPM searches perl files for dependancies and this breaks for non packaged perl lib\n# like thrift so disable this\n%define _use_internal_dependency_generator 0\n\nSummary: ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.\nLicense: Apache License, Version 2.0\nURL: http://zookeeper.apache.org/\nVendor: Apache Software Foundation\nGroup: Development/Libraries\nName: %{name}\nVersion: %{version}\nRelease: %{release} \nSource0: %{_final_name}.tar.gz\nSource1: %{_final_name}-lib.tar.gz\nPrefix: %{_prefix}\nPrefix: %{_conf_dir}\nPrefix: %{_log_dir}\nPrefix: %{_pid_dir}\nPrefix: %{_var_dir}\nRequires: sh-utils, textutils, /usr/sbin/useradd, /usr/sbin/usermod, /sbin/chkconfig, /sbin/service, jdk >= 1.6\nAutoReqProv: no\nProvides: zookeeper\n\n%description\nZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them ,which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.\n\n%package lib\nSummary: ZooKeeper C binding library\nGroup: System/Libraries\n#Requires: %{name} == %{version}\nProvides: zookeeper-lib\n\n%description lib\nZooKeeper C client library for communicating with ZooKeeper Server.\n\n%prep\n%setup -D -b 1 -n %{_final_name}\n%setup -D -a 0 -n %{_final_name}\n\n%build\nmkdir -p ${RPM_BUILD_DIR}%{_prefix}\nmkdir -p ${RPM_BUILD_DIR}%{_bin_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_include_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_lib_dir}\n%ifarch amd64 x86_64\nmkdir -p ${RPM_BUILD_DIR}%{_lib64_dir}\n%endif\nmkdir -p ${RPM_BUILD_DIR}%{_libexec_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_log_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_conf_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_man_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_pid_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_sbin_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_share_dir}\nmkdir -p ${RPM_BUILD_DIR}%{_var_dir}\nmkdir -p ${RPM_BUILD_DIR}/etc/init.d\n\ncp ${RPM_BUILD_DIR}/%{_final_name}/src/packages/rpm/init.d/zookeeper ${RPM_BUILD_DIR}/etc/init.d/zookeeper\ncp ${RPM_BUILD_DIR}/%{_final_name}/src/packages/update-zookeeper-env.sh ${RPM_BUILD_DIR}/%{_final_name}/sbin/update-zookeeper-env.sh\nchmod 0755 ${RPM_BUILD_DIR}/%{_final_name}/sbin/*\nchmod 0755 ${RPM_BUILD_DIR}/etc/init.d/zookeeper\n\n#########################\n#### INSTALL SECTION ####\n#########################\n%install\npushd ${RPM_BUILD_DIR}\nmv ${RPM_BUILD_DIR}/%{_final_name}/bin/* ${RPM_BUILD_DIR}%{_bin_dir}\nmv ${RPM_BUILD_DIR}/%{_final_name}/libexec/* ${RPM_BUILD_DIR}%{_libexec_dir}\nmv ${RPM_BUILD_DIR}/%{_final_name}/share/zookeeper/* ${RPM_BUILD_DIR}%{_share_dir}\nmv ${RPM_BUILD_DIR}/%{_final_name}/conf/* ${RPM_BUILD_DIR}%{_conf_dir}\nmv ${RPM_BUILD_DIR}/%{_final_name}/sbin/* ${RPM_BUILD_DIR}%{_sbin_dir}\ncp -f ${RPM_BUILD_DIR}%{_conf_dir}/zoo_sample.cfg ${RPM_BUILD_DIR}%{_conf_dir}/zoo.cfg\npopd ${RPM_BUILD_DIR}\nrm -rf ${RPM_BUILD_DIR}/%{_final_name}\n\n%pre\ngetent group hadoop 2>/dev/null >/dev/null || /usr/sbin/groupadd -r hadoop\n\n/usr/sbin/useradd --comment \"ZooKeeper\" --shell /bin/bash -M -r --groups hadoop --home %{_share_dir} zookeeper 2> /dev/null || :\n\n%post\nbash ${RPM_INSTALL_PREFIX0}/sbin/update-zookeeper-env.sh \\\n       --prefix=${RPM_INSTALL_PREFIX0} \\\n       --conf-dir=${RPM_INSTALL_PREFIX1} \\\n       --log-dir=${RPM_INSTALL_PREFIX2} \\\n       --pid-dir=${RPM_INSTALL_PREFIX3} \\\n       --var-dir=${RPM_INSTALL_PREFIX4}\n\n%preun\nbash ${RPM_INSTALL_PREFIX0}/sbin/update-zookeeper-env.sh \\\n       --prefix=${RPM_INSTALL_PREFIX0} \\\n       --conf-dir=${RPM_INSTALL_PREFIX1} \\\n       --log-dir=${RPM_INSTALL_PREFIX2} \\\n       --pid-dir=${RPM_INSTALL_PREFIX3} \\\n       --var-dir=${RPM_INSTALL_PREFIX4} \\\n       --uninstall\n\n%files \n%defattr(-,root,root)\n%attr(0755,root,hadoop) %{_log_dir}\n%attr(0775,root,hadoop) %{_pid_dir}\n%attr(0775,root,hadoop) /etc/init.d/zookeeper\n%config(noreplace) %{_conf_dir}/*\n%{_prefix}\n\n%post lib\n/sbin/ldconfig\n\n%files lib\n%defattr(-,root,root)\n%{_prefix}/lib/*\n%{_prefix}/bin\n"
  },
  {
    "path": "src/packages/templates/conf/zookeeper-env.sh",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nexport JAVA_HOME=${JAVA_HOME}\nexport ZOO_LOG_DIR=${LOG_DIR}\n"
  },
  {
    "path": "src/packages/update-zookeeper-env.sh",
    "content": "#!/usr/bin/env bash\n\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This script configures zookeeper-env.sh and zoo.cfg.\n\nusage() {\n  echo \"\nusage: $0 <parameters>\n  Required parameters:\n     --prefix=PREFIX               path to install into\n\n  Optional parameters:\n     --arch=i386                   OS Architecture\n     --conf-dir=/etc/zookeeper     Configuration directory\n     --log-dir=/var/log/zookeeper  Log directory\n     --pid-dir=/var/run            PID file location\n  \"\n  exit 1\n}\n\ntemplate_generator() {\n  REGEX='(\\$\\{[a-zA-Z_][a-zA-Z_0-9]*\\})'\n  cat $1 |\n  while read line ; do\n    while [[ \"$line\" =~ $REGEX ]] ; do\n      LHS=${BASH_REMATCH[1]}\n      RHS=\"$(eval echo \"\\\"$LHS\\\"\")\"\n      line=${line//$LHS/$RHS}\n    done\n    echo $line >> $2\n  done\n}\n\nOPTS=$(getopt \\\n  -n $0 \\\n  -o '' \\\n  -l 'arch:' \\\n  -l 'prefix:' \\\n  -l 'conf-dir:' \\\n  -l 'log-dir:' \\\n  -l 'pid-dir:' \\\n  -l 'var-dir:' \\\n  -l 'uninstall' \\\n  -- \"$@\")\n\nif [ $? != 0 ] ; then\n    usage\nfi\n\neval set -- \"${OPTS}\"\nwhile true ; do\n  case \"$1\" in\n    --arch)\n      ARCH=$2 ; shift 2\n      ;;\n    --prefix)\n      PREFIX=$2 ; shift 2\n      ;;\n    --log-dir)\n      LOG_DIR=$2 ; shift 2\n      ;;\n    --lib-dir)\n      LIB_DIR=$2 ; shift 2\n      ;;\n    --conf-dir)\n      CONF_DIR=$2 ; shift 2\n      ;;\n    --pid-dir)\n      PID_DIR=$2 ; shift 2\n      ;;\n    --uninstall)\n      UNINSTALL=1; shift\n      ;;\n    --var-dir)\n      VAR_DIR=$2 ; shift 2\n      ;;\n    --)\n      shift ; break\n      ;;\n    *)\n      echo \"Unknown option: $1\"\n      usage\n      exit 1\n      ;;\n  esac\ndone\n\nfor var in PREFIX; do\n  if [ -z \"$(eval \"echo \\$$var\")\" ]; then\n    echo Missing param: $var\n    usage\n  fi\ndone\n\nARCH=${ARCH:-i386}\nCONF_DIR=${CONF_DIR:-$PREFIX/etc/zookeeper}\nLIB_DIR=${LIB_DIR:-$PREFIX/lib}\nLOG_DIR=${LOG_DIR:-$PREFIX/var/log}\nPID_DIR=${PID_DIR:-$PREFIX/var/run}\nVAR_DIR=${VAR_DIR:-$PREFIX/var/lib}\nUNINSTALL=${UNINSTALL:-0}\n\nif [ \"${ARCH}\" != \"i386\" ]; then\n  LIB_DIR=${LIB_DIR}64\nfi\n\nif [ \"${UNINSTALL}\" -eq \"1\" ]; then\n  # Remove symlinks\n  if [ -e ${PREFIX}/etc/zookeeper ]; then\n    rm -f ${PREFIX}/etc/zookeeper\n  fi\nelse\n  # Create symlinks\n  if [ ${CONF_DIR} != ${PREFIX}/etc/zookeeper ]; then\n    mkdir -p ${PREFIX}/etc\n    ln -sf ${CONF_DIR} ${PREFIX}/etc/zookeeper\n  fi\n\n  mkdir -p ${LOG_DIR}\n  chown zookeeper:hadoop ${LOG_DIR}\n  chmod 755 ${LOG_DIR}\n\n  if [ ! -d ${PID_DIR} ]; then\n    mkdir -p ${PID_DIR}\n    chown zookeeper:hadoop ${PID_DIR}\n    chmod 755 ${PID_DIR}\n  fi\n\n  if [ ! -d ${VAR_DIR} ]; then\n    mkdir -p ${VAR_DIR}/data\n    chown -R zookeeper:hadoop ${VAR_DIR}\n    chmod -R 755 ${VAR_DIR}\n  fi\n\n  TFILE=\"/tmp/$(basename $0).$$.tmp\"\n  if [ -z \"${JAVA_HOME}\" ]; then\n    if [ -e /etc/debian_version ]; then\n      JAVA_HOME=/usr/lib/jvm/java-6-sun/jre\n    else\n      JAVA_HOME=/usr/java/default\n    fi\n  fi\n  template_generator ${PREFIX}/share/zookeeper/templates/conf/zookeeper-env.sh $TFILE\n  cp ${TFILE} ${CONF_DIR}/zookeeper-env.sh\n  rm -f ${TFILE}\n  template_generator ${PREFIX}/share/zookeeper/templates/conf/zoo.cfg $TFILE\n  cp ${TFILE} ${CONF_DIR}/zoo.cfg\n  rm -f ${TFILE}\nfi\n"
  },
  {
    "path": "src/pom.template",
    "content": "SKIP_LINE  ***************************************************************\nSKIP_LINE  * Licensed to the Apache Software Foundation (ASF) under one\nSKIP_LINE  * or more contributor license agreements.  See the NOTICE file\nSKIP_LINE  * distributed with this work for additional information\nSKIP_LINE  * regarding copyright ownership.  The ASF licenses this file\nSKIP_LINE  * to you under the Apache License, Version 2.0 (the\nSKIP_LINE  * \"License\"); you may not use this file except in compliance\nSKIP_LINE  * with the License.  You may obtain a copy of the License at\nSKIP_LINE  * \nSKIP_LINE  *   http://www.apache.org/licenses/LICENSE-2.0\nSKIP_LINE  * \nSKIP_LINE  * Unless required by applicable law or agreed to in writing,\nSKIP_LINE  * software distributed under the License is distributed on an\nSKIP_LINE  * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nSKIP_LINE  * KIND, either express or implied.  See the License for the\nSKIP_LINE  * specific language governing permissions and limitations\nSKIP_LINE  * under the License.\nSKIP_LINE  ***************************************************************\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n${ivy.pom.license}\n${ivy.pom.header}\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>${ivy.pom.groupId}</groupId>\n  <artifactId>${ivy.pom.artifactId}</artifactId>\n  <packaging>${ivy.pom.packaging}</packaging>\n  <version>${ivy.pom.version}</version>\n  <name>${ivy.pom.name}</name>\n  <description>${ivy.pom.description}</description>\n  <url>${ivy.pom.url}</url>\n\n  <licenses>\n    <license>\n      <name>The Apache Software License, Version 2.0</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n      <distribution>repo</distribution>\n   </license>\n  </licenses>\n</project>\n"
  },
  {
    "path": "src/recipes/README.txt",
    "content": "1) This source directory contains various Zookeeper recipe implementations. \n\n2) The recipe directory name should specify the name of the recipe you are implementing - eg. lock/.\n\n3) It would be great if you can provide both the java and c recipes for the zookeeper recipes.\nThe c recipes go in to recipe-name/src/c and the java implementation goes into recipe-name/src/java.\n\n4) The recipes hold high standards like our zookeeper c/java libraries, so make sure that you include\nsome unit testing with both the c and java recipe code.\n\n5) Also, please name your c client public methods as\nzkr_recipe-name_methodname\n(eg. zkr_lock_lock in lock/src/c)\n\n6) The various recipes are in ../../docs/recipes.html or\n../../docs/reciped.pdf. Also, this is not an exhaustive list by any chance.\nZookeeper is used (and can be used) for more than what we have listed in the docs.\n\n7) To run the c tests in all the recipes, \n- make sure the main zookeeper c libraries in\n{top}/src/c/ are compiled. Run autoreconf -if;./configure; make. The libaries\nwill be installed in {top}/src/c/.libs. \n- run autoreconf if;./configure;make run-check \n  in src/recipes/$recipename/src/c\n\n"
  },
  {
    "path": "src/recipes/build-recipes.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<!-- Imported by recipesb/*/build.xml files to share generic targets. -->\n\n<project name=\"zookeeperbuildrecipes\">\n\n  <property name=\"name\" value=\"${ant.project.name}\"/>\n  <property name=\"root\" value=\"${basedir}\"/>\n\n  <property name=\"zk.root\" location=\"${root}/../../../\"/>\n\n  <property name=\"src.dir\"  location=\"${root}/src/java\"/>\n  <property name=\"src.test\" location=\"${root}/src/test\"/>\n\n  <property name=\"build.dir\" location=\"${zk.root}/build/recipes/${name}\"/>\n  <property name=\"build.classes\" location=\"${build.dir}/classes\"/>\n  <property name=\"build.test\" location=\"${build.dir}/test\"/>\n\n  <property name=\"javac.deprecation\" value=\"on\"/>\n  <property name=\"javac.debug\" value=\"on\"/>\n\n  <property name=\"build.encoding\" value=\"ISO-8859-1\"/>\n\n  <!-- to be overridden by sub-projects -->\n  <target name=\"check-recipes\"/>\n  <target name=\"init-recipes\"/>\n\n  <property name=\"lib.jars.includes\" value=\"lib/*.jar\" />\n  <property name=\"lib.jars.excludes\" value=\"\" />\n\n  <!-- prior to ant 1.7.1 fileset always fails if dir doesn't exist\n       so just point to bin directory and provide settings that exclude\n       everything - user can change as appropriate -->\n  <property name=\"additional.lib.dir\" value=\"${zk.root}/bin\" />\n  <property name=\"additional.lib.dir.includes\" value=\"**/*.jar\" />\n  <property name=\"additional.lib.dir.excludes\" value=\"**/*.jar\" />\n\n  <fileset id=\"lib.jars\" dir=\"${root}\">\n    <include name=\"${lib.jars.includes}\" />\n    <exclude name=\"${lib.jars.excludes}\" />\n  </fileset>\n\n  <path id=\"classpath\">\n    <pathelement location=\"${build.classes}\"/>\n    <!-- allow the user to override (e.g. if there are local versions) -->\n    <fileset dir=\"${additional.lib.dir}\">\n      <include name=\"${additional.lib.dir.includes}\" />\n      <exclude name=\"${additional.lib.dir.excludes}\" />\n    </fileset>\n    <fileset refid=\"lib.jars\"/>\n    <pathelement location=\"${zk.root}/build/classes\"/>\n    <fileset dir=\"${zk.root}/build/lib\">\n      <include name=\"**/*.jar\" />\n    </fileset>\n    <fileset dir=\"${zk.root}/build/test/lib\">\n      <include name=\"**/*.jar\"/>\n    </fileset>\n    <fileset dir=\"${zk.root}/src/java/lib\">\n      <include name=\"**/*.jar\" />\n    </fileset>\n  </path>\n\n  <!-- ====================================================== -->\n  <!-- Stuff needed by all targets                            -->\n  <!-- ====================================================== -->\n  <target name=\"init\" depends=\"check-recipes\" unless=\"skip.recipes\">\n    <echo message=\"recipes: ${name}\"/>\n    <mkdir dir=\"${build.dir}\"/>\n    <mkdir dir=\"${build.classes}\"/>\n    <mkdir dir=\"${build.test}\"/>\n    <antcall target=\"init-recipes\"/>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Compile a recipes files                                -->\n  <!-- ====================================================== -->\n  <target name=\"compile\" depends=\"init\" unless=\"skip.contrib\">\n    <echo message=\"contrib: ${name}\"/>\n\n    <javac\n     encoding=\"${build.encoding}\"\n     srcdir=\"${src.dir}\"\n     includes=\"**/*.java\"\n     destdir=\"${build.classes}\"\n     debug=\"${javac.debug}\"\n     deprecation=\"${javac.deprecation}\">\n      <classpath refid=\"classpath\"/>\n    </javac>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Make a recipes jar                                     -->\n  <!-- ====================================================== -->\n  <target name=\"jar\" depends=\"compile\" unless=\"skip.recipes\">\n    <echo message=\"recipes: ${name}\"/>\n    <jar\n      jarfile=\"${build.dir}/zookeeper-${version}-recipes-${name}.jar\"\n      basedir=\"${build.classes}\"      \n    />\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- Package a recipes files                                -->\n  <!-- ====================================================== -->\n  <target name=\"package\" depends=\"jar\" unless=\"skip.recipes\"> \n    <echo message=\"recipes: ${name}\"/>\n\n    <mkdir dir=\"${dist.dir}${package.share}/recipes/${name}\"/>\n    <copy todir=\"${dist.dir}${package.share}/recipes/${name}\" includeEmptyDirs=\"false\"\n          flatten=\"true\">\n      <fileset dir=\"${build.dir}\">\n        <include name=\"zookeeper-${version}-recipes-${name}.jar\" />\n      </fileset>\n    </copy>\n  </target>\n\n  <!-- ================================================================== -->\n  <!-- Clean.  Delete the build files, and their directories              -->\n  <!-- ================================================================== -->\n  <target name=\"clean\">\n    <echo message=\"recipes: ${name}\"/>\n    <delete dir=\"${build.dir}\"/>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- rpm a contrib's files                                  -->\n  <!-- ====================================================== -->\n  <target name=\"rpm\" depends=\"jar\" unless=\"skip.contrib\">\n    <echo message=\"recipes: ${name}\"/>\n\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- deb a contrib's files                                  -->\n  <!-- ====================================================== -->\n  <target name=\"deb\" depends=\"jar\" unless=\"skip.contrib\">\n    <echo message=\"recipes: ${name}\"/>\n\n  </target>\n\n  <!-- ================================================================== -->\n  <!-- Utility features                                                   -->\n  <!-- ================================================================== -->\n\n  <target name=\"checkMainIsAvailable\">\n    <available classname=\"org.apache.zookeeper.ZooKeeperMain\"\n               property=\"mainIsCompiled\">\n      <!-- we can't use id=classpath, because available fails if fileset directory\n           doesn't exist -->\n      <classpath>\n        <pathelement location=\"${zk.root}/build/classes\"/>\n      </classpath>\n    </available>\n  </target>\n\n  <target name=\"checkMainCompiled\" unless=\"mainIsCompiled\" depends=\"checkMainIsAvailable\">\n    <fail message=\"ZooKeeper main must first be compiled (toplevel build.xml)\"/>\n  </target>\n\n</project>\n"
  },
  {
    "path": "src/recipes/build.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"zookeeperrecipes\" default=\"compile\" basedir=\".\">\n  \n  <!-- In case one of the contrib subdirectories -->\n  <!-- fails the build or test targets and you cannot fix it: -->\n  <!-- Then add to fileset: excludes=\"badcontrib/build.xml\" -->\n\n  <!-- ====================================================== -->\n  <!-- Compile contribs.                                      -->\n  <!-- ====================================================== -->\n  <target name=\"compile\">\n    <subant target=\"jar\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n  \n  <!-- ====================================================== -->\n  <!-- Package contrib jars.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"package\">\n    <subant target=\"package\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n  \n  <!-- ====================================================== -->\n  <!-- Test all the contribs.                               -->\n  <!-- ====================================================== -->\n  <target name=\"test\">\n    <subant target=\"test\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n  \n  <!-- ====================================================== -->\n  <!-- Clean all the contribs.                              -->\n  <!-- ====================================================== -->\n  <target name=\"clean\">\n    <subant target=\"clean\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- rpm all the contribs.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"rpm\">\n    <subant target=\"rpm\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n\n  <!-- ====================================================== -->\n  <!-- deb all the contribs.                                  -->\n  <!-- ====================================================== -->\n  <target name=\"deb\">\n    <subant target=\"deb\">\n      <fileset dir=\".\" includes=\"*/build.xml\"/>\n    </subant>\n  </target>\n</project>\n"
  },
  {
    "path": "src/recipes/election/README.txt",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n1) This election interface recipe implements the leader election recipe\nmentioned in ../../../docs/recipes.[html,pdf].\n\n2) To compile the leader election java recipe you can just run ant jar from\nthis directory.\nPlease report any bugs on the jira \n\nhttp://issues.apache.org/jira/browse/ZOOKEEPER\n\n  \n"
  },
  {
    "path": "src/recipes/election/build.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"election\" default=\"jar\">\n  <import file=\"../build-recipes.xml\"/>\n    <property name=\"test.main.classes\" value=\"${zk.root}/build/test/classes\"/>\n    <property name=\"test.build.dir\" value=\"${build.test}\" />\n    <property name=\"test.src.dir\" value=\"test\"/>\n    <property name=\"test.log.dir\" value=\"${test.build.dir}/logs\" />\n    <property name=\"test.data.dir\" value=\"${test.build.dir}/data\" />\n    <property name=\"test.data.upgrade.dir\" value=\"${test.data.dir}/upgrade\" />\n    <property name=\"test.tmp.dir\" value=\"${test.build.dir}/tmp\" />\n    <property name=\"test.output\" value=\"no\" />\n    <property name=\"test.timeout\" value=\"900000\" />\n    <property name=\"test.junit.output.format\" value=\"plain\" />\n    <property name=\"test.junit.fork.mode\" value=\"perTest\" />\n    <property name=\"test.junit.printsummary\" value=\"yes\" />\n    <property name=\"test.junit.haltonfailure\" value=\"no\" />\n    <property name=\"test.junit.maxmem\" value=\"512m\" />\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\"\n              value=\"${build.dir}/zookeeper-${version}-recipes-${name}.jar\"/>\n  </target>\n\n  <!-- Override jar target to specify main class -->\n  <target name=\"jar\" depends=\"checkMainCompiled, setjarname, compile\">\n    <echo message=\"recipes: ${name}\"/>\n\n    <jar jarfile=\"${jarname}\">\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset dir=\"${build.classes}\"/>\n      <fileset dir=\"${build.test}\"/>\n    </jar>\n  </target>\n\n\t<target name=\"test\" depends=\"compile-test,test-init,test-category,junit.run\" />\n\n\t<target name=\"compile-test\" depends=\"compile\">\n  \t\t<property name=\"target.jdk\" value=\"${ant.java.version}\" />\t\n\t\t<property name=\"src.test.local\" location=\"${basedir}/test\" />\n\t\t<mkdir dir=\"${build.test}\"/>\n\t\t<javac srcdir=\"${src.test.local}\" \n\t\t\tdestdir=\"${build.test}\" \n\t\t\ttarget=\"${target.jdk}\" \n\t\t\tdebug=\"on\" >\n\t\t\t<classpath refid=\"classpath\" />\n                        <classpath>\n                        <pathelement path=\"${test.main.classes}\"/>\n                        </classpath>\n\t\t</javac>\n\t</target>\n\t\n    <target name=\"test-init\" depends=\"jar,compile-test\">\n        <delete dir=\"${test.log.dir}\" />\n        <delete dir=\"${test.tmp.dir}\" />\n        <delete dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.tmp.dir}\" />\n        <mkdir dir=\"${test.data.dir}\" />\n    </target>\n\n\t<target name=\"test-category\">\n         <property name=\"test.category\" value=\"\"/>\n    </target>\n\n\t<target name=\"junit.run\">\n\t\t<echo message=\"${test.src.dir}\" />\n        <junit showoutput=\"${test.output}\"\n               printsummary=\"${test.junit.printsummary}\"\n               haltonfailure=\"${test.junit.haltonfailure}\"\n               fork=\"yes\"\n               forkmode=\"${test.junit.fork.mode}\"\n               maxmemory=\"${test.junit.maxmem}\"\n               dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n          <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n          <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n          <sysproperty key=\"log4j.configuration\"\n                    value=\"file:${basedir}/conf/log4j.properties\" />\n          <classpath refid=\"classpath\"/>\n          <classpath>\n             <pathelement path=\"${build.test}\" />\n             <pathelement path=\"${test.main.classes}\"/>\n          </classpath>\n          <formatter type=\"${test.junit.output.format}\" />\n          <batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n              <fileset dir=\"${test.src.dir}\"\n                     includes=\"**/*${test.category}Test.java\"/>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n              <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n          </batchtest>\n       </junit>\n            <fail if=\"tests.failed\">Tests failed!</fail>\n    </target>\n\n  <target name=\"package\" depends=\"jar, zookeeperbuildrecipes.package\"\n          unless=\"skip.recipes\">\n\n    <copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}/recipes/${name}\"/>\n\n    <mkdir dir=\"${dist.dir}/recipes/${name}/test\"/>\n    <copy todir=\"${dist.dir}/recipes/${name}/test\">\n      <fileset dir=\"${basedir}/test\"/>\n    </copy>\n    <mkdir dir=\"${dist.dir}/recipes/${name}/src\"/>\n    <copy todir=\"${dist.dir}/recipes/${name}/src\">\n      <fileset dir=\"${basedir}/src\"/>\n    </copy>\n  </target>\n\n</project>\n\n"
  },
  {
    "path": "src/recipes/election/src/java/org/apache/zookeeper/recipes/leader/LeaderElectionAware.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.leader;\n\nimport org.apache.zookeeper.recipes.leader.LeaderElectionSupport.EventType;\n\n/**\n * An interface to be implemented by clients that want to receive election\n * events.\n */\npublic interface LeaderElectionAware {\n\n  /**\n   * Called during each state transition. Current, low level events are provided\n   * at the beginning and end of each state. For instance, START may be followed\n   * by OFFER_START, OFFER_COMPLETE, DETERMINE_START, DETERMINE_COMPLETE, and so\n   * on.\n   * \n   * @param eventType\n   */\n  public void onElectionEvent(EventType eventType);\n\n}\n"
  },
  {
    "path": "src/recipes/election/src/java/org/apache/zookeeper/recipes/leader/LeaderElectionSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.leader;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * A leader election support library implementing the ZooKeeper election recipe.\n * </p>\n * <p>\n * This support library is meant to simplify the construction of an exclusive\n * leader system on top of Apache ZooKeeper. Any application that can become the\n * leader (usually a process that provides a service, exclusively) would\n * configure an instance of this class with their hostname, at least one\n * listener (an implementation of {@link LeaderElectionAware}), and either an\n * instance of {@link ZooKeeper} or the proper connection information. Once\n * configured, invoking {@link #start()} will cause the client to connect to\n * ZooKeeper and create a leader offer. The library then determines if it has\n * been elected the leader using the algorithm described below. The client\n * application can follow all state transitions via the listener callback.\n * </p>\n * <p>\n * Leader election algorithm\n * </p>\n * <p>\n * The library starts in a START state. Through each state transition, a state\n * start and a state complete event are sent to all listeners. When\n * {@link #start()} is called, a leader offer is created in ZooKeeper. A leader\n * offer is an ephemeral sequential node that indicates a process that can act\n * as a leader for this service. A read of all leader offers is then performed.\n * The offer with the lowest sequence number is said to be the leader. The\n * process elected leader will transition to the leader state. All other\n * processes will transition to a ready state. Internally, the library creates a\n * ZooKeeper watch on the leader offer with the sequence ID of N - 1 (where N is\n * the process's sequence ID). If that offer disappears due to a process\n * failure, the watching process will run through the election determination\n * process again to see if it should become the leader. Note that sequence ID\n * may not be contiguous due to failed processes. A process may revoke its offer\n * to be the leader at any time by calling {@link #stop()}.\n * </p>\n * <p>\n * Guarantees (not) Made and Caveats\n * </p>\n * <p>\n * <ul>\n * <li>It is possible for a (poorly implemented) process to create a leader\n * offer, get the lowest sequence ID, but have something terrible occur where it\n * maintains its connection to ZK (and thus its ephemeral leader offer node) but\n * doesn't actually provide the service in question. It is up to the user to\n * ensure any failure to become the leader - and whatever that means in the\n * context of the user's application - results in a revocation of its leader\n * offer (i.e. that {@link #stop()} is called).</li>\n * <li>It is possible for ZK timeouts and retries to play a role in service\n * liveliness. In other words, if process A has the lowest sequence ID but\n * requires a few attempts to read the other leader offers' sequence IDs,\n * election can seem slow. Users should apply timeouts during the determination\n * process if they need to hit a specific SLA.</li>\n * <li>The library makes a \"best effort\" to detect catastrophic failures of the\n * process. It is possible that an unforeseen event results in (for instance) an\n * unchecked exception that propagates passed normal error handling code. This\n * normally doesn't matter as the same exception would almost certain destroy\n * the entire process and thus the connection to ZK and the leader offer\n * resulting in another round of leader determination.</li>\n * </ul>\n * </p>\n */\npublic class LeaderElectionSupport implements Watcher {\n\n  private static final Logger logger = LoggerFactory\n      .getLogger(LeaderElectionSupport.class);\n\n  private ZooKeeper zooKeeper;\n\n  private State state;\n  private Set<LeaderElectionAware> listeners;\n\n  private String rootNodeName;\n  private LeaderOffer leaderOffer;\n  private String hostName;\n\n  public LeaderElectionSupport() {\n    state = State.STOP;\n    listeners = Collections.synchronizedSet(new HashSet<LeaderElectionAware>());\n  }\n\n  /**\n   * <p>\n   * Start the election process. This method will create a leader offer,\n   * determine its status, and either become the leader or become ready. If an\n   * instance of {@link ZooKeeper} has not yet been configured by the user, a\n   * new instance is created using the connectString and sessionTime specified.\n   * </p>\n   * <p>\n   * Any (anticipated) failures result in a failed event being sent to all\n   * listeners.\n   * </p>\n   */\n  public synchronized void start() {\n    state = State.START;\n    dispatchEvent(EventType.START);\n\n    logger.info(\"Starting leader election support\");\n\n    if (zooKeeper == null) {\n      throw new IllegalStateException(\n          \"No instance of zookeeper provided. Hint: use setZooKeeper()\");\n    }\n\n    if (hostName == null) {\n      throw new IllegalStateException(\n          \"No hostname provided. Hint: use setHostName()\");\n    }\n\n    try {\n      makeOffer();\n      determineElectionStatus();\n    } catch (KeeperException e) {\n      becomeFailed(e);\n      return;\n    } catch (InterruptedException e) {\n      becomeFailed(e);\n      return;\n    }\n  }\n\n  /**\n   * Stops all election services, revokes any outstanding leader offers, and\n   * disconnects from ZooKeeper.\n   */\n  public synchronized void stop() {\n    state = State.STOP;\n    dispatchEvent(EventType.STOP_START);\n\n    logger.info(\"Stopping leader election support\");\n\n    if (leaderOffer != null) {\n      try {\n        zooKeeper.delete(leaderOffer.getNodePath(), -1);\n        logger.info(\"Removed leader offer {}\", leaderOffer.getNodePath());\n      } catch (InterruptedException e) {\n        becomeFailed(e);\n      } catch (KeeperException e) {\n        becomeFailed(e);\n      }\n    }\n\n    dispatchEvent(EventType.STOP_COMPLETE);\n  }\n\n  private void makeOffer() throws KeeperException, InterruptedException {\n    state = State.OFFER;\n    dispatchEvent(EventType.OFFER_START);\n\n    leaderOffer = new LeaderOffer();\n\n    leaderOffer.setHostName(hostName);\n    leaderOffer.setNodePath(zooKeeper.create(rootNodeName + \"/\" + \"n_\",\n        hostName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,\n        CreateMode.EPHEMERAL_SEQUENTIAL));\n\n    logger.debug(\"Created leader offer {}\", leaderOffer);\n\n    dispatchEvent(EventType.OFFER_COMPLETE);\n  }\n\n  private void determineElectionStatus() throws KeeperException,\n      InterruptedException {\n\n    state = State.DETERMINE;\n    dispatchEvent(EventType.DETERMINE_START);\n\n    String[] components = leaderOffer.getNodePath().split(\"/\");\n\n    leaderOffer.setId(Integer.valueOf(components[components.length - 1]\n        .substring(\"n_\".length())));\n\n    List<LeaderOffer> leaderOffers = toLeaderOffers(zooKeeper.getChildren(\n        rootNodeName, false));\n\n    /*\n     * For each leader offer, find out where we fit in. If we're first, we\n     * become the leader. If we're not elected the leader, attempt to stat the\n     * offer just less than us. If they exist, watch for their failure, but if\n     * they don't, become the leader.\n     */\n    for (int i = 0; i < leaderOffers.size(); i++) {\n      LeaderOffer leaderOffer = leaderOffers.get(i);\n\n      if (leaderOffer.getId().equals(this.leaderOffer.getId())) {\n        logger.debug(\"There are {} leader offers. I am {} in line.\",\n            leaderOffers.size(), i);\n\n        dispatchEvent(EventType.DETERMINE_COMPLETE);\n\n        if (i == 0) {\n          becomeLeader();\n        } else {\n          becomeReady(leaderOffers.get(i - 1));\n        }\n\n        /* Once we've figured out where we are, we're done. */\n        break;\n      }\n    }\n  }\n\n  private void becomeReady(LeaderOffer neighborLeaderOffer)\n      throws KeeperException, InterruptedException {\n    dispatchEvent(EventType.READY_START);\n\n    logger.info(\"{} not elected leader. Watching node:{}\",\n        leaderOffer.getNodePath(), neighborLeaderOffer.getNodePath());\n\n    /*\n     * Make sure to pass an explicit Watcher because we could be sharing this\n     * zooKeeper instance with someone else.\n     */\n    Stat stat = zooKeeper.exists(neighborLeaderOffer.getNodePath(), this);\n\n    if (stat != null) {\n      logger.debug(\n          \"We're behind {} in line and they're alive. Keeping an eye on them.\",\n          neighborLeaderOffer.getNodePath());\n      state = State.READY;\n      dispatchEvent(EventType.READY_COMPLETE);\n    } else {\n      /*\n       * If the stat fails, the node has gone missing between the call to\n       * getChildren() and exists(). We need to try and become the leader.\n       */\n      logger\n          .info(\n              \"We were behind {} but it looks like they died. Back to determination.\",\n              neighborLeaderOffer.getNodePath());\n      determineElectionStatus();\n    }\n\n  }\n\n  private void becomeLeader() {\n    state = State.ELECTED;\n    dispatchEvent(EventType.ELECTED_START);\n\n    logger.info(\"Becoming leader with node:{}\", leaderOffer.getNodePath());\n\n    dispatchEvent(EventType.ELECTED_COMPLETE);\n  }\n\n  private void becomeFailed(Exception e) {\n    logger.error(\"Failed in state {} - Exception:{}\", state, e);\n\n    state = State.FAILED;\n    dispatchEvent(EventType.FAILED);\n  }\n\n  /**\n   * Fetch the (user supplied) hostname of the current leader. Note that by the\n   * time this method returns, state could have changed so do not depend on this\n   * to be strongly consistent. This method has to read all leader offers from\n   * ZooKeeper to deterime who the leader is (i.e. there is no caching) so\n   * consider the performance implications of frequent invocation. If there are\n   * no leader offers this method returns null.\n   * \n   * @return hostname of the current leader\n   * @throws KeeperException\n   * @throws InterruptedException\n   */\n  public String getLeaderHostName() throws KeeperException,\n      InterruptedException {\n\n    List<LeaderOffer> leaderOffers = toLeaderOffers(zooKeeper.getChildren(\n        rootNodeName, false));\n\n    if (leaderOffers.size() > 0) {\n      return leaderOffers.get(0).getHostName();\n    }\n\n    return null;\n  }\n\n  private List<LeaderOffer> toLeaderOffers(List<String> strings)\n      throws KeeperException, InterruptedException {\n\n    List<LeaderOffer> leaderOffers = new ArrayList<LeaderOffer>(strings.size());\n\n    /*\n     * Turn each child of rootNodeName into a leader offer. This is a tuple of\n     * the sequence number and the node name.\n     */\n    for (String offer : strings) {\n      String hostName = new String(zooKeeper.getData(\n          rootNodeName + \"/\" + offer, false, null));\n\n      leaderOffers.add(new LeaderOffer(Integer.valueOf(offer.substring(\"n_\"\n          .length())), rootNodeName + \"/\" + offer, hostName));\n    }\n\n    /*\n     * We sort leader offers by sequence number (which may not be zero-based or\n     * contiguous) and keep their paths handy for setting watches.\n     */\n    Collections.sort(leaderOffers, new LeaderOffer.IdComparator());\n\n    return leaderOffers;\n  }\n\n  @Override\n  public void process(WatchedEvent event) {\n    if (event.getType().equals(Watcher.Event.EventType.NodeDeleted)) {\n      if (!event.getPath().equals(leaderOffer.getNodePath())\n          && state != State.STOP) {\n        logger.debug(\n            \"Node {} deleted. Need to run through the election process.\",\n            event.getPath());\n        try {\n          determineElectionStatus();\n        } catch (KeeperException e) {\n          becomeFailed(e);\n        } catch (InterruptedException e) {\n          becomeFailed(e);\n        }\n      }\n    }\n  }\n\n  private void dispatchEvent(EventType eventType) {\n    logger.debug(\"Dispatching event:{}\", eventType);\n\n    synchronized (listeners) {\n      if (listeners.size() > 0) {\n        for (LeaderElectionAware observer : listeners) {\n          observer.onElectionEvent(eventType);\n        }\n      }\n    }\n  }\n\n  /**\n   * Adds {@code listener} to the list of listeners who will receive events.\n   * \n   * @param listener\n   */\n  public void addListener(LeaderElectionAware listener) {\n    listeners.add(listener);\n  }\n\n  /**\n   * Remove {@code listener} from the list of listeners who receive events.\n   * \n   * @param listener\n   */\n  public void removeListener(LeaderElectionAware listener) {\n    listeners.remove(listener);\n  }\n\n  @Override\n  public String toString() {\n    return \"{ state:\" + state + \" leaderOffer:\" + leaderOffer + \" zooKeeper:\"\n        + zooKeeper + \" hostName:\" + hostName + \" listeners:\" + listeners\n        + \" }\";\n  }\n\n  /**\n   * <p>\n   * Gets the ZooKeeper root node to use for this service.\n   * </p>\n   * <p>\n   * For instance, a root node of {@code /mycompany/myservice} would be the\n   * parent of all leader offers for this service. Obviously all processes that\n   * wish to contend for leader status need to use the same root node. Note: We\n   * assume this node already exists.\n   * </p>\n   * \n   * @return a znode path\n   */\n  public String getRootNodeName() {\n    return rootNodeName;\n  }\n\n  /**\n   * <p>\n   * Sets the ZooKeeper root node to use for this service.\n   * </p>\n   * <p>\n   * For instance, a root node of {@code /mycompany/myservice} would be the\n   * parent of all leader offers for this service. Obviously all processes that\n   * wish to contend for leader status need to use the same root node. Note: We\n   * assume this node already exists.\n   * </p>\n   */\n  public void setRootNodeName(String rootNodeName) {\n    this.rootNodeName = rootNodeName;\n  }\n\n  /**\n   * The {@link ZooKeeper} instance to use for all operations. Provided this\n   * overrides any connectString or sessionTimeout set.\n   */\n  public ZooKeeper getZooKeeper() {\n    return zooKeeper;\n  }\n\n  public void setZooKeeper(ZooKeeper zooKeeper) {\n    this.zooKeeper = zooKeeper;\n  }\n\n  /**\n   * The hostname of this process. Mostly used as a convenience for logging and\n   * to respond to {@link #getLeaderHostName()} requests.\n   */\n  public String getHostName() {\n    return hostName;\n  }\n\n  public void setHostName(String hostName) {\n    this.hostName = hostName;\n  }\n\n  /**\n   * The type of event.\n   */\n  public static enum EventType {\n    START, OFFER_START, OFFER_COMPLETE, DETERMINE_START, DETERMINE_COMPLETE, ELECTED_START, ELECTED_COMPLETE, READY_START, READY_COMPLETE, FAILED, STOP_START, STOP_COMPLETE,\n  }\n\n  /**\n   * The internal state of the election support service.\n   */\n  public static enum State {\n    START, OFFER, DETERMINE, ELECTED, READY, FAILED, STOP\n  }\n}\n"
  },
  {
    "path": "src/recipes/election/src/java/org/apache/zookeeper/recipes/leader/LeaderOffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.leader;\n\nimport java.util.Comparator;\n\n/**\n * A leader offer is a numeric id / path pair. The id is the sequential node id\n * assigned by ZooKeeper where as the path is the absolute path to the ZNode.\n */\npublic class LeaderOffer {\n\n  private Integer id;\n  private String nodePath;\n  private String hostName;\n\n  public LeaderOffer() {\n    // Default constructor\n  }\n\n  public LeaderOffer(Integer id, String nodePath, String hostName) {\n    this.id = id;\n    this.nodePath = nodePath;\n    this.hostName = hostName;\n  }\n\n  @Override\n  public String toString() {\n    return \"{ id:\" + id + \" nodePath:\" + nodePath + \" hostName:\" + hostName\n        + \" }\";\n  }\n\n  public Integer getId() {\n    return id;\n  }\n\n  public void setId(Integer id) {\n    this.id = id;\n  }\n\n  public String getNodePath() {\n    return nodePath;\n  }\n\n  public void setNodePath(String nodePath) {\n    this.nodePath = nodePath;\n  }\n\n  public String getHostName() {\n    return hostName;\n  }\n\n  public void setHostName(String hostName) {\n    this.hostName = hostName;\n  }\n\n  /**\n   * Compare two instances of {@link LeaderOffer} using only the {code}id{code}\n   * member.\n   */\n  public static class IdComparator implements Comparator<LeaderOffer> {\n\n    @Override\n    public int compare(LeaderOffer o1, LeaderOffer o2) {\n      return o1.getId().compareTo(o2.getId());\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "src/recipes/election/test/org/apache/zookeeper/recipes/leader/LeaderElectionSupportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.leader;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport junit.framework.Assert;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class LeaderElectionSupportTest extends ClientBase {\n\n  private static final Logger logger = LoggerFactory\n      .getLogger(LeaderElectionSupportTest.class);\n  private static final String testRootNode = \"/\" + System.currentTimeMillis()\n      + \"_\";\n\n  private ZooKeeper zooKeeper;\n\n  @Before\n  public void setUp() throws Exception {\n    super.setUp();\n\n    zooKeeper = createClient();\n\n    zooKeeper.create(testRootNode + Thread.currentThread().getId(),\n        new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n  }\n\n  @After\n  public void tearDown() throws Exception {\n    if (zooKeeper != null) {\n      zooKeeper.delete(testRootNode + Thread.currentThread().getId(), -1);\n    }\n\n    super.tearDown();\n  }\n\n  @Test\n  public void testNode() throws IOException, InterruptedException,\n      KeeperException {\n\n    LeaderElectionSupport electionSupport = createLeaderElectionSupport();\n\n    electionSupport.start();\n    Thread.sleep(3000);\n    electionSupport.stop();\n  }\n\n  @Test\n  public void testNodes3() throws IOException, InterruptedException,\n      KeeperException {\n\n    int testIterations = 3;\n    final CountDownLatch latch = new CountDownLatch(testIterations);\n    final AtomicInteger failureCounter = new AtomicInteger();\n\n    for (int i = 0; i < testIterations; i++) {\n      runElectionSupportThread(latch, failureCounter);\n    }\n\n    Assert.assertEquals(0, failureCounter.get());\n\n    if (!latch.await(10, TimeUnit.SECONDS)) {\n      logger\n          .info(\n              \"Waited for all threads to start, but timed out. We had {} failures.\",\n              failureCounter);\n    }\n  }\n\n  @Test\n  public void testNodes9() throws IOException, InterruptedException,\n      KeeperException {\n\n    int testIterations = 9;\n    final CountDownLatch latch = new CountDownLatch(testIterations);\n    final AtomicInteger failureCounter = new AtomicInteger();\n\n    for (int i = 0; i < testIterations; i++) {\n      runElectionSupportThread(latch, failureCounter);\n    }\n\n    Assert.assertEquals(0, failureCounter.get());\n\n    if (!latch.await(10, TimeUnit.SECONDS)) {\n      logger\n          .info(\n              \"Waited for all threads to start, but timed out. We had {} failures.\",\n              failureCounter);\n    }\n  }\n\n  @Test\n  public void testNodes20() throws IOException, InterruptedException,\n      KeeperException {\n\n    int testIterations = 20;\n    final CountDownLatch latch = new CountDownLatch(testIterations);\n    final AtomicInteger failureCounter = new AtomicInteger();\n\n    for (int i = 0; i < testIterations; i++) {\n      runElectionSupportThread(latch, failureCounter);\n    }\n\n    Assert.assertEquals(0, failureCounter.get());\n\n    if (!latch.await(10, TimeUnit.SECONDS)) {\n      logger\n          .info(\n              \"Waited for all threads to start, but timed out. We had {} failures.\",\n              failureCounter);\n    }\n  }\n\n  @Test\n  public void testNodes100() throws IOException, InterruptedException,\n      KeeperException {\n\n    int testIterations = 100;\n    final CountDownLatch latch = new CountDownLatch(testIterations);\n    final AtomicInteger failureCounter = new AtomicInteger();\n\n    for (int i = 0; i < testIterations; i++) {\n      runElectionSupportThread(latch, failureCounter);\n    }\n\n    Assert.assertEquals(0, failureCounter.get());\n\n    if (!latch.await(20, TimeUnit.SECONDS)) {\n      logger\n          .info(\n              \"Waited for all threads to start, but timed out. We had {} failures.\",\n              failureCounter);\n    }\n  }\n\n  @Test\n  public void testOfferShuffle() throws InterruptedException {\n    int testIterations = 10;\n    final CountDownLatch latch = new CountDownLatch(testIterations);\n    final AtomicInteger failureCounter = new AtomicInteger();\n    List<Thread> threads = new ArrayList<Thread>(testIterations);\n\n    for (int i = 1; i <= testIterations; i++) {\n      threads.add(runElectionSupportThread(latch, failureCounter,\n          Math.min(i * 1200, 10000)));\n    }\n\n    if (!latch.await(60, TimeUnit.SECONDS)) {\n      logger\n          .info(\n              \"Waited for all threads to start, but timed out. We had {} failures.\",\n              failureCounter);\n    }\n  }\n\n  @Test\n  public void testGetLeaderHostName() throws KeeperException,\n      InterruptedException {\n\n    LeaderElectionSupport electionSupport = createLeaderElectionSupport();\n\n    electionSupport.start();\n\n    // Sketchy: We assume there will be a leader (probably us) in 3 seconds.\n    Thread.sleep(3000);\n\n    String leaderHostName = electionSupport.getLeaderHostName();\n\n    Assert.assertNotNull(leaderHostName);\n    Assert.assertEquals(\"foohost\", leaderHostName);\n\n    electionSupport.stop();\n  }\n\n  private LeaderElectionSupport createLeaderElectionSupport() {\n    LeaderElectionSupport electionSupport = new LeaderElectionSupport();\n\n    electionSupport.setZooKeeper(zooKeeper);\n    electionSupport.setRootNodeName(testRootNode\n        + Thread.currentThread().getId());\n    electionSupport.setHostName(\"foohost\");\n\n    return electionSupport;\n  }\n\n  private Thread runElectionSupportThread(final CountDownLatch latch,\n      final AtomicInteger failureCounter) {\n    return runElectionSupportThread(latch, failureCounter, 3000);\n  }\n\n  private Thread runElectionSupportThread(final CountDownLatch latch,\n      final AtomicInteger failureCounter, final long sleepDuration) {\n\n    final LeaderElectionSupport electionSupport = createLeaderElectionSupport();\n\n    Thread t = new Thread() {\n\n      @Override\n      public void run() {\n        try {\n          electionSupport.start();\n          Thread.sleep(sleepDuration);\n          electionSupport.stop();\n\n          latch.countDown();\n        } catch (Exception e) {\n          logger.warn(\"Failed to run leader election due to: {}\",\n              e.getMessage());\n          failureCounter.incrementAndGet();\n        }\n      }\n    };\n\n    t.start();\n\n    return t;\n  }\n\n}\n"
  },
  {
    "path": "src/recipes/lock/README.txt",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n1) This lock interface recipe implements the lock recipe\nmentioned in ../../../docs/recipes.[html,pdf].\n\n2) To compile the lock java recipe you can just run ant jar from \nthis directory. For compiling the c libarary go to src/c and read\nthe INSTALLATION instructions. \nPlease report any bugs on the jira \n\nhttp://issues.apache.org/jira/browse/ZOOKEEPER\n\n  \n"
  },
  {
    "path": "src/recipes/lock/build.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"lock\" default=\"jar\">\n  <import file=\"../build-recipes.xml\"/>\n    <property name=\"test.main.classes\" value=\"${zk.root}/build/test/classes\"/>\n    <property name=\"test.build.dir\" value=\"${build.test}\" />\n    <property name=\"test.src.dir\" value=\"test\"/>\n    <property name=\"test.log.dir\" value=\"${test.build.dir}/logs\" />\n    <property name=\"test.data.dir\" value=\"${test.build.dir}/data\" />\n    <property name=\"test.data.upgrade.dir\" value=\"${test.data.dir}/upgrade\" />\n    <property name=\"test.tmp.dir\" value=\"${test.build.dir}/tmp\" />\n    <property name=\"test.output\" value=\"no\" />\n    <property name=\"test.timeout\" value=\"900000\" />\n    <property name=\"test.junit.output.format\" value=\"plain\" />\n    <property name=\"test.junit.fork.mode\" value=\"perTest\" />\n    <property name=\"test.junit.printsummary\" value=\"yes\" />\n    <property name=\"test.junit.haltonfailure\" value=\"no\" />\n    <property name=\"test.junit.maxmem\" value=\"512m\" />\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\"\n              value=\"${build.dir}/zookeeper-${version}-recipes-${name}.jar\"/>\n  </target>\n\n  <!-- Override jar target to specify main class -->\n  <target name=\"jar\" depends=\"checkMainCompiled, setjarname, compile\">\n    <echo message=\"recipes: ${name}\"/>\n\n    <jar jarfile=\"${jarname}\">\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset dir=\"${build.classes}\"/>\n      <fileset dir=\"${build.test}\"/>\n    </jar>\n  </target>\n\n\t<target name=\"test\" depends=\"compile-test,test-init,test-category,junit.run\" />\n\n\t<target name=\"compile-test\" depends=\"compile\">\n  \t\t<property name=\"target.jdk\" value=\"${ant.java.version}\" />\t\n\t\t<property name=\"src.test.local\" location=\"${basedir}/test\" />\n\t\t<mkdir dir=\"${build.test}\"/>\n\t\t<javac srcdir=\"${src.test.local}\" \n\t\t\tdestdir=\"${build.test}\" \n\t\t\ttarget=\"${target.jdk}\" \n\t\t\tdebug=\"on\" >\n\t\t\t<classpath refid=\"classpath\" />\n                        <classpath>\n                        <pathelement path=\"${test.main.classes}\"/>\n                        </classpath>\n\t\t</javac>\n\t</target>\n\t\n    <target name=\"test-init\" depends=\"jar,compile-test\">\n        <delete dir=\"${test.log.dir}\" />\n        <delete dir=\"${test.tmp.dir}\" />\n        <delete dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.tmp.dir}\" />\n        <mkdir dir=\"${test.data.dir}\" />\n    </target>\n\n\t<target name=\"test-category\">\n         <property name=\"test.category\" value=\"\"/>\n    </target>\n\n\t<target name=\"junit.run\">\n\t\t<echo message=\"${test.src.dir}\" />\n        <junit showoutput=\"${test.output}\"\n               printsummary=\"${test.junit.printsummary}\"\n               haltonfailure=\"${test.junit.haltonfailure}\"\n               fork=\"yes\"\n               forkmode=\"${test.junit.fork.mode}\"\n               maxmemory=\"${test.junit.maxmem}\"\n               dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n          <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n          <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n          <sysproperty key=\"log4j.configuration\"\n                    value=\"file:${basedir}/conf/log4j.properties\" />\n          <classpath refid=\"classpath\"/>\n          <classpath>\n             <pathelement path=\"${build.test}\" />\n             <pathelement path=\"${test.main.classes}\"/>\n          </classpath>\n          <formatter type=\"${test.junit.output.format}\" />\n          <batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n              <fileset dir=\"${test.src.dir}\"\n                     includes=\"**/*${test.category}Test.java\"/>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n              <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n          </batchtest>\n       </junit>\n            <fail if=\"tests.failed\">Tests failed!</fail>\n    </target>\n\n  <target name=\"package\" depends=\"jar, zookeeperbuildrecipes.package\"\n          unless=\"skip.recipes\">\n\n    <copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}${package.share}/recipes/${name}\"/>\n\n    <mkdir dir=\"${dist.dir}${package.share}/recipes/${name}/test\"/>\n    <copy todir=\"${dist.dir}${package.share}/recipes/${name}/test\">\n      <fileset dir=\"${basedir}/test\"/>\n    </copy>\n    <mkdir dir=\"${dist.dir}${package.share}/recipes/${name}/src\"/>\n    <copy todir=\"${dist.dir}${package.share}/recipes/${name}/src\">\n      <fileset dir=\"${basedir}/src\"/>\n    </copy>\n  </target>\n\n</project>\n\n"
  },
  {
    "path": "src/recipes/lock/src/c/INSTALL",
    "content": "Installation Instructions\n*************************\n\nCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,\n2006 Free Software Foundation, Inc.\n\nThis file is free documentation; the Free Software Foundation gives\nunlimited permission to copy, distribute and modify it.\n\nBasic Installation\n==================\n\nBriefly, the shell commands `./configure; make; make install' should\nconfigure, build, and install this package.  The following\nmore-detailed instructions are generic; see the `README' file for\ninstructions specific to this package.\n\n   The `configure' shell script attempts to guess correct values for\nvarious system-dependent variables used during compilation.  It uses\nthose values to create a `Makefile' in each directory of the package.\nIt may also create one or more `.h' files containing system-dependent\ndefinitions.  Finally, it creates a shell script `config.status' that\nyou can run in the future to recreate the current configuration, and a\nfile `config.log' containing compiler output (useful mainly for\ndebugging `configure').\n\n   It can also use an optional file (typically called `config.cache'\nand enabled with `--cache-file=config.cache' or simply `-C') that saves\nthe results of its tests to speed up reconfiguring.  Caching is\ndisabled by default to prevent problems with accidental use of stale\ncache files.\n\n   If you need to do unusual things to compile the package, please try\nto figure out how `configure' could check whether to do them, and mail\ndiffs or instructions to the address given in the `README' so they can\nbe considered for the next release.  If you are using the cache, and at\nsome point `config.cache' contains results you don't want to keep, you\nmay remove or edit it.\n\n   The file `configure.ac' (or `configure.in') is used to create\n`configure' by a program called `autoconf'.  You need `configure.ac' if\nyou want to change it or regenerate `configure' using a newer version\nof `autoconf'.\n\nThe simplest way to compile this package is:\n\n  1. `cd' to the directory containing the package's source code and type\n     `./configure' to configure the package for your system.\n\n     Running `configure' might take a while.  While running, it prints\n     some messages telling which features it is checking for.\n\n  2. Type `make' to compile the package.\n\n  3. Optionally, type `make check' to run any self-tests that come with\n     the package.\n\n  4. Type `make install' to install the programs and any data files and\n     documentation.\n\n  5. You can remove the program binaries and object files from the\n     source code directory by typing `make clean'.  To also remove the\n     files that `configure' created (so you can compile the package for\n     a different kind of computer), type `make distclean'.  There is\n     also a `make maintainer-clean' target, but that is intended mainly\n     for the package's developers.  If you use it, you may have to get\n     all sorts of other programs in order to regenerate files that came\n     with the distribution.\n\nCompilers and Options\n=====================\n\nSome systems require unusual options for compilation or linking that the\n`configure' script does not know about.  Run `./configure --help' for\ndetails on some of the pertinent environment variables.\n\n   You can give `configure' initial values for configuration parameters\nby setting variables in the command line or in the environment.  Here\nis an example:\n\n     ./configure CC=c99 CFLAGS=-g LIBS=-lposix\n\n   *Note Defining Variables::, for more details.\n\nCompiling For Multiple Architectures\n====================================\n\nYou can compile the package for more than one kind of computer at the\nsame time, by placing the object files for each architecture in their\nown directory.  To do this, you can use GNU `make'.  `cd' to the\ndirectory where you want the object files and executables to go and run\nthe `configure' script.  `configure' automatically checks for the\nsource code in the directory that `configure' is in and in `..'.\n\n   With a non-GNU `make', it is safer to compile the package for one\narchitecture at a time in the source code directory.  After you have\ninstalled the package for one architecture, use `make distclean' before\nreconfiguring for another architecture.\n\nInstallation Names\n==================\n\nBy default, `make install' installs the package's commands under\n`/usr/local/bin', include files under `/usr/local/include', etc.  You\ncan specify an installation prefix other than `/usr/local' by giving\n`configure' the option `--prefix=PREFIX'.\n\n   You can specify separate installation prefixes for\narchitecture-specific files and architecture-independent files.  If you\npass the option `--exec-prefix=PREFIX' to `configure', the package uses\nPREFIX as the prefix for installing programs and libraries.\nDocumentation and other data files still use the regular prefix.\n\n   In addition, if you use an unusual directory layout you can give\noptions like `--bindir=DIR' to specify different values for particular\nkinds of files.  Run `configure --help' for a list of the directories\nyou can set and what kinds of files go in them.\n\n   If the package supports it, you can cause programs to be installed\nwith an extra prefix or suffix on their names by giving `configure' the\noption `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.\n\nOptional Features\n=================\n\nSome packages pay attention to `--enable-FEATURE' options to\n`configure', where FEATURE indicates an optional part of the package.\nThey may also pay attention to `--with-PACKAGE' options, where PACKAGE\nis something like `gnu-as' or `x' (for the X Window System).  The\n`README' should mention any `--enable-' and `--with-' options that the\npackage recognizes.\n\n   For packages that use the X Window System, `configure' can usually\nfind the X include and library files automatically, but if it doesn't,\nyou can use the `configure' options `--x-includes=DIR' and\n`--x-libraries=DIR' to specify their locations.\n\nSpecifying the System Type\n==========================\n\nThere may be some features `configure' cannot figure out automatically,\nbut needs to determine by the type of machine the package will run on.\nUsually, assuming the package is built to be run on the _same_\narchitectures, `configure' can figure that out, but if it prints a\nmessage saying it cannot guess the machine type, give it the\n`--build=TYPE' option.  TYPE can either be a short name for the system\ntype, such as `sun4', or a canonical name which has the form:\n\n     CPU-COMPANY-SYSTEM\n\nwhere SYSTEM can have one of these forms:\n\n     OS KERNEL-OS\n\n   See the file `config.sub' for the possible values of each field.  If\n`config.sub' isn't included in this package, then this package doesn't\nneed to know the machine type.\n\n   If you are _building_ compiler tools for cross-compiling, you should\nuse the option `--target=TYPE' to select the type of system they will\nproduce code for.\n\n   If you want to _use_ a cross compiler, that generates code for a\nplatform different from the build platform, you should specify the\n\"host\" platform (i.e., that on which the generated programs will\neventually be run) with `--host=TYPE'.\n\nSharing Defaults\n================\n\nIf you want to set default values for `configure' scripts to share, you\ncan create a site shell script called `config.site' that gives default\nvalues for variables like `CC', `cache_file', and `prefix'.\n`configure' looks for `PREFIX/share/config.site' if it exists, then\n`PREFIX/etc/config.site' if it exists.  Or, you can set the\n`CONFIG_SITE' environment variable to the location of the site script.\nA warning: not all `configure' scripts look for a site script.\n\nDefining Variables\n==================\n\nVariables not defined in a site shell script can be set in the\nenvironment passed to `configure'.  However, some packages may run\nconfigure again during the build, and the customized values of these\nvariables may be lost.  In order to avoid this problem, you should set\nthem in the `configure' command line, using `VAR=value'.  For example:\n\n     ./configure CC=/usr/local2/bin/gcc\n\ncauses the specified `gcc' to be used as the C compiler (unless it is\noverridden in the site shell script).\n\nUnfortunately, this technique does not work for `CONFIG_SHELL' due to\nan Autoconf bug.  Until the bug is fixed you can use this workaround:\n\n     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash\n\n`configure' Invocation\n======================\n\n`configure' recognizes the following options to control how it operates.\n\n`--help'\n`-h'\n     Print a summary of the options to `configure', and exit.\n\n`--version'\n`-V'\n     Print the version of Autoconf used to generate the `configure'\n     script, and exit.\n\n`--cache-file=FILE'\n     Enable the cache: use and save the results of the tests in FILE,\n     traditionally `config.cache'.  FILE defaults to `/dev/null' to\n     disable caching.\n\n`--config-cache'\n`-C'\n     Alias for `--cache-file=config.cache'.\n\n`--quiet'\n`--silent'\n`-q'\n     Do not print messages saying which checks are being made.  To\n     suppress all normal output, redirect it to `/dev/null' (any error\n     messages will still be shown).\n\n`--srcdir=DIR'\n     Look for the package's source code in directory DIR.  Usually\n     `configure' can determine that directory automatically.\n\n`configure' also accepts some other, not widely useful, options.  Run\n`configure --help' for more details.\n\n"
  },
  {
    "path": "src/recipes/lock/src/c/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/recipes/lock/src/c/Makefile.am",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ninclude $(top_srcdir)/aminclude.am\n\nAM_CFLAGS = -Wall -fPIC -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated \\\n  -I$(top_srcdir)/include -I/usr/include \nAM_CPPFLAGS = -Wall -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated\\\n  -I${top_srcdir}/include -I/usr/include\nEXTRA_DIST = LICENSE\nlib_LTLIBRARIES = libzoolock.la\nlibzoolock_la_SOURCES = src/zoo_lock.c include/zoo_lock.h\nlibzoolock_la_CPPFLAGS = -DDLOPEN_MODULE\nlibzoolock_la_LDFLAGS = -version-info 0:1:0\n\n#run the tests now\n\nTEST_SOURCES = tests/TestDriver.cc tests/TestClient.cc tests/Util.cc \n\n\ncheck_PROGRAMS = zklocktest\nnodist_zklocktest_SOURCES = ${TEST_SOURCES}\nzklocktest_LDADD =  ${ZOOKEEPER_LD} libzoolock.la -lpthread  ${CPPUNIT_LIBS}\nzklocktest_CXXFLAGS = -DUSE_STATIC_LIB ${CPPUNIT_CFLAGS}\n\nrun-check: check\n\t./zklocktest ${TEST_OPTIONS}\n\nclean-local: clean-check\n\t${RM} ${DX_CLEANFILES}\n\nclean-check:\n\t${RM} ${nodist_zklocktest_OBJECTS} \n"
  },
  {
    "path": "src/recipes/lock/src/c/README.txt",
    "content": "                     Zookeeper C lock client library \n\n\nINSTALLATION\n\nIf you're building the client from a source checkout you need to\nfollow the steps outlined below. If you're building from a release\ntar downloaded from Apache please skip to step 2.\n\n1) make sure that you compile the main zookeeper c client library.\n \n2) change directory to src/recipes/lock/src/c \n    and do a \"autoreconf -if\" to bootstrap\n   autoconf, automake and libtool. Please make sure you have autoconf\n   version 2.59 or greater installed.\n3) do a \"./configure [OPTIONS]\" to generate the makefile. See INSTALL\n   for general information about running configure.\n\n4) do a \"make\" or \"make install\" to build the libraries and install them. \n   Alternatively, you can also build and run a unit test suite (and\n   you probably should).  Please make sure you have cppunit-1.10.x or\n   higher installed before you execute step 4.  Once ./configure has\n   finished, do a \"make run-check\". It will build the libraries, build\n   the tests and run them.\n5) to generate doxygen documentation do a \"make doxygen-doc\". All\n   documentations will be placed to a new subfolder named docs. By\n   default only HTML documentation is generated.  For information on\n   other document formats please use \"./configure --help\"\n"
  },
  {
    "path": "src/recipes/lock/src/c/acinclude.m4",
    "content": "# This file is part of Autoconf.                       -*- Autoconf -*-\n\n# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Autoconf macro files.\n\n# Generate automatic documentation using Doxygen. Works in concert with the\n# aminclude.m4 file and a compatible doxygen configuration file. Defines the\n# following public macros:\n#\n# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.\n# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,\n# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'\n# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',\n# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment\n# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'\n# paper size.\n#\n# By default, HTML, PDF and PS documentation is generated as this seems to be\n# the most popular and portable combination. MAN pages created by Doxygen are\n# usually problematic, though by picking an appropriate subset and doing some\n# massaging they might be better than nothing. CHM and RTF are specific for MS\n# (note that you can't generate both HTML and CHM at the same time). The XML is\n# rather useless unless you apply specialized post-processing to it.\n#\n# The macro mainly controls the default state of the feature. The use can\n# override the default by specifying --enable or --disable. The macros ensure\n# that contradictory flags are not given (e.g., --enable-doxygen-html and\n# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)\n# Finally, each feature will be automatically disabled (with a warning) if the\n# required programs are missing.\n#\n# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with\n# the following parameters: a one-word name for the project for use as a\n# filename base etc., an optional configuration file name (the default is\n# 'Doxyfile', the same as Doxygen's default), and an optional output directory\n# name (the default is 'doxygen-doc').\n\n## ----------##\n## Defaults. ##\n## ----------##\n\nDX_ENV=\"\"\nAC_DEFUN([DX_FEATURE_doc],  ON)\nAC_DEFUN([DX_FEATURE_dot],  ON)\nAC_DEFUN([DX_FEATURE_man],  OFF)\nAC_DEFUN([DX_FEATURE_html], ON)\nAC_DEFUN([DX_FEATURE_chm],  OFF)\nAC_DEFUN([DX_FEATURE_chi],  OFF)\nAC_DEFUN([DX_FEATURE_rtf],  OFF)\nAC_DEFUN([DX_FEATURE_xml],  OFF)\nAC_DEFUN([DX_FEATURE_pdf],  ON)\nAC_DEFUN([DX_FEATURE_ps],   ON)\n\n## --------------- ##\n## Private macros. ##\n## --------------- ##\n\n# DX_ENV_APPEND(VARIABLE, VALUE)\n# ------------------------------\n# Append VARIABLE=\"VALUE\" to DX_ENV for invoking doxygen.\nAC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], [\"$DX_ENV $1='$2'\"])])\n\n# DX_DIRNAME_EXPR\n# ---------------\n# Expand into a shell expression prints the directory part of a path.\nAC_DEFUN([DX_DIRNAME_EXPR],\n         [[expr \".$1\" : '\\(\\.\\)[^/]*$' \\| \"x$1\" : 'x\\(.*\\)/[^/]*$']])\n\n# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)\n# -------------------------------------\n# Expands according to the M4 (static) status of the feature.\nAC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])\n\n# DX_REQUIRE_PROG(VARIABLE, PROGRAM)\n# ----------------------------------\n# Require the specified program to be found for the DX_CURRENT_FEATURE to work.\nAC_DEFUN([DX_REQUIRE_PROG], [\nAC_PATH_TOOL([$1], [$2])\nif test \"$DX_FLAG_$[DX_CURRENT_FEATURE$$1]\" = 1; then\n    AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])\n    AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\nfi\n])\n\n# DX_TEST_FEATURE(FEATURE)\n# ------------------------\n# Expand to a shell expression testing whether the feature is active.\nAC_DEFUN([DX_TEST_FEATURE], [test \"$DX_FLAG_$1\" = 1])\n\n# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)\n# -------------------------------------------------\n# Verify that a required features has the right state before trying to turn on\n# the DX_CURRENT_FEATURE.\nAC_DEFUN([DX_CHECK_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" \\\n|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,\n                            requires, contradicts) doxygen-DX_CURRENT_FEATURE])\n])\n\n# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)\n# ----------------------------------------------------------\n# Turn off the DX_CURRENT_FEATURE if the required feature is off.\nAC_DEFUN([DX_CLEAR_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" || AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\n])\n\n# DX_FEATURE_ARG(FEATURE, DESCRIPTION,\n#                CHECK_DEPEND, CLEAR_DEPEND,\n#                REQUIRE, DO-IF-ON, DO-IF-OFF)\n# --------------------------------------------\n# Parse the command-line option controlling a feature. CHECK_DEPEND is called\n# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),\n# otherwise CLEAR_DEPEND is called to turn off the default state if a required\n# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional\n# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and\n# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.\nAC_DEFUN([DX_ARG_ABLE], [\n    AC_DEFUN([DX_CURRENT_FEATURE], [$1])\n    AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])\n    AC_ARG_ENABLE(doxygen-$1,\n                  [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],\n                                                      [--enable-doxygen-$1]),\n                                  DX_IF_FEATURE([$1], [don't $2], [$2]))],\n                  [\ncase \"$enableval\" in\n#(\ny|Y|yes|Yes|YES)\n    AC_SUBST([DX_FLAG_$1], 1)\n    $3\n;; #(\nn|N|no|No|NO)\n    AC_SUBST([DX_FLAG_$1], 0)\n;; #(\n*)\n    AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])\n;;\nesac\n], [\nAC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])\n$4\n])\nif DX_TEST_FEATURE([$1]); then\n    $5\n    :\nfi\nif DX_TEST_FEATURE([$1]); then\n    AM_CONDITIONAL(DX_COND_$1, :)\n    $6\n    :\nelse\n    AM_CONDITIONAL(DX_COND_$1, false)\n    $7\n    :\nfi\n])\n\n## -------------- ##\n## Public macros. ##\n## -------------- ##\n\n# DX_XXX_FEATURE(DEFAULT_STATE)\n# -----------------------------\nAC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc],  [$1])])\nAC_DEFUN([DX_MAN_FEATURE],     [AC_DEFUN([DX_FEATURE_man],  [$1])])\nAC_DEFUN([DX_HTML_FEATURE],    [AC_DEFUN([DX_FEATURE_html], [$1])])\nAC_DEFUN([DX_CHM_FEATURE],     [AC_DEFUN([DX_FEATURE_chm],  [$1])])\nAC_DEFUN([DX_CHI_FEATURE],     [AC_DEFUN([DX_FEATURE_chi],  [$1])])\nAC_DEFUN([DX_RTF_FEATURE],     [AC_DEFUN([DX_FEATURE_rtf],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])\nAC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])\n\n# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])\n# ---------------------------------------------------------\n# PROJECT also serves as the base name for the documentation files.\n# The default CONFIG-FILE is \"Doxyfile\" and OUTPUT-DOC-DIR is \"doxygen-doc\".\nAC_DEFUN([DX_INIT_DOXYGEN], [\n\n# Files:\nAC_SUBST([DX_PROJECT], [$1])\nAC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])\nAC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])\n\n# Environment variables used inside doxygen.cfg:\nDX_ENV_APPEND(SRCDIR, $srcdir)\nDX_ENV_APPEND(PROJECT, $DX_PROJECT)\nDX_ENV_APPEND(DOCDIR, $DX_DOCDIR)\nDX_ENV_APPEND(VERSION, $PACKAGE_VERSION)\n\n# Doxygen itself:\nDX_ARG_ABLE(doc, [generate any doxygen documentation],\n            [],\n            [],\n            [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)\n             DX_REQUIRE_PROG([DX_PERL], perl)],\n            [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])\n\n# Dot for graphics:\nDX_ARG_ABLE(dot, [generate graphics for doxygen documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_DOT], dot)],\n            [DX_ENV_APPEND(HAVE_DOT, YES)\n             DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],\n            [DX_ENV_APPEND(HAVE_DOT, NO)])\n\n# Man pages generation:\nDX_ARG_ABLE(man, [generate doxygen manual pages],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_MAN, YES)],\n            [DX_ENV_APPEND(GENERATE_MAN, NO)])\n\n# RTF file generation:\nDX_ARG_ABLE(rtf, [generate doxygen RTF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_RTF, YES)],\n            [DX_ENV_APPEND(GENERATE_RTF, NO)])\n\n# XML file generation:\nDX_ARG_ABLE(xml, [generate doxygen XML documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_XML, YES)],\n            [DX_ENV_APPEND(GENERATE_XML, NO)])\n\n# (Compressed) HTML help generation:\nDX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_HHC], hhc)],\n            [DX_ENV_APPEND(HHC_PATH, $DX_HHC)\n             DX_ENV_APPEND(GENERATE_HTML, YES)\n             DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],\n            [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])\n\n# Seperate CHI file generation.\nDX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],\n            [DX_CHECK_DEPEND(chm, 1)],\n            [DX_CLEAR_DEPEND(chm, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_CHI, YES)],\n            [DX_ENV_APPEND(GENERATE_CHI, NO)])\n\n# Plain HTML pages generation:\nDX_ARG_ABLE(html, [generate doxygen plain HTML documentation],\n            [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],\n            [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],\n            [],\n            [DX_ENV_APPEND(GENERATE_HTML, YES)],\n            [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])\n\n# PostScript file generation:\nDX_ARG_ABLE(ps, [generate doxygen PostScript documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_LATEX], latex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_DVIPS], dvips)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# PDF file generation:\nDX_ARG_ABLE(pdf, [generate doxygen PDF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# LaTeX generation for PS and/or PDF:\nif DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then\n    AM_CONDITIONAL(DX_COND_latex, :)\n    DX_ENV_APPEND(GENERATE_LATEX, YES)\nelse\n    AM_CONDITIONAL(DX_COND_latex, false)\n    DX_ENV_APPEND(GENERATE_LATEX, NO)\nfi\n\n# Paper size for PS and/or PDF:\nAC_ARG_VAR(DOXYGEN_PAPER_SIZE,\n           [a4wide (default), a4, letter, legal or executive])\ncase \"$DOXYGEN_PAPER_SIZE\" in\n#(\n\"\")\n    AC_SUBST(DOXYGEN_PAPER_SIZE, \"\")\n;; #(\na4wide|a4|letter|legal|executive)\n    DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)\n;; #(\n*)\n    AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])\n;;\nesac\n\n#For debugging:\n#echo DX_FLAG_doc=$DX_FLAG_doc\n#echo DX_FLAG_dot=$DX_FLAG_dot\n#echo DX_FLAG_man=$DX_FLAG_man\n#echo DX_FLAG_html=$DX_FLAG_html\n#echo DX_FLAG_chm=$DX_FLAG_chm\n#echo DX_FLAG_chi=$DX_FLAG_chi\n#echo DX_FLAG_rtf=$DX_FLAG_rtf\n#echo DX_FLAG_xml=$DX_FLAG_xml\n#echo DX_FLAG_pdf=$DX_FLAG_pdf\n#echo DX_FLAG_ps=$DX_FLAG_ps\n#echo DX_ENV=$DX_ENV\n])\n"
  },
  {
    "path": "src/recipes/lock/src/c/aminclude.am",
    "content": "# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Automake macro files.\n\n# Generate automatic documentation using Doxygen. Goals and variables values\n# are controlled by the various DX_COND_??? conditionals set by autoconf.\n#\n# The provided goals are:\n# doxygen-doc: Generate all doxygen documentation.\n# doxygen-run: Run doxygen, which will generate some of the documentation\n#              (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post\n#              processing required for the rest of it (PS, PDF, and some MAN).\n# doxygen-man: Rename some doxygen generated man pages.\n# doxygen-ps: Generate doxygen PostScript documentation.\n# doxygen-pdf: Generate doxygen PDF documentation.\n#\n# Note that by default these are not integrated into the automake goals. If\n# doxygen is used to generate man pages, you can achieve this integration by\n# setting man3_MANS to the list of man pages generated and then adding the\n# dependency:\n#\n#   $(man3_MANS): doxygen-doc\n#\n# This will cause make to run doxygen and generate all the documentation.\n#\n# The following variable is intended for use in Makefile.am:\n#\n# DX_CLEANFILES = everything to clean.\n#\n# This is usually added to MOSTLYCLEANFILES.\n\n## --------------------------------- ##\n## Format-independent Doxygen rules. ##\n## --------------------------------- ##\n\nif DX_COND_doc\n\n## ------------------------------- ##\n## Rules specific for HTML output. ##\n## ------------------------------- ##\n\nif DX_COND_html\n\nDX_CLEAN_HTML = @DX_DOCDIR@/html\n\nendif DX_COND_html\n\n## ------------------------------ ##\n## Rules specific for CHM output. ##\n## ------------------------------ ##\n\nif DX_COND_chm\n\nDX_CLEAN_CHM = @DX_DOCDIR@/chm\n\nif DX_COND_chi\n\nDX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi\n\nendif DX_COND_chi\n\nendif DX_COND_chm\n\n## ------------------------------ ##\n## Rules specific for MAN output. ##\n## ------------------------------ ##\n\nif DX_COND_man\n\nDX_CLEAN_MAN = @DX_DOCDIR@/man\n\nendif DX_COND_man\n\n## ------------------------------ ##\n## Rules specific for RTF output. ##\n## ------------------------------ ##\n\nif DX_COND_rtf\n\nDX_CLEAN_RTF = @DX_DOCDIR@/rtf\n\nendif DX_COND_rtf\n\n## ------------------------------ ##\n## Rules specific for XML output. ##\n## ------------------------------ ##\n\nif DX_COND_xml\n\nDX_CLEAN_XML = @DX_DOCDIR@/xml\n\nendif DX_COND_xml\n\n## ----------------------------- ##\n## Rules specific for PS output. ##\n## ----------------------------- ##\n\nif DX_COND_ps\n\nDX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps\n\nDX_PS_GOAL = doxygen-ps\n\ndoxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps\n\n@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_LATEX) refman.tex; \\\n\t$(MAKEINDEX_PATH) refman.idx; \\\n\t$(DX_LATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_LATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\t$(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi\n\nendif DX_COND_ps\n\n## ------------------------------ ##\n## Rules specific for PDF output. ##\n## ------------------------------ ##\n\nif DX_COND_pdf\n\nDX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf\n\nDX_PDF_GOAL = doxygen-pdf\n\ndoxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf\n\n@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\t$(DX_MAKEINDEX) refman.idx; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_PDFLATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\tmv refman.pdf ../@PACKAGE@.pdf\n\nendif DX_COND_pdf\n\n## ------------------------------------------------- ##\n## Rules specific for LaTeX (shared for PS and PDF). ##\n## ------------------------------------------------- ##\n\nif DX_COND_latex\n\nDX_CLEAN_LATEX = @DX_DOCDIR@/latex\n\nendif DX_COND_latex\n\n.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\ndoxygen-run: @DX_DOCDIR@/@PACKAGE@.tag\n\ndoxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)\n\trm -rf @DX_DOCDIR@\n\t$(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)\n\nDX_CLEANFILES = \\\n    @DX_DOCDIR@/@PACKAGE@.tag \\\n    -r \\\n    $(DX_CLEAN_HTML) \\\n    $(DX_CLEAN_CHM) \\\n    $(DX_CLEAN_CHI) \\\n    $(DX_CLEAN_MAN) \\\n    $(DX_CLEAN_RTF) \\\n    $(DX_CLEAN_XML) \\\n    $(DX_CLEAN_PS) \\\n    $(DX_CLEAN_PDF) \\\n    $(DX_CLEAN_LATEX)\n\nendif DX_COND_doc\n"
  },
  {
    "path": "src/recipes/lock/src/c/c-doc.Doxyfile",
    "content": "# Doxyfile 1.4.7\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project\n#\n# All text after a hash (#) is considered a comment and will be ignored\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \")\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \n# by quotes) that should identify the project.\n\nPROJECT_NAME = $(PROJECT)-$(VERSION)\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. \n# This could be handy for archiving the generated documentation or \n# if some version control system is used.\n\nPROJECT_NUMBER = \n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \n# base path where the generated documentation will be put. \n# If a relative path is entered, it will be relative to the location \n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY = $(DOCDIR)\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \n# 4096 sub-directories (in 2 levels) under the output directory of each output \n# format and will distribute the generated files over these directories. \n# Enabling this option can be useful when feeding doxygen a huge amount of \n# source files, where putting all generated files in the same directory would \n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all \n# documentation generated by doxygen is written. Doxygen will use this \n# information to generate all constant output in the proper language. \n# The default language is English, other supported languages are: \n# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \n# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \n# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \n# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \n# Swedish, and Ukrainian.\n\nOUTPUT_LANGUAGE = English\n\n# This tag can be used to specify the encoding used in the generated output. \n# The encoding is not always determined by the language that is chosen, \n# but also whether or not the output is meant for Windows or non-Windows users. \n# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \n# forces the Windows encoding (this is the default for the Windows binary), \n# whereas setting the tag to NO uses a Unix-style encoding (the default for \n# all platforms other than Windows).\n\nUSE_WINDOWS_ENCODING = NO\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n# include brief member descriptions after the members that are listed in \n# the file and class documentation (similar to JavaDoc). \n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n# the brief description of a member or function before the detailed description. \n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator \n# that is used to form the text in various listings. Each string \n# in this list, if found as the leading text of the brief description, will be \n# stripped from the text and the result after processing the whole list, is \n# used as the annotated text. Otherwise, the brief description is used as-is. \n# If left blank, the following values are used (\"$name\" is automatically \n# replaced with the name of the entity): \"The $name class\" \"The $name widget\" \n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\" \n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF = \n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n# Doxygen will generate a detailed section even if there is only a brief \n# description.\n\nALWAYS_DETAILED_SEC = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all \n# inherited members of a class in the documentation of that class as if those \n# members were ordinary class members. Constructors, destructors and assignment \n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n# path before files name in the file list and in the header files. If set \n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES = YES\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n# can be used to strip a user-defined part of the path. Stripping is \n# only done if one of the specified strings matches the left-hand part of \n# the path. The tag can be used to show relative paths in the file list. \n# If left blank the directory from which doxygen is run is used as the \n# path to strip.\n\nSTRIP_FROM_PATH = \n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \n# the path mentioned in the documentation of a class, which tells \n# the reader which header file to include in order to use a class. \n# If left blank only the name of the header file containing the class \n# definition is used. Otherwise one should specify the include paths that \n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH = \n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n# (but less readable) file names. This can be useful is your file systems \n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n# will interpret the first line (until the first dot) of a JavaDoc-style \n# comment as the brief description. If set to NO, the JavaDoc \n# comments will behave just like the Qt-style comments (thus requiring an \n# explicit @brief command for a brief description.\n\nJAVADOC_AUTOBRIEF = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n# treat a multi-line C++ special comment block (i.e. a block of //! or /// \n# comments) as a brief description. This used to be the default behaviour. \n# The new default is to treat a multi-line C++ comment block as a detailed \n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the DETAILS_AT_TOP tag is set to YES then Doxygen \n# will output the detailed description near the top, like JavaDoc.\n# If set to NO, the detailed description appears after the member \n# documentation.\n\nDETAILS_AT_TOP = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n# member inherits the documentation from any documented member that it \n# re-implements.\n\nINHERIT_DOCS = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce \n# a new page for each member. If set to NO, the documentation of a member will \n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. \n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE = 8\n\n# This tag can be used to specify a number of aliases that acts \n# as commands in the documentation. An alias has the form \"name=value\". \n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n# put the command \\sideeffect (or @sideeffect) in the documentation, which \n# will result in a user-defined paragraph with heading \"Side Effects:\". \n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES = \n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C \n# sources only. Doxygen will then generate output that is more tailored for C. \n# For instance, some of the names that are used will be different. The list \n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java \n# sources only. Doxygen will then generate output that is more tailored for Java. \n# For instance, namespaces will be presented as packages, qualified scopes \n# will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA = NO\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to \n# include (a tag file for) the STL sources as input, then you should \n# set this tag to YES in order to let doxygen match functions declarations and \n# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. \n# func(std::string) {}). This also make the inheritance and collaboration \n# diagrams that involve STL classes more complete and accurate.\n\nBUILTIN_STL_SUPPORT = NO\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n# tag is set to YES, then doxygen will reuse the documentation of the first \n# member in the group (if any) for the other members of the group. By default \n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n# the same type (for instance a group of public functions) to be put as a \n# subgroup of that type (e.g. under the Public Functions section). Set it to \n# NO to prevent subgrouping. Alternatively, this can be done per class using \n# the \\nosubgrouping command.\n\nSUBGROUPING = YES\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \n# documentation are documented, even if no documentation was available. \n# Private class members and static file members will be hidden unless \n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \n# will be included in the documentation.\n\nEXTRACT_PRIVATE = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file \n# will be included in the documentation.\n\nEXTRACT_STATIC = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \n# defined locally in source files will be included in the documentation. \n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES = YES\n\n# This flag is only useful for Objective-C code. When set to YES local \n# methods, which are defined in the implementation section but not in \n# the interface are included in the documentation. \n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \n# undocumented members of documented classes, files or namespaces. \n# If set to NO (the default) these members will be included in the \n# various overviews, but no documentation section is generated. \n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \n# undocumented classes that are normally visible in the class hierarchy. \n# If set to NO (the default) these classes will be included in the various \n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \n# friend (class|struct|union) declarations. \n# If set to NO (the default) these declarations will be included in the \n# documentation.\n\nHIDE_FRIEND_COMPOUNDS = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \n# documentation blocks found inside the body of a function. \n# If set to NO (the default) these blocks will be appended to the \n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS = NO\n\n# The INTERNAL_DOCS tag determines if documentation \n# that is typed after a \\internal command is included. If the tag is set \n# to NO (the default) then the documentation will be excluded. \n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \n# file names in lower-case letters. If set to YES upper-case letters are also \n# allowed. This is useful if you have classes or files whose names only differ \n# in case and if your file system supports case sensitive file names. Windows \n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \n# will show members with their full class and namespace scopes in the \n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \n# will put a list of the files that are included by a file in the documentation \n# of that file.\n\nSHOW_INCLUDE_FILES = NO\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \n# is inserted in the documentation for inline members.\n\nINLINE_INFO = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \n# will sort the (detailed) documentation of file and class members \n# alphabetically by member name. If set to NO the members will appear in \n# declaration order.\n\nSORT_MEMBER_DOCS = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \n# brief documentation of file, namespace and class members alphabetically \n# by member name. If set to NO (the default) the members will appear in \n# declaration order.\n\nSORT_BRIEF_DOCS = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \n# sorted by fully-qualified names, including namespaces. If set to \n# NO (the default), the class list will be sorted only by class name, \n# not including the namespace part. \n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the \n# alphabetical list.\n\nSORT_BY_SCOPE_NAME = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or \n# disable (NO) the todo list. This list is created by putting \\todo \n# commands in the documentation.\n\nGENERATE_TODOLIST = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or \n# disable (NO) the test list. This list is created by putting \\test \n# commands in the documentation.\n\nGENERATE_TESTLIST = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or \n# disable (NO) the bug list. This list is created by putting \\bug \n# commands in the documentation.\n\nGENERATE_BUGLIST = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \n# disable (NO) the deprecated list. This list is created by putting \n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST = YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional \n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS = \n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \n# the initial value of a variable or define consists of for it to appear in \n# the documentation. If the initializer consists of more lines than specified \n# here it will be hidden. Use a value of 0 to hide initializers completely. \n# The appearance of the initializer of individual variables and defines in the \n# documentation can be controlled using \\showinitializer or \\hideinitializer \n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \n# at the bottom of the documentation of classes and structs. If set to YES the \n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES = YES\n\n# If the sources in your project are distributed over multiple directories \n# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \n# in the documentation. The default is NO.\n\nSHOW_DIRECTORIES = NO\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that \n# doxygen should invoke to get the current version for each file (typically from the \n# version control system). Doxygen will invoke the program by executing (via \n# popen()) the command <command> <input-file>, where <command> is the value of \n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file \n# provided by doxygen. Whatever the program writes to standard output \n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER = \n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated \n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are \n# generated by doxygen. Possible values are YES and NO. If left blank \n# NO is used.\n\nWARNINGS = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \n# potential errors in the documentation, such as not documenting some \n# parameters in a documented function, or documenting parameters that \n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR = YES\n\n# This WARN_NO_PARAMDOC option can be abled to get warnings for \n# functions that are documented, but have no documentation for their parameters \n# or return value. If set to NO (the default) doxygen will only warn about \n# wrong or incomplete parameter documentation, but not about the absence of \n# documentation.\n\nWARN_NO_PARAMDOC = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that \n# doxygen can produce. The string should contain the $file, $line, and $text \n# tags, which will be replaced by the file and line number from which the \n# warning originated and the warning text. Optionally the format may contain \n# $version, which will be replaced by the version of the file (if it could \n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning \n# and error messages should be written. If left blank the output is written \n# to stderr.\n\nWARN_LOGFILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain \n# documented source files. You may enter file names like \"myfile.cpp\" or \n# directories like \"/usr/src/myproject\". Separate the files or directories \n# with spaces.\n\nINPUT = include/zoo_lock.h\n\n# If the value of the INPUT tag contains directories, you can use the \n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank the following patterns are tested: \n# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx \n# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py\n\nFILE_PATTERNS = \n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories \n# should be searched for input files as well. Possible values are YES and NO. \n# If left blank NO is used.\n\nRECURSIVE = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should \n# excluded from the INPUT source files. This way you can easily exclude a \n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n\nEXCLUDE = \n\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or \n# directories that are symbolic links (a Unix filesystem feature) are excluded \n# from the input.\n\nEXCLUDE_SYMLINKS = NO\n\n# If the value of the INPUT tag contains directories, you can use the \n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \n# certain files from those directories. Note that the wildcards are matched \n# against the file with absolute path, so to exclude all test directories \n# for example use the pattern */test/*\n\nEXCLUDE_PATTERNS = \n\n# The EXAMPLE_PATH tag can be used to specify one or more files or \n# directories that contain example code fragments that are included (see \n# the \\include command).\n\nEXAMPLE_PATH = \n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the \n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank all files are included.\n\nEXAMPLE_PATTERNS = \n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \n# searched for input files to be used with the \\include or \\dontinclude \n# commands irrespective of the value of the RECURSIVE tag. \n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or \n# directories that contain image that are included in the documentation (see \n# the \\image command).\n\nIMAGE_PATH = \n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should \n# invoke to filter for each input file. Doxygen will invoke the filter program \n# by executing (via popen()) the command <filter> <input-file>, where <filter> \n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \n# input file. Doxygen will then use the output that the filter program writes \n# to standard output.  If FILTER_PATTERNS is specified, this tag will be \n# ignored.\n\nINPUT_FILTER = \n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \n# basis.  Doxygen will compare the file name with each pattern and apply the \n# filter if there is a match.  The filters are a list of the form: \n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \n# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \n# is applied to all files.\n\nFILTER_PATTERNS = \n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \n# INPUT_FILTER) will be used to filter the input files when producing source \n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will \n# be generated. Documented entities will be cross-referenced with these sources. \n# Note: To get rid of all source code in the generated output, make sure also \n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body \n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \n# doxygen to hide any special comment blocks from generated source code \n# fragments. Normal C and C++ comments will always remain visible.\n\nSTRIP_CODE_COMMENTS = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES (the default) \n# then for each documented function all documented \n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES (the default) \n# then for each documented function all documented entities \n# called/used by that function will be listed.\n\nREFERENCES_RELATION = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n# link to the source code.  Otherwise they will link to the documentstion.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code \n# will point to the HTML generated by the htags(1) tool instead of doxygen \n# built-in source browser. The htags tool is part of GNU's global source \n# tagging system (see http://www.gnu.org/software/global/global.html). You \n# will need version 4.8.6 or higher.\n\nUSE_HTAGS = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \n# will generate a verbatim copy of the header file for each class for \n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \n# of all compounds will be generated. Enable this if the project \n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX = 5\n\n# In case all classes in a project start with a common prefix, all \n# classes will be put under the same header in the alphabetical index. \n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX = \n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \n# generate HTML output.\n\nGENERATE_HTML = $(GENERATE_HTML)\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard header.\n\nHTML_HEADER = \n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard footer.\n\nHTML_FOOTER = \n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \n# style sheet that is used by each HTML page. It can be used to \n# fine-tune the look of the HTML output. If the tag is left blank doxygen \n# will generate a default style sheet. Note that doxygen will try to copy \n# the style sheet file to the HTML output directory, so don't put your own \n# stylesheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET = \n\n# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \n# files or namespaces will be aligned in HTML using tables. If set to \n# NO a bullet list will be used.\n\nHTML_ALIGN_MEMBERS = YES\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files \n# will be generated that can be used as input for tools like the \n# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP = $(GENERATE_HTMLHELP)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \n# be used to specify the file name of the resulting .chm file. You \n# can add a path in front of the file if the result should not be \n# written to the html output directory.\n\nCHM_FILE = ../$(PROJECT).chm\n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \n# be used to specify the location (absolute path including file name) of \n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION = $(HHC_PATH)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \n# controls if a separate .chi index file is generated (YES) or that \n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI = $(GENERATE_CHI)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \n# controls whether a binary table of contents is generated (YES) or a \n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members \n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND = NO\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \n# top of each HTML page. The value NO (the default) enables the index and \n# the value YES disables it.\n\nDISABLE_INDEX = NO\n\n# This tag can be used to set the number of enum values (range [1..20]) \n# that doxygen will group on one line in the generated HTML documentation.\n\nENUM_VALUES_PER_LINE = 4\n\n# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\n# generated containing a tree-like index structure (just like the one that \n# is generated for HTML Help). For this to work a browser that supports \n# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \n# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \n# probably better off using the HTML help feature.\n\nGENERATE_TREEVIEW = NO\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \n# used to set the initial width (in pixels) of the frame in which the tree \n# is shown.\n\nTREEVIEW_WIDTH = 250\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \n# generate Latex output.\n\nGENERATE_LATEX = $(GENERATE_LATEX)\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \n# invoked. If left blank `latex' will be used as the default command name.\n\nLATEX_CMD_NAME = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \n# generate index for LaTeX. If left blank `makeindex' will be used as the \n# default command name.\n\nMAKEINDEX_CMD_NAME = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \n# LaTeX documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_LATEX = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used \n# by the printer. Possible values are: a4, a4wide, letter, legal and \n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE = $(PAPER_SIZE)\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES = \n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \n# the generated latex document. The header should contain everything until \n# the first chapter. If it is left blank doxygen will generate a \n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER = \n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \n# is prepared for conversion to pdf (using ps2pdf). The pdf file will \n# contain links (just like the HTML output) instead of page references \n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS = NO\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \n# plain latex in the generated Makefile. Set this option to YES to get a \n# higher quality PDF documentation.\n\nUSE_PDFLATEX = $(GENERATE_PDF)\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode. \n# command to the generated LaTeX files. This will instruct LaTeX to keep \n# running if errors occur, instead of asking the user for help. \n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not \n# include the index chapters (such as File Index, Compound Index, etc.) \n# in the output.\n\nLATEX_HIDE_INDICES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \n# The RTF output is optimized for Word 97 and may not look very pretty with \n# other RTF readers or editors.\n\nGENERATE_RTF = $(GENERATE_RTF)\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \n# RTF documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_RTF = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \n# will contain hyperlink fields. The RTF file will \n# contain links (just like the HTML output) instead of page references. \n# This makes the output suitable for online browsing using WORD or other \n# programs which support those fields. \n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's \n# config file, i.e. a series of assignments. You only have to provide \n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE = \n\n# Set optional variables used in the generation of an rtf document. \n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \n# generate man pages\n\nGENERATE_MAN = $(GENERATE_MAN)\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT = man\n\n# The MAN_EXTENSION tag determines the extension that is added to \n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \n# then it will generate one additional man file for each entity \n# documented in the real man page(s). These additional files \n# only source the real man page, but without them the man command \n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will \n# generate an XML file that captures the structure of \n# the code including all documentation.\n\nGENERATE_XML = $(GENERATE_XML)\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_SCHEMA = \n\n# The XML_DTD tag can be used to specify an XML DTD, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_DTD = \n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \n# dump the program listings (including syntax highlighting \n# and cross-referencing information) to the XML output. Note that \n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \n# generate an AutoGen Definitions (see autogen.sf.net) file \n# that captures the structure of the code including all \n# documentation. Note that this feature is still experimental \n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will \n# generate a Perl module file that captures the structure of \n# the code including all documentation. Note that this \n# feature is still experimental and incomplete at the \n# moment.\n\nGENERATE_PERLMOD = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \n# the necessary Makefile rules, Perl scripts and LaTeX code to be able \n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \n# nicely formatted so it can be parsed by a human reader.  This is useful \n# if you want to understand what is going on.  On the other hand, if this \n# tag is set to NO the size of the Perl module output will be much smaller \n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY = YES\n\n# The names of the make variables in the generated doxyrules.make file \n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \n# This is useful so different doxyrules.make files included by the same \n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor   \n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \n# evaluate all C-preprocessor directives found in the sources and include \n# files.\n\nENABLE_PREPROCESSING = YES\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \n# names in the source code. If set to NO (the default) only conditional \n# compilation will be performed. Macro expansion can be done in a controlled \n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \n# then the macro expansion is limited to the macros specified with the \n# PREDEFINED and EXPAND_AS_DEFINED tags.\n\nEXPAND_ONLY_PREDEF = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \n# in the INCLUDE_PATH (see below) will be search if a #include is found.\n\nSEARCH_INCLUDES = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that \n# contain include files that are not input files but should be processed by \n# the preprocessor.\n\nINCLUDE_PATH = \n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \n# patterns (like *.h and *.hpp) to filter out the header-files in the \n# directories. If left blank, the patterns specified with FILE_PATTERNS will \n# be used.\n\nINCLUDE_FILE_PATTERNS = \n\n# The PREDEFINED tag can be used to specify one or more macro names that \n# are defined before the preprocessor is started (similar to the -D option of \n# gcc). The argument of the tag is a list of macros of the form: name \n# or name=definition (no spaces). If the definition and the = are \n# omitted =1 is assumed. To prevent a macro definition from being \n# undefined via #undef or recursively expanded use the := operator \n# instead of the = operator.\n\nPREDEFINED = \n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \n# this tag can be used to specify a list of macro names that should be expanded. \n# The macro definition that is found in the sources will be used. \n# Use the PREDEFINED tag if you want to use a different macro definition.\n\nEXPAND_AS_DEFINED = \n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \n# doxygen's preprocessor will remove all function-like macros that are alone \n# on a line, have an all uppercase name, and do not end with a semicolon. Such \n# function macros are typically used for boiler-plate code, and will confuse \n# the parser if not removed.\n\nSKIP_FUNCTION_MACROS = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references   \n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles. \n# Optionally an initial location of the external documentation \n# can be added for each tagfile. The format of a tag file without \n# this location is as follows: \n#   TAGFILES = file1 file2 ... \n# Adding location for the tag files is done as follows: \n#   TAGFILES = file1=loc1 \"file2 = loc2\" ... \n# where \"loc1\" and \"loc2\" can be relative or absolute paths or \n# URLs. If a location is present for each tag, the installdox tool \n# does not have to be run to correct the links.\n# Note that each tag file must have a unique name\n# (where the name does NOT include the path)\n# If a tag file is not located in the directory in which doxygen \n# is run, you must also specify the path to the tagfile here.\n\nTAGFILES = \n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create \n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag\n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed \n# in the class index. If set to NO only the inherited external classes \n# will be listed.\n\nALLEXTERNALS = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \n# in the modules index. If set to NO, only the current project's groups will \n# be listed.\n\nEXTERNAL_GROUPS = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script \n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool   \n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base \n# or super classes. Setting the tag to NO turns the diagrams off. Note that \n# this option is superseded by the HAVE_DOT option below. This is only a \n# fallback. It is recommended to install and use dot, since it yields more \n# powerful graphs.\n\nCLASS_DIAGRAMS = YES\n\n# If set to YES, the inheritance and collaboration graphs will hide \n# inheritance and usage relations if the target is undocumented \n# or is not a class.\n\nHIDE_UNDOC_RELATIONS = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \n# available from the path. This tool is part of Graphviz, a graph visualization \n# toolkit from AT&T and Lucent Bell Labs. The other options in this section \n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT = $(HAVE_DOT)\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect inheritance relations. Setting this tag to YES will force the \n# the CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect implementation dependencies (inheritance, containment, and \n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \n# collaboration diagrams in a style similar to the OMG's Unified Modeling \n# Language.\n\nUML_LOOK = NO\n\n# If set to YES, the inheritance and collaboration graphs will show the \n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \n# tags are set to YES then doxygen will generate a graph for each documented \n# file showing the direct and indirect include dependencies of the file with \n# other documented files.\n\nINCLUDE_GRAPH = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \n# documented header file showing the documented files that directly or \n# indirectly include this file.\n\nINCLUDED_BY_GRAPH = YES\n\n# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a call dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable call graphs for selected \n# functions only using the \\callgraph command.\n\nCALL_GRAPH = NO\n\n# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a caller dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable caller graphs for selected \n# functions only using the \\callergraph command.\n\nCALLER_GRAPH = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \n# will graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY = YES\n\n# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \n# then doxygen will show the dependencies a directory has on other directories \n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \n# generated by dot. Possible values are png, jpg, or gif\n# If left blank png will be used.\n\nDOT_IMAGE_FORMAT = png\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be \n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH = $(DOT_PATH)\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that \n# contain dot files that are included in the documentation (see the \n# \\dotfile command).\n\nDOTFILE_DIRS = \n\n# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_WIDTH = 1024\n\n# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_HEIGHT = 1024\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \n# graphs generated by dot. A depth value of 3 means that only nodes reachable \n# from the root by following a path via at most 3 edges will be shown. Nodes \n# that lay further from the root node will be omitted. Note that setting this \n# option to 1 or 2 may greatly reduce the computation time needed for large \n# code bases. Also note that a graph may be further truncated if the graph's \n# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH \n# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), \n# the graph is not depth-constrained.\n\nMAX_DOT_GRAPH_DEPTH = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent \n# background. This is disabled by default, which results in a white background. \n# Warning: Depending on the platform used, enabling this option may lead to \n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to \n# read).\n\nDOT_TRANSPARENT = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output \n# files in one run (i.e. multiple -o and -T options on the command line). This \n# makes dot run faster, but since only newer versions of dot (>1.8.10) \n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \n# generate a legend page explaining the meaning of the various boxes and \n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \n# remove the intermediate dot files that are used to generate \n# the various graphs.\n\nDOT_CLEANUP = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to the search engine   \n#---------------------------------------------------------------------------\n\n# The SEARCHENGINE tag specifies whether or not a search engine should be \n# used. If set to NO the values of all tags below this one will be ignored.\n\nSEARCHENGINE = NO\n"
  },
  {
    "path": "src/recipes/lock/src/c/configure.ac",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ(2.59)\n\nAC_INIT([zoolock], [3.2.0])\n\nAC_CONFIG_SRCDIR([include/zoo_lock.h])\n\nPACKAGE=zoolock\nVERSION=1.0\n\nAC_SUBST(PACKAGE)\nAC_SUBST(VERSION)\n\nBUILD_PATH=\"`pwd`\"\n\n# Checks for programs.\nAC_LANG_CPLUSPLUS\n\nAM_INIT_AUTOMAKE([-Wall foreign])\n# Checks for libraries.\n\n#initialize Doxygen support\nDX_HTML_FEATURE(ON)\nDX_CHM_FEATURE(OFF)\nDX_CHI_FEATURE(OFF)\nDX_MAN_FEATURE(OFF)\nDX_RTF_FEATURE(OFF)\nDX_XML_FEATURE(OFF)\nDX_PDF_FEATURE(OFF)\nDX_PS_FEATURE(OFF)\nDX_INIT_DOXYGEN([zookeeper-locks],[c-doc.Doxyfile],[docs])\n\n  \nZOOKEEPER_PATH=${BUILD_PATH}/../../../../../src/c\nZOOKEEPER_LD=-L${BUILD_PATH}/../../../../../src/c\\ -lzookeeper_mt\n\nAC_SUBST(ZOOKEEPER_PATH)\nAC_SUBST(ZOOKEEPER_LD)\n\n# Checks for header files.\nAC_HEADER_DIRENT\nAC_HEADER_STDC\nAC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h])\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_HEADER_STDBOOL\nAC_C_CONST\nAC_TYPE_UID_T\nAC_C_INLINE\nAC_TYPE_OFF_T\nAC_TYPE_SIZE_T\nAC_STRUCT_ST_BLOCKS\nAC_HEADER_TIME\nAC_C_VOLATILE\nAC_PROG_CC\nAC_PROG_LIBTOOL\n#check for cppunit \nAM_PATH_CPPUNIT(1.10.2)\n# Checks for library functions.\nAC_FUNC_UTIME_NULL\nAC_CHECK_FUNCS([gettimeofday memset mkdir rmdir strdup strerror strstr strtol strtoul strtoull utime])\n\nAC_CONFIG_FILES([Makefile])\nAC_OUTPUT\nAC_C_VOLATILE\n"
  },
  {
    "path": "src/recipes/lock/src/c/include/zoo_lock.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#ifndef ZOOKEEPER_LOCK_H_\n#define ZOOKEEPER_LOCK_H_\n\n#include <zookeeper.h>\n#include <pthread.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/**\n * \\brief the call back function called on status change of lock\n * \n * the call back funtion is called with a rc of 0 if lock is acquired and \n * with an rc of 1 if the lock is released\n * \\param rc the value to let us know if its locked or unlocked\n * \\param cbdata the callback data that we passed when initializing \n * the zookeeper lock.\n */\n\ntypedef void (* zkr_lock_completion) (int rc, void* cbdata);\n\n/** \n * \\file zoo_lock.h\n * \\brief zookeeper recipe for locking and leader election.\n * this api implements a writelock on a given path in zookeeper.\n * this api can also be used for leader election.\n */\n\nstruct zkr_lock_mutex {\n    zhandle_t *zh;\n    char *path;\n    struct ACL_vector *acl;\n    char *id;\n    void *cbdata;\n    zkr_lock_completion completion;\n    pthread_mutex_t pmutex;\n    int isOwner;\n    char* ownerid;\n};\n\ntypedef struct zkr_lock_mutex zkr_lock_mutex_t;\n\n\n/**\n * \\brief initializing a zookeeper lock.\n *\n * this method instantiates the zookeeper mutex lock.\n * \\param mutex the mutex to initialize\n * \\param zh the zookeeper handle to use\n * \\param path the path in zookeeper to use for locking\n * \\param acl the acls to use in zookeeper.\n * \\return return 0 if successful.\n */\nZOOAPI int zkr_lock_init(zkr_lock_mutex_t *mutex, zhandle_t* zh, \n                      char* path, struct ACL_vector *acl);\n\n/**\n * \\brief initializing a zookeeper lock.\n *\n *\n * this method instantiates the zookeeper mutex lock with\n * a completion function.\n * \n * \\param mutex the mutex to initialize\n * \\param zh the zookeeper handle to use\n * \\param path the path in zookeeper to use for locking\n * \\param acl the acls to use in zookeeper.\n * \\param completion the callback thats called when lock \n * is acquired and released.\n * \\param cbdata the callback method is called with data\n * \\return return 0 if successful.\n */\nZOOAPI int zkr_lock_init_cb(zkr_lock_mutex_t *mutex, zhandle_t* zh,\n                      char* path, struct ACL_vector *acl, \n                      zkr_lock_completion completion, void* cbdata);\n\n/**\n * \\brief lock the zookeeper mutex\n *\n * this method tries locking the mutex\n * \\param mutex the zookeeper mutex\n * \\return return 0 if there is no error. check \n * with zkr_lock_isowner() if you have the lock\n */\nZOOAPI int zkr_lock_lock(zkr_lock_mutex_t *mutex);\n\n/**\n * \\brief unlock the zookeeper mutex\n *\n * this method unlocks the zookeeper mutex\n * \\param mutex the zookeeper mutex\n * \\return return 0 if there is not error in executing unlock.\n * else returns non zero\n */\nZOOAPI int zkr_lock_unlock(zkr_lock_mutex_t *mutex);\n\n/**\n * \\brief set the callback function for zookeeper mutex\n * \n * this method sets the callback for zookeeper mutex\n * \\param mutex the zookeeper mutex\n * \\param callback the call back completion function\n */\nZOOAPI void zkr_lock_setcallback(zkr_lock_mutex_t *mutex, \n                           zkr_lock_completion completion);\n\n/**\n * \\brief get the callback function for zookeeper mutex\n *\n * this method gets the callback funtion for zookeeper mutex\n * \\param mutex the zookeeper mutex\n * \\return the lock completion function\n */\nZOOAPI zkr_lock_completion zkr_lock_getcallback(zkr_lock_mutex_t *mutex);\n\n/**\n * \\brief destroy the mutex \n * this method free the mutex\n * \\param mutex destroy the zookepeer lock.\n * \\return return 0 if destroyed.\n */\nZOOAPI int zkr_lock_destroy(zkr_lock_mutex_t* mutex);\n\n/**\n * \\brief return the parent path this mutex is using\n * this method returns the parent path\n * \\param mutex the mutex\n * \\return return the parent path\n */\nZOOAPI char* zkr_lock_getpath(zkr_lock_mutex_t *mutex);\n\n/**\n * \\brief return if this mutex is owner of the lock\n * this method returns if its owner or not\n * \\param mutex the mutex\n * \\return return true if is owner and false if not\n */\nZOOAPI int zkr_lock_isowner(zkr_lock_mutex_t *mutex);\n\n/**\n * \\brief return the id for this mutex\n * this mutex retunrns the id string \n * \\param mutex the mutex\n * \\return the id for this mutex\n */\nZOOAPI char* zkr_lock_getid(zkr_lock_mutex_t *mutex);\n\n#ifdef __cplusplus\n}\n#endif\n#endif  //ZOOKEEPER_LOCK_H_\n"
  },
  {
    "path": "src/recipes/lock/src/c/src/zoo_lock.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifdef DLL_EXPORT\n#define USE_STATIC_LIB\n#endif\n\n#if defined(__CYGWIN__)\n#define USE_IPV6\n#endif\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <zookeeper_log.h>\n#include <time.h>\n#include <sys/time.h>\n#include <sys/socket.h>\n#include <limits.h>\n#include <zoo_lock.h>\n#include <stdbool.h>\n#ifdef HAVE_SYS_UTSNAME_H\n#include <sys/utsname.h>\n#endif\n\n#ifdef HAVE_GETPWUID_R\n#include <pwd.h>\n#endif\n\n#define IF_DEBUG(x) if (logLevel==ZOO_LOG_LEVEL_DEBUG) {x;}\n\n \nZOOAPI int zkr_lock_init(zkr_lock_mutex_t* mutex, zhandle_t* zh,\n                      char* path, struct ACL_vector *acl) {\n    mutex->zh = zh;\n    mutex->path = path;\n    mutex->acl = acl;\n    mutex->completion = NULL;\n    mutex->cbdata = NULL;\n    mutex->id = NULL;\n    mutex->ownerid = NULL;\n    mutex->isOwner = 0;\n    pthread_mutex_init(&(mutex->pmutex), NULL);\n    return 0;\n}\n\nZOOAPI int zkr_lock_init_cb(zkr_lock_mutex_t *mutex, zhandle_t* zh,\n                         char *path, struct ACL_vector *acl,\n                         zkr_lock_completion completion, void* cbdata) {\n    mutex->zh = zh;\n    mutex->path = path;\n    mutex->acl = acl;\n    mutex->completion = completion;\n    mutex->cbdata = cbdata;\n    mutex->isOwner = 0;\n    mutex->ownerid = NULL;\n    mutex->id = NULL;\n    pthread_mutex_init(&(mutex->pmutex), NULL);\n    return 0;\n}\n\n/**\n * unlock the mutex\n */\nZOOAPI int zkr_lock_unlock(zkr_lock_mutex_t *mutex) {\n    pthread_mutex_lock(&(mutex->pmutex));\n    zhandle_t *zh = mutex->zh;\n    if (mutex->id != NULL) {\n        int len = strlen(mutex->path) + strlen(mutex->id) + 2;\n        char buf[len];\n        sprintf(buf, \"%s/%s\", mutex->path, mutex->id);\n        int ret = 0;\n        int count = 0;\n        struct timespec ts;\n        ts.tv_sec = 0;\n        ts.tv_nsec = (.5)*1000000;\n        ret = ZCONNECTIONLOSS;\n        while (ret == ZCONNECTIONLOSS && (count < 3)) {\n            ret = zoo_delete(zh, buf, -1);\n            if (ret == ZCONNECTIONLOSS) {\n                LOG_DEBUG((\"connectionloss while deleting the node\"));\n                nanosleep(&ts, 0);\n                count++;\n            }\n        }\n        if (ret == ZOK || ret == ZNONODE) {\n            zkr_lock_completion completion = mutex->completion;\n            if (completion != NULL) {\n                completion(1, mutex->cbdata);\n            }\n\n            free(mutex->id);\n            mutex->id = NULL;\n            pthread_mutex_unlock(&(mutex->pmutex));\n            return 0;\n        }\n        LOG_WARN((\"not able to connect to server - giving up\"));\n        pthread_mutex_unlock(&(mutex->pmutex));\n        return ZCONNECTIONLOSS;\n    }\n    pthread_mutex_unlock(&(mutex->pmutex));\n    return ZSYSTEMERROR;\n}\n\nstatic void free_String_vector(struct String_vector *v) {\n    if (v->data) {\n        int32_t i;\n        for (i=0; i<v->count; i++) {\n            free(v->data[i]);\n        }\n        free(v->data);\n        v->data = 0;\n    }\n}\n\nstatic int vstrcmp(const void* str1, const void* str2) {\n    const char **a = (const char**)str1;\n    const char **b = (const char**) str2;\n    return strcmp(strrchr(*a, '-')+1, strrchr(*b, '-')+1); \n} \n\nstatic void sort_children(struct String_vector *vector) {\n    qsort( vector->data, vector->count, sizeof(char*), &vstrcmp);\n}\n        \nstatic char* child_floor(char **sorted_data, int len, char *element) {\n    char* ret = NULL;\n    int i =0;\n    for (i=0; i < len; i++) {\n        if (strcmp(sorted_data[i], element) < 0) {\n            ret = sorted_data[i];\n        }\n    }\n    return ret;\n}\n\nstatic void lock_watcher_fn(zhandle_t* zh, int type, int state,\n                            const char* path, void *watcherCtx) {\n    //callback that we registered \n    //should be called\n    zkr_lock_lock((zkr_lock_mutex_t*) watcherCtx);\n}\n\n/**\n * get the last name of the path\n */\nstatic char* getName(char* str) {\n    char* name = strrchr(str, '/');\n    if (name == NULL) \n        return NULL;\n    return strdup(name + 1);\n}\n\n/**\n * just a method to retry get children\n */\nstatic int retry_getchildren(zhandle_t *zh, char* path, struct String_vector *vector, \n                             struct timespec *ts, int retry) {\n    int ret = ZCONNECTIONLOSS;\n    int count = 0;\n    while (ret == ZCONNECTIONLOSS && count < retry) {\n        ret = zoo_get_children(zh, path, 0, vector);\n        if (ret == ZCONNECTIONLOSS) {\n            LOG_DEBUG((\"connection loss to the server\"));\n            nanosleep(ts, 0);\n            count++;\n        }\n    }\n    return ret;\n}\n\n/** see if our node already exists\n * if it does then we dup the name and \n * return it\n */\nstatic char* lookupnode(struct String_vector *vector, char *prefix) {\n    char *ret = NULL;\n    if (vector->data) {\n        int i = 0;\n        for (i = 0; i < vector->count; i++) {\n            char* child = vector->data[i];\n            if (strncmp(prefix, child, strlen(prefix)) == 0) {\n                ret = strdup(child);\n                break;\n            }\n        }\n    }\n    return ret;\n}\n\n/** retry zoo_wexists\n */\nstatic int retry_zoowexists(zhandle_t *zh, char* path, watcher_fn watcher, void* ctx,\n                            struct Stat *stat, struct timespec *ts, int retry) {\n    int ret = ZCONNECTIONLOSS;\n    int count = 0;\n    while (ret == ZCONNECTIONLOSS && count < retry) {\n        ret = zoo_wexists(zh, path, watcher, ctx, stat);\n        if (ret == ZCONNECTIONLOSS) {\n            LOG_DEBUG((\"connectionloss while setting watch on my predecessor\"));\n            nanosleep(ts, 0);\n            count++;\n        }\n    }\n    return ret;\n}\n                        \n/**\n * the main code that does the zookeeper leader \n * election. this code creates its own ephemeral \n * node on the given path and sees if its the first\n * one on the list and claims to be a leader if and only\n * if its the first one of children in the paretn path\n */\nstatic int zkr_lock_operation(zkr_lock_mutex_t *mutex, struct timespec *ts) {\n    zhandle_t *zh = mutex->zh;\n    char *path = mutex->path;\n    char *id = mutex->id;\n    struct Stat stat;\n    char* owner_id = NULL;\n    int retry = 3;\n    do {\n        const clientid_t *cid = zoo_client_id(zh);\n        // get the session id\n        int64_t session = cid->client_id;\n        char prefix[30];\n        int ret = 0;\n#if defined(__x86_64__)\n        snprintf(prefix, 30, \"x-%016lx-\", session);\n#else \n        snprintf(prefix, 30, \"x-%016llx-\", session);\n#endif\n        struct String_vector vectorst;\n        vectorst.data = NULL;\n        vectorst.count = 0;\n        ret = ZCONNECTIONLOSS;\n        ret = retry_getchildren(zh, path, &vectorst, ts, retry);\n        if (ret != ZOK)\n            return ret;\n        struct String_vector *vector = &vectorst;\n        mutex->id = lookupnode(vector, prefix);\n        free_String_vector(vector);\n        if (mutex->id == NULL) {\n            int len = strlen(path) + strlen(prefix) + 2;\n            char buf[len];\n            char retbuf[len+20];\n            snprintf(buf, len, \"%s/%s\", path, prefix);\n            ret = ZCONNECTIONLOSS;\n            ret = zoo_create(zh, buf, NULL, 0,  mutex->acl, \n                             ZOO_EPHEMERAL|ZOO_SEQUENCE, retbuf, (len+20));\n            \n            // do not want to retry the create since \n            // we would end up creating more than one child\n            if (ret != ZOK) {\n                LOG_WARN((\"could not create zoo node %s\", buf));\n                return ret;\n            }\n            mutex->id = getName(retbuf);\n        }\n        \n        if (mutex->id != NULL) {\n            ret = ZCONNECTIONLOSS;\n            ret = retry_getchildren(zh, path, vector, ts, retry);\n            if (ret != ZOK) {\n                LOG_WARN((\"could not connect to server\"));\n                return ret;\n            }\n            //sort this list\n            sort_children(vector);\n            owner_id = vector->data[0];\n            mutex->ownerid = strdup(owner_id);\n            id = mutex->id;\n            char* lessthanme = child_floor(vector->data, vector->count, id);\n            if (lessthanme != NULL) {\n                int flen = strlen(mutex->path) + strlen(lessthanme) + 2;\n                char last_child[flen];\n                sprintf(last_child, \"%s/%s\",mutex->path, lessthanme);\n                ret = ZCONNECTIONLOSS;\n                ret = retry_zoowexists(zh, last_child, &lock_watcher_fn, mutex, \n                                       &stat, ts, retry);\n                // cannot watch my predecessor i am giving up\n                // we need to be able to watch the predecessor \n                // since if we do not become a leader the others \n                // will keep waiting\n                if (ret != ZOK) {\n                    free_String_vector(vector);\n                    LOG_WARN((\"unable to watch my predecessor\"));\n                    ret = zkr_lock_unlock(mutex);\n                    while (ret == 0) {\n                        //we have to give up our leadership\n                        // since we cannot watch out predecessor\n                        ret = zkr_lock_unlock(mutex);\n                    }\n                    return ret;\n                }\n                // we are not the owner of the lock\n                mutex->isOwner = 0;\n            }\n            else {\n                // this is the case when we are the owner \n                // of the lock\n                if (strcmp(mutex->id, owner_id) == 0) {\n                    LOG_DEBUG((\"got the zoo lock owner - %s\", mutex->id));\n                    mutex->isOwner = 1;\n                    if (mutex->completion != NULL) {\n                        mutex->completion(0, mutex->cbdata);\n                    }\n                    return ZOK;\n                }\n            }\n            free_String_vector(vector);\n            return ZOK;\n        }\n    } while (mutex->id == NULL);\n    return ZOK;\n}\n\nZOOAPI int zkr_lock_lock(zkr_lock_mutex_t *mutex) {\n    pthread_mutex_lock(&(mutex->pmutex));\n    zhandle_t *zh = mutex->zh;\n    char *path = mutex->path;\n    struct Stat stat;\n    int exists = zoo_exists(zh, path, 0, &stat);\n    int count = 0;\n    struct timespec ts;\n    ts.tv_sec = 0;\n    ts.tv_nsec = (.5)*1000000;\n    // retry to see if the path exists and \n    // and create if the path does not exist\n    while ((exists == ZCONNECTIONLOSS || exists == ZNONODE) && (count <4)) {\n        count++;\n        // retry the operation\n        if (exists == ZCONNECTIONLOSS) \n            exists = zoo_exists(zh, path, 0, &stat);\n        else if (exists == ZNONODE) \n            exists = zoo_create(zh, path, NULL, 0, mutex->acl, 0, NULL, 0);\n        nanosleep(&ts, 0);\n          \n    }\n\n    // need to check if we cannot still access the server \n    int check_retry = ZCONNECTIONLOSS;\n    count = 0;\n    while (check_retry != ZOK && count <4) {\n        check_retry = zkr_lock_operation(mutex, &ts);\n        if (check_retry != ZOK) {\n            nanosleep(&ts, 0);\n            count++;\n        }\n    }\n    pthread_mutex_unlock(&(mutex->pmutex));\n    return zkr_lock_isowner(mutex);\n}\n\n                    \nZOOAPI char* zkr_lock_getpath(zkr_lock_mutex_t *mutex) {\n    return mutex->path;\n}\n\nZOOAPI int zkr_lock_isowner(zkr_lock_mutex_t *mutex) {\n    return (mutex->id != NULL && mutex->ownerid != NULL \n            && (strcmp(mutex->id, mutex->ownerid) == 0));\n}\n\nZOOAPI char* zkr_lock_getid(zkr_lock_mutex_t *mutex) {\n    return mutex->ownerid;\n}\n\nZOOAPI int zkr_lock_destroy(zkr_lock_mutex_t* mutex) {\n    if (mutex->id) \n        free(mutex->id);\n    mutex->path = NULL;\n    mutex->acl = NULL;\n    mutex->completion = NULL;\n    pthread_mutex_destroy(&(mutex->pmutex));\n    mutex->isOwner = 0;\n    if (mutex->ownerid) \n        free(mutex->ownerid);\n    return 0;\n}\n\n"
  },
  {
    "path": "src/recipes/lock/src/c/tests/TestClient.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n\n#include <stdlib.h>\n#include <sys/select.h>\n#include <cppunit/TestAssert.h>\n\n\nusing namespace std;\n\n#include <cstring>\n#include <list>\n\n#include <zookeeper.h>\n#include <zoo_lock.h>\n\nstatic void yield(zhandle_t *zh, int i)\n{\n    sleep(i);\n}\n\ntypedef struct evt {\n    string path;\n    int type;\n} evt_t;\n\ntypedef struct watchCtx {\nprivate:\n    list<evt_t> events;\npublic:\n    bool connected;\n    zhandle_t *zh;\n    \n    watchCtx() {\n        connected = false;\n        zh = 0;\n    }\n    ~watchCtx() {\n        if (zh) {\n            zookeeper_close(zh);\n            zh = 0;\n        }\n    }\n\n    evt_t getEvent() {\n        evt_t evt;\n        evt = events.front();\n        events.pop_front();\n        return evt;\n    }\n\n    int countEvents() {\n        int count;\n        count = events.size();\n        return count;\n    }\n\n    void putEvent(evt_t evt) {\n        events.push_back(evt);\n    }\n\n    bool waitForConnected(zhandle_t *zh) {\n        time_t expires = time(0) + 10;\n        while(!connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return connected;\n    }\n    bool waitForDisconnected(zhandle_t *zh) {\n        time_t expires = time(0) + 15;\n        while(connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return !connected;\n    }\n} watchctx_t; \n\nclass Zookeeper_locktest : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_locktest);\n    CPPUNIT_TEST(testlock);\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int type, int state, const char *path,void*v){\n        watchctx_t *ctx = (watchctx_t*)v;\n\n        if (state == ZOO_CONNECTED_STATE) {\n            ctx->connected = true;\n        } else {\n            ctx->connected = false;\n        }\n        if (type != ZOO_SESSION_EVENT) {\n            evt_t evt;\n            evt.path = path;\n            evt.type = type;\n            ctx->putEvent(evt);\n        }\n    }\n\n    static const char hostPorts[];\n\n    const char *getHostPorts() {\n        return hostPorts;\n    }\n\n    zhandle_t *createClient(watchctx_t *ctx) {\n        zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0,\n                                       ctx, 0);\n        ctx->zh = zk;\n        sleep(1);\n        return zk;\n    }\n    \npublic:\n\n#define ZKSERVER_CMD \"./tests/zkServer.sh\"\n\n    void setUp()\n    {\n        char cmd[1024];\n        sprintf(cmd, \"%s startClean %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n    \n\n    void startServer() {\n        char cmd[1024];\n        sprintf(cmd, \"%s start %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n\n    void stopServer() {\n        tearDown();\n    }\n\n    void tearDown()\n    {\n        char cmd[1024];\n        sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n    \n\n    void testlock()\n    {\n        watchctx_t ctx;\n        int rc;\n        struct Stat stat;\n        char buf[1024];\n        int blen;\n        struct String_vector strings;\n        const char *testName;\n        zkr_lock_mutex_t mutexes[3];\n        int count = 3;\n        int i = 0;\n        char* path = \"/test-lock\";\n        for (i=0; i< 3; i++) {\n            zhandle_t *zh = createClient(&ctx);\n            zkr_lock_init(&mutexes[i], zh, path, &ZOO_OPEN_ACL_UNSAFE);\n            zkr_lock_lock(&mutexes[i]);\n        }\n        sleep(30);\n        zkr_lock_mutex leader = mutexes[0];\n        zkr_lock_mutex mutex;\n        int ret = strcmp(leader.id, leader.ownerid);\n        CPPUNIT_ASSERT(ret == 0);\n        for(i=1; i < count; i++) {\n            mutex = mutexes[i];\n            CPPUNIT_ASSERT(strcmp(mutex.id, mutex.ownerid) != 0);\n        } \n        zkr_lock_unlock(&leader);\n        sleep(30);\n        zkr_lock_mutex secondleader = mutexes[1];\n        CPPUNIT_ASSERT(strcmp(secondleader.id , secondleader.ownerid) == 0);\n        for (i=2; i<count; i++) {\n            mutex = mutexes[i];\n            CPPUNIT_ASSERT(strcmp(mutex.id, mutex.ownerid) != 0);\n        }\n    }\n\n};\n\nconst char Zookeeper_locktest::hostPorts[] = \"127.0.0.1:22181\";\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_locktest);\n"
  },
  {
    "path": "src/recipes/lock/src/c/tests/TestDriver.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <string>\n#include <cppunit/TestRunner.h>\n#include <cppunit/CompilerOutputter.h>\n#include <cppunit/TestResult.h>\n#include <cppunit/TestResultCollector.h>\n#include <cppunit/TextTestProgressListener.h>\n#include <cppunit/BriefTestProgressListener.h>\n#include <cppunit/extensions/TestFactoryRegistry.h>\n#include <stdexcept>\n#include <cppunit/Exception.h>\n#include <cppunit/TestFailure.h>\n#include <cppunit/XmlOutputter.h>\n#include <fstream>\n\n#include \"Util.h\"\n\nusing namespace std;\n\nCPPUNIT_NS_BEGIN\n\nclass EclipseOutputter: public CompilerOutputter\n{\npublic:\n  EclipseOutputter(TestResultCollector *result,ostream &stream):\n        CompilerOutputter(result,stream,\"%p:%l: \"),stream_(stream)\n    {\n    }\n    virtual void printFailedTestName( TestFailure *failure ){}\n    virtual void printFailureMessage( TestFailure *failure )\n    {\n      stream_<<\": \";\n      Message msg = failure->thrownException()->message();\n      stream_<< msg.shortDescription();\n\n      string text;\n      for(int i=0; i<msg.detailCount();i++){\n          text+=msg.detailAt(i);\n          if(i+1!=msg.detailCount())\n              text+=\", \";\n      }\n      if(text.length()!=0)\n          stream_ <<\" [\"<<text<<\"]\";\n      stream_<<\"\\n\";\n    }\n    ostream& stream_;\n};\n\nCPPUNIT_NS_END\n\nint main( int argc, char* argv[] ) { \n   // if command line contains \"-ide\" then this is the post build check\n   // => the output must be in the compiler error format.\n   //bool selfTest = (argc > 1) && (std::string(\"-ide\") == argv[1]);\n   globalTestConfig.addConfigFromCmdLine(argc,argv);\n\n   // Create the event manager and test controller\n   CPPUNIT_NS::TestResult controller;\n   // Add a listener that colllects test result\n   CPPUNIT_NS::TestResultCollector result;\n   controller.addListener( &result );\n   \n   // Add a listener that print dots as tests run.\n   // CPPUNIT_NS::TextTestProgressListener progress;\n   CPPUNIT_NS::BriefTestProgressListener progress;\n   controller.addListener( &progress );\n \n   CPPUNIT_NS::TestRunner runner;\n   runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );\n \n   try\n   {\n     cout << \"Running \"  <<  globalTestConfig.getTestName();\n     runner.run( controller, globalTestConfig.getTestName());\n     cout<<endl;\n\n     // Print test in a compiler compatible format.\n     CPPUNIT_NS::EclipseOutputter outputter( &result,cout);\n     outputter.write(); \n\n // Uncomment this for XML output\n#ifdef ENABLE_XML_OUTPUT\n     std::ofstream file( \"tests.xml\" );\n     CPPUNIT_NS::XmlOutputter xml( &result, file );\n     xml.setStyleSheet( \"report.xsl\" );\n     xml.write();\n     file.close();\n#endif\n   }\n   catch ( std::invalid_argument &e )  // Test path not resolved\n   {\n     cout<<\"\\nERROR: \"<<e.what()<<endl;\n     return 0;\n   }\n\n   return result.wasSuccessful() ? 0 : 1;\n }\n"
  },
  {
    "path": "src/recipes/lock/src/c/tests/Util.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"Util.h\"\n\nconst std::string EMPTY_STRING;\n\nTestConfig globalTestConfig;\n\nvoid millisleep(int ms){\n    timespec ts;\n    ts.tv_sec=ms/1000;\n    ts.tv_nsec=(ms%1000)*1000000; // to nanoseconds\n    nanosleep(&ts,0);\n}\n"
  },
  {
    "path": "src/recipes/lock/src/c/tests/Util.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UTIL_H_\n#define UTIL_H_\n\n#include <map>\n#include <vector>\n#include <string>\n\n// number of elements in array\n#define COUNTOF(array) sizeof(array)/sizeof(array[0])\n\n#define DECLARE_WRAPPER(ret,sym,sig) \\\n    extern \"C\" ret __real_##sym sig; \\\n    extern \"C\" ret __wrap_##sym sig\n\n#define CALL_REAL(sym,params) \\\n    __real_##sym params\n\n// must include \"src/zookeeper_log.h\" to be able to use this macro\n#define TEST_TRACE(x) \\\n    log_message(3,__LINE__,__func__,format_log_message x)\n\nextern const std::string EMPTY_STRING;\n\n// *****************************************************************************\n// A bit of wizardry to get to the bare type from a reference or a pointer \n// to the type\ntemplate <class T>\nstruct TypeOp {\n    typedef T BareT;\n    typedef T ArgT;\n};\n\n// partial specialization for reference types\ntemplate <class T>\nstruct TypeOp<T&>{\n    typedef T& ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// partial specialization for pointers\ntemplate <class T>\nstruct TypeOp<T*>{\n    typedef T* ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// *****************************************************************************\n// Container utilities\n\ntemplate <class K, class V>\nvoid putValue(std::map<K,V>& map,const K& k, const V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        map.insert(typename Map::value_type(k,v));\n    else\n        map[k]=v;\n}\n\ntemplate <class K, class V>\nbool getValue(const std::map<K,V>& map,const K& k,V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        return false;\n    v=it->second;\n    return true;\n}\n\n// *****************************************************************************\n// misc utils\n\n// millisecond sleep\nvoid millisleep(int ms);\n// evaluate given predicate until it returns true or the timeout \n// (in millis) has expired\ntemplate<class Predicate>\nint ensureCondition(const Predicate& p,int timeout){\n    int elapsed=0;\n    while(!p() && elapsed<timeout){\n        millisleep(2);\n        elapsed+=2;\n    }\n    return elapsed;\n};\n\n// *****************************************************************************\n// test global configuration data \nclass TestConfig{\n    typedef std::vector<std::string> CmdLineOptList;\npublic:\n    typedef CmdLineOptList::const_iterator const_iterator;\n    TestConfig(){}\n    ~TestConfig(){}\n    void addConfigFromCmdLine(int argc, char* argv[]){\n        if(argc>=2)\n            testName_=argv[1];\n        for(int i=2; i<argc;++i)\n            cmdOpts_.push_back(argv[i]);\n    }\n    const_iterator getExtraOptBegin() const {return cmdOpts_.begin();}\n    const_iterator getExtraOptEnd() const {return cmdOpts_.end();}\n    size_t getExtraOptCount() const {\n        return cmdOpts_.size();\n    }\n    const std::string& getTestName() const {\n        return testName_==\"all\"?EMPTY_STRING:testName_;\n    }\nprivate:\n    CmdLineOptList cmdOpts_;\n    std::string testName_;\n};\n\nextern TestConfig globalTestConfig;\n\n#endif /*UTIL_H_*/\n"
  },
  {
    "path": "src/recipes/lock/src/c/tests/zkServer.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nif [ \"x$1\" == \"x\" ]\nthen\n\techo \"USAGE: $0 startClean|start|stop hostPorts\"\n\texit 2\nfi\n\nif [ \"x$1\" == \"xstartClean\" ]\nthen\n\trm -rf /tmp/zkdata\nfi\n\n# Make sure nothing is left over from before\nif [ -r \"/tmp/zk.pid\" ]\nthen\npid=`cat /tmp/zk.pid`\nkill -9 $pid\nrm -f /tmp/zk.pid\nfi\n\nbase_dir=\"../../../../..\"\n\nCLASSPATH=\"$CLASSPATH:${base_dir}/build/classes\"\nCLASSPATH=\"$CLASSPATH:${base_dir}/conf\"\n\nfor f in \"${base_dir}\"/zookeeper-*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$f\"\ndone\n\nfor i in \"${base_dir}\"/build/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nfor i in \"${base_dir}\"/src/java/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nCLASSPATH=\"$CLASSPATH:${CLOVER_HOME}/lib/clover.jar\"\n\ncase $1 in\nstart|startClean)\n\tmkdir -p /tmp/zkdata\n\tjava -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22181 /tmp/zkdata &> /tmp/zk.log &\n        echo $! > /tmp/zk.pid\n        sleep 5\n\t;;\nstop)\n\t# Already killed above\n\t;;\n*)\n\techo \"Unknown command \" + $1\n\texit 2\nesac\n\n"
  },
  {
    "path": "src/recipes/lock/src/java/org/apache/zookeeper/recipes/lock/LockListener.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\n/**\n * This class has two methods which are call\n * back methods when a lock is acquired and \n * when the lock is released.\n *\n */\npublic interface LockListener {\n    /**\n     * call back called when the lock \n     * is acquired\n     */\n    public void lockAcquired();\n    \n    /**\n     * call back called when the lock is \n     * released.\n     */\n    public void lockReleased();\n}\n"
  },
  {
    "path": "src/recipes/lock/src/java/org/apache/zookeeper/recipes/lock/ProtocolSupport.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\nimport org.apache.zookeeper.recipes.lock.ZooKeeperOperation;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * A base class for protocol implementations which provides a number of higher \n * level helper methods for working with ZooKeeper along with retrying synchronous\n *  operations if the connection to ZooKeeper closes such as \n *  {@link #retryOperation(ZooKeeperOperation)}\n *\n */\nclass ProtocolSupport {\n    private static final Logger LOG = LoggerFactory.getLogger(ProtocolSupport.class);\n\n    protected final ZooKeeper zookeeper;\n    private AtomicBoolean closed = new AtomicBoolean(false);\n    private long retryDelay = 500L;\n    private int retryCount = 10;\n    private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;\n\n    public ProtocolSupport(ZooKeeper zookeeper) {\n        this.zookeeper = zookeeper;\n    }\n\n    /**\n     * Closes this strategy and releases any ZooKeeper resources; but keeps the\n     *  ZooKeeper instance open\n     */\n    public void close() {\n        if (closed.compareAndSet(false, true)) {\n            doClose();\n        }\n    }\n    \n    /**\n     * return zookeeper client instance\n     * @return zookeeper client instance\n     */\n    public ZooKeeper getZookeeper() {\n        return zookeeper;\n    }\n\n    /**\n     * return the acl its using\n     * @return the acl.\n     */\n    public List<ACL> getAcl() {\n        return acl;\n    }\n\n    /**\n     * set the acl \n     * @param acl the acl to set to\n     */\n    public void setAcl(List<ACL> acl) {\n        this.acl = acl;\n    }\n\n    /**\n     * get the retry delay in milliseconds\n     * @return the retry delay\n     */\n    public long getRetryDelay() {\n        return retryDelay;\n    }\n\n    /**\n     * Sets the time waited between retry delays\n     * @param retryDelay the retry delay\n     */\n    public void setRetryDelay(long retryDelay) {\n        this.retryDelay = retryDelay;\n    }\n\n    /**\n     * Allow derived classes to perform \n     * some custom closing operations to release resources\n     */\n    protected void doClose() {\n    }\n\n\n    /**\n     * Perform the given operation, retrying if the connection fails\n     * @return object. it needs to be cast to the callee's expected \n     * return type.\n     */\n    protected Object retryOperation(ZooKeeperOperation operation) \n        throws KeeperException, InterruptedException {\n        KeeperException exception = null;\n        for (int i = 0; i < retryCount; i++) {\n            try {\n                return operation.execute();\n            } catch (KeeperException.SessionExpiredException e) {\n                LOG.warn(\"Session expired for: \" + zookeeper + \" so reconnecting due to: \" + e, e);\n                throw e;\n            } catch (KeeperException.ConnectionLossException e) {\n                if (exception == null) {\n                    exception = e;\n                }\n                LOG.debug(\"Attempt \" + i + \" failed with connection loss so \" +\n                \t\t\"attempting to reconnect: \" + e, e);\n                retryDelay(i);\n            }\n        }\n        throw exception;\n    }\n\n    /**\n     * Ensures that the given path exists with no data, the current\n     * ACL and no flags\n     * @param path\n     */\n    protected void ensurePathExists(String path) {\n        ensureExists(path, null, acl, CreateMode.PERSISTENT);\n    }\n\n    /**\n     * Ensures that the given path exists with the given data, ACL and flags\n     * @param path\n     * @param acl\n     * @param flags\n     */\n    protected void ensureExists(final String path, final byte[] data,\n            final List<ACL> acl, final CreateMode flags) {\n        try {\n            retryOperation(new ZooKeeperOperation() {\n                public boolean execute() throws KeeperException, InterruptedException {\n                    Stat stat = zookeeper.exists(path, false);\n                    if (stat != null) {\n                        return true;\n                    }\n                    zookeeper.create(path, data, acl, flags);\n                    return true;\n                }\n            });\n        } catch (KeeperException e) {\n            LOG.warn(\"Caught: \" + e, e);\n        } catch (InterruptedException e) {\n            LOG.warn(\"Caught: \" + e, e);\n        }\n    }\n\n    /**\n     * Returns true if this protocol has been closed\n     * @return true if this protocol is closed\n     */\n    protected boolean isClosed() {\n        return closed.get();\n    }\n\n    /**\n     * Performs a retry delay if this is not the first attempt\n     * @param attemptCount the number of the attempts performed so far\n     */\n    protected void retryDelay(int attemptCount) {\n        if (attemptCount > 0) {\n            try {\n                Thread.sleep(attemptCount * retryDelay);\n            } catch (InterruptedException e) {\n                LOG.debug(\"Failed to sleep: \" + e, e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/recipes/lock/src/java/org/apache/zookeeper/recipes/lock/WriteLock.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport static org.apache.zookeeper.CreateMode.EPHEMERAL_SEQUENTIAL;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\n\nimport java.util.List;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * A <a href=\"package.html\">protocol to implement an exclusive\n *  write lock or to elect a leader</a>. <p/> You invoke {@link #lock()} to \n *  start the process of grabbing the lock; you may get the lock then or it may be \n *  some time later. <p/> You can register a listener so that you are invoked \n *  when you get the lock; otherwise you can ask if you have the lock\n *  by calling {@link #isOwner()}\n *\n */\npublic class WriteLock extends ProtocolSupport {\n    private static final Logger LOG = LoggerFactory.getLogger(WriteLock.class);\n\n    private final String dir;\n    private String id;\n    private ZNodeName idName;\n    private String ownerId;\n    private String lastChildId;\n    private byte[] data = {0x12, 0x34};\n    private LockListener callback;\n    private LockZooKeeperOperation zop;\n    \n    /**\n     * zookeeper contructor for writelock\n     * @param zookeeper zookeeper client instance\n     * @param dir the parent path you want to use for locking\n     * @param acls the acls that you want to use for all the paths, \n     * if null world read/write is used.\n     */\n    public WriteLock(ZooKeeper zookeeper, String dir, List<ACL> acl) {\n        super(zookeeper);\n        this.dir = dir;\n        if (acl != null) {\n            setAcl(acl);\n        }\n        this.zop = new LockZooKeeperOperation();\n    }\n    \n    /**\n     * zookeeper contructor for writelock with callback\n     * @param zookeeper the zookeeper client instance\n     * @param dir the parent path you want to use for locking\n     * @param acl the acls that you want to use for all the paths\n     * @param callback the call back instance\n     */\n    public WriteLock(ZooKeeper zookeeper, String dir, List<ACL> acl, \n            LockListener callback) {\n        this(zookeeper, dir, acl);\n        this.callback = callback;\n    }\n\n    /**\n     * return the current locklistener\n     * @return the locklistener\n     */\n    public LockListener getLockListener() {\n        return this.callback;\n    }\n    \n    /**\n     * register a different call back listener\n     * @param callback the call back instance\n     */\n    public void setLockListener(LockListener callback) {\n        this.callback = callback;\n    }\n\n    /**\n     * Removes the lock or associated znode if \n     * you no longer require the lock. this also \n     * removes your request in the queue for locking\n     * in case you do not already hold the lock.\n     * @throws RuntimeException throws a runtime exception\n     * if it cannot connect to zookeeper.\n     */\n    public synchronized void unlock() throws RuntimeException {\n        \n        if (!isClosed() && id != null) {\n            // we don't need to retry this operation in the case of failure\n            // as ZK will remove ephemeral files and we don't wanna hang\n            // this process when closing if we cannot reconnect to ZK\n            try {\n                \n                ZooKeeperOperation zopdel = new ZooKeeperOperation() {\n                    public boolean execute() throws KeeperException,\n                        InterruptedException {\n                        zookeeper.delete(id, -1);   \n                        return Boolean.TRUE;\n                    }\n                };\n                zopdel.execute();\n            } catch (InterruptedException e) {\n                LOG.warn(\"Caught: \" + e, e);\n                //set that we have been interrupted.\n               Thread.currentThread().interrupt();\n            } catch (KeeperException.NoNodeException e) {\n                // do nothing\n            } catch (KeeperException e) {\n                LOG.warn(\"Caught: \" + e, e);\n                throw (RuntimeException) new RuntimeException(e.getMessage()).\n                    initCause(e);\n            }\n            finally {\n                if (callback != null) {\n                    callback.lockReleased();\n                }\n                id = null;\n            }\n        }\n    }\n    \n    /** \n     * the watcher called on  \n     * getting watch while watching \n     * my predecessor\n     */\n    private class LockWatcher implements Watcher {\n        public void process(WatchedEvent event) {\n            // lets either become the leader or watch the new/updated node\n            LOG.debug(\"Watcher fired on path: \" + event.getPath() + \" state: \" + \n                    event.getState() + \" type \" + event.getType());\n            try {\n                lock();\n            } catch (Exception e) {\n                LOG.warn(\"Failed to acquire lock: \" + e, e);\n            }\n        }\n    }\n    \n    /**\n     * a zoookeeper operation that is mainly responsible\n     * for all the magic required for locking.\n     */\n    private  class LockZooKeeperOperation implements ZooKeeperOperation {\n        \n        /** find if we have been created earler if not create our node\n         * \n         * @param prefix the prefix node\n         * @param zookeeper teh zookeeper client\n         * @param dir the dir paretn\n         * @throws KeeperException\n         * @throws InterruptedException\n         */\n        private void findPrefixInChildren(String prefix, ZooKeeper zookeeper, String dir) \n            throws KeeperException, InterruptedException {\n            List<String> names = zookeeper.getChildren(dir, false);\n            for (String name : names) {\n                if (name.startsWith(prefix)) {\n                    id = name;\n                    if (LOG.isDebugEnabled()) {\n                        LOG.debug(\"Found id created last time: \" + id);\n                    }\n                    break;\n                }\n            }\n            if (id == null) {\n                id = zookeeper.create(dir + \"/\" + prefix, data, \n                        getAcl(), EPHEMERAL_SEQUENTIAL);\n\n                if (LOG.isDebugEnabled()) {\n                    LOG.debug(\"Created id: \" + id);\n                }\n            }\n\n        }\n        \n        /**\n         * the command that is run and retried for actually \n         * obtaining the lock\n         * @return if the command was successful or not\n         */\n        public boolean execute() throws KeeperException, InterruptedException {\n            do {\n                if (id == null) {\n                    long sessionId = zookeeper.getSessionId();\n                    String prefix = \"x-\" + sessionId + \"-\";\n                    // lets try look up the current ID if we failed \n                    // in the middle of creating the znode\n                    findPrefixInChildren(prefix, zookeeper, dir);\n                    idName = new ZNodeName(id);\n                }\n                if (id != null) {\n                    List<String> names = zookeeper.getChildren(dir, false);\n                    if (names.isEmpty()) {\n                        LOG.warn(\"No children in: \" + dir + \" when we've just \" +\n                        \"created one! Lets recreate it...\");\n                        // lets force the recreation of the id\n                        id = null;\n                    } else {\n                        // lets sort them explicitly (though they do seem to come back in order ususally :)\n                        SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();\n                        for (String name : names) {\n                            sortedNames.add(new ZNodeName(dir + \"/\" + name));\n                        }\n                        ownerId = sortedNames.first().getName();\n                        SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName);\n                        if (!lessThanMe.isEmpty()) {\n                            ZNodeName lastChildName = lessThanMe.last();\n                            lastChildId = lastChildName.getName();\n                            if (LOG.isDebugEnabled()) {\n                                LOG.debug(\"watching less than me node: \" + lastChildId);\n                            }\n                            Stat stat = zookeeper.exists(lastChildId, new LockWatcher());\n                            if (stat != null) {\n                                return Boolean.FALSE;\n                            } else {\n                                LOG.warn(\"Could not find the\" +\n                                \t\t\" stats for less than me: \" + lastChildName.getName());\n                            }\n                        } else {\n                            if (isOwner()) {\n                                if (callback != null) {\n                                    callback.lockAcquired();\n                                }\n                                return Boolean.TRUE;\n                            }\n                        }\n                    }\n                }\n            }\n            while (id == null);\n            return Boolean.FALSE;\n        }\n    };\n\n    /**\n     * Attempts to acquire the exclusive write lock returning whether or not it was\n     * acquired. Note that the exclusive lock may be acquired some time later after\n     * this method has been invoked due to the current lock owner going away.\n     */\n    public synchronized boolean lock() throws KeeperException, InterruptedException {\n        if (isClosed()) {\n            return false;\n        }\n        ensurePathExists(dir);\n\n        return (Boolean) retryOperation(zop);\n    }\n\n    /**\n     * return the parent dir for lock\n     * @return the parent dir used for locks.\n     */\n    public String getDir() {\n        return dir;\n    }\n\n    /**\n     * Returns true if this node is the owner of the\n     *  lock (or the leader)\n     */\n    public boolean isOwner() {\n        return id != null && ownerId != null && id.equals(ownerId);\n    }\n\n    /**\n     * return the id for this lock\n     * @return the id for this lock\n     */\n    public String getId() {\n       return this.id;\n    }\n}\n\n"
  },
  {
    "path": "src/recipes/lock/src/java/org/apache/zookeeper/recipes/lock/ZNodeName.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Represents an ephemeral znode name which has an ordered sequence number\n * and can be sorted in order\n *\n */\nclass ZNodeName implements Comparable<ZNodeName> {\n    private final String name;\n    private String prefix;\n    private int sequence = -1;\n    private static final Logger LOG = LoggerFactory.getLogger(ZNodeName.class);\n    \n    public ZNodeName(String name) {\n        if (name == null) {\n            throw new NullPointerException(\"id cannot be null\");\n        }\n        this.name = name;\n        this.prefix = name;\n        int idx = name.lastIndexOf('-');\n        if (idx >= 0) {\n            this.prefix = name.substring(0, idx);\n            try {\n                this.sequence = Integer.parseInt(name.substring(idx + 1));\n                // If an exception occurred we misdetected a sequence suffix,\n                // so return -1.\n            } catch (NumberFormatException e) {\n                LOG.info(\"Number format exception for \" + idx, e);\n            } catch (ArrayIndexOutOfBoundsException e) {\n               LOG.info(\"Array out of bounds for \" + idx, e);\n            }\n        }\n    }\n\n    @Override\n    public String toString() {\n        return name.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        ZNodeName sequence = (ZNodeName) o;\n\n        if (!name.equals(sequence.name)) return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        return name.hashCode() + 37;\n    }\n\n    /**\n     * Compare znodes based on their sequence number\n     * @param that other znode to compare to\n     * @return the difference between their sequence numbers: a positive value if this\n     *         znode has a larger sequence number, 0 if they have the same sequence number\n     *         or a negative number if this znode has a lower sequence number\n     */\n    public int compareTo(ZNodeName that) {\n        int answer = this.sequence - that.sequence;\n        if (answer == 0) {\n            return this.prefix.compareTo(that.prefix);\n        }\n        return answer;\n    }\n\n    /**\n     * Returns the name of the znode\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the sequence number\n     */\n    public int getZNodeName() {\n        return sequence;\n    }\n\n    /**\n     * Returns the text prefix before the sequence number\n     */\n    public String getPrefix() {\n        return prefix;\n    }\n}\n"
  },
  {
    "path": "src/recipes/lock/src/java/org/apache/zookeeper/recipes/lock/ZooKeeperOperation.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport org.apache.zookeeper.KeeperException;\n\n/**\n * A callback object which can be used for implementing retry-able operations in the \n * {@link org.apache.zookeeper.recipes.lock.ProtocolSupport} class\n *\n */\npublic interface ZooKeeperOperation {\n    \n    /**\n     * Performs the operation - which may be involved multiple times if the connection\n     * to ZooKeeper closes during this operation\n     *\n     * @return the result of the operation or null\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public boolean execute() throws KeeperException, InterruptedException;\n}\n"
  },
  {
    "path": "src/recipes/lock/test/org/apache/zookeeper/recipes/lock/WriteLockTest.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * test for writelock\n */\npublic class WriteLockTest extends ClientBase {\n    protected int sessionTimeout = 10 * 1000;\n    protected String dir = \"/\" + getClass().getName();\n    protected WriteLock[] nodes;\n    protected CountDownLatch latch = new CountDownLatch(1);\n    private boolean restartServer = true;\n    private boolean workAroundClosingLastZNodeFails = true;\n    private boolean killLeader = true;\n\n    @Test\n    public void testRun() throws Exception {\n        runTest(3);\n    }\n\n    class LockCallback implements LockListener {\n        public void lockAcquired() {\n            latch.countDown();\n        }\n\n        public void lockReleased() {\n            \n        }\n        \n    }\n    protected void runTest(int count) throws Exception {\n        nodes = new WriteLock[count];\n        for (int i = 0; i < count; i++) {\n            ZooKeeper keeper = createClient();\n            WriteLock leader = new WriteLock(keeper, dir, null);\n            leader.setLockListener(new LockCallback());\n            nodes[i] = leader;\n\n            leader.lock();\n        }\n\n        // lets wait for any previous leaders to die and one of our new\n        // nodes to become the new leader\n        latch.await(30, TimeUnit.SECONDS);\n\n        WriteLock first = nodes[0];\n        dumpNodes(count);\n\n        // lets assert that the first election is the leader\n        Assert.assertTrue(\"The first znode should be the leader \" + first.getId(), first.isOwner());\n\n        for (int i = 1; i < count; i++) {\n            WriteLock node = nodes[i];\n            Assert.assertFalse(\"Node should not be the leader \" + node.getId(), node.isOwner());\n        }\n\n        if (count > 1) {\n            if (killLeader) {\n            System.out.println(\"Now killing the leader\");\n            // now lets kill the leader\n            latch = new CountDownLatch(1);\n            first.unlock();\n            latch.await(30, TimeUnit.SECONDS);\n            //Thread.sleep(10000);\n            WriteLock second = nodes[1];\n            dumpNodes(count);\n            // lets assert that the first election is the leader\n            Assert.assertTrue(\"The second znode should be the leader \" + second.getId(), second.isOwner());\n\n            for (int i = 2; i < count; i++) {\n                WriteLock node = nodes[i];\n                Assert.assertFalse(\"Node should not be the leader \" + node.getId(), node.isOwner());\n            }\n            }\n\n\n            if (restartServer) {\n                // now lets stop the server\n                System.out.println(\"Now stopping the server\");\n                stopServer();\n                Thread.sleep(10000);\n\n                // TODO lets assert that we are no longer the leader\n                dumpNodes(count);\n\n                System.out.println(\"Starting the server\");\n                startServer();\n                Thread.sleep(10000);\n\n                for (int i = 0; i < count - 1; i++) {\n                    System.out.println(\"Calling acquire for node: \" + i);\n                    nodes[i].lock();\n                }\n                dumpNodes(count);\n                System.out.println(\"Now closing down...\");\n            }\n        }\n    }\n\n    protected void dumpNodes(int count) {\n        for (int i = 0; i < count; i++) {\n            WriteLock node = nodes[i];\n            System.out.println(\"node: \" + i + \" id: \" + \n                    node.getId() + \" is leader: \" + node.isOwner());\n        }\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if (nodes != null) {\n            for (int i = 0; i < nodes.length; i++) {\n                WriteLock node = nodes[i];\n                if (node != null) {\n                    System.out.println(\"Closing node: \" + i);\n                    node.close();\n                    if (workAroundClosingLastZNodeFails && i == nodes.length - 1) {\n                        System.out.println(\"Not closing zookeeper: \" + i + \" due to bug!\");\n                    } else {\n                        System.out.println(\"Closing zookeeper: \" + i);\n                        node.getZookeeper().close();\n                        System.out.println(\"Closed zookeeper: \" + i);\n                    }\n                }\n            }\n        }\n        System.out.println(\"Now lets stop the server\");\n        super.tearDown();\n\n    }\n}\n"
  },
  {
    "path": "src/recipes/lock/test/org/apache/zookeeper/recipes/lock/ZNodeNameTest.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.lock;\n\nimport junit.framework.TestCase;\n\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\nimport org.junit.Test;\n\n/**\n * test for znodenames\n */\npublic class ZNodeNameTest extends TestCase {\n    @Test\n    public void testOrderWithSamePrefix() throws Exception {\n        String[] names = { \"x-3\", \"x-5\", \"x-11\", \"x-1\" };\n        String[] expected = { \"x-1\", \"x-3\", \"x-5\", \"x-11\" };\n        assertOrderedNodeNames(names, expected);\n    }\n    @Test\n    public void testOrderWithDifferentPrefixes() throws Exception {\n        String[] names = { \"r-3\", \"r-2\", \"r-1\", \"w-2\", \"w-1\" };\n        String[] expected = { \"r-1\", \"w-1\", \"r-2\", \"w-2\", \"r-3\" };\n        assertOrderedNodeNames(names, expected);\n    }\n    @Test\n    public void testOrderWithDifferentPrefixIncludingSessionId() throws Exception {\n        String[] names = { \"x-242681582799028564-0000000002\", \"x-170623981976748329-0000000003\", \"x-98566387950223723-0000000001\" };\n        String[] expected = { \"x-98566387950223723-0000000001\", \"x-242681582799028564-0000000002\", \"x-170623981976748329-0000000003\" };\n        assertOrderedNodeNames(names, expected);\n    }\n    @Test\n    public void testOrderWithExtraPrefixes() throws Exception {\n        String[] names = { \"r-1-3-2\", \"r-2-2-1\", \"r-3-1-3\" };\n        String[] expected = { \"r-2-2-1\", \"r-1-3-2\", \"r-3-1-3\" };\n        assertOrderedNodeNames(names, expected);\n    }\n\n    protected void assertOrderedNodeNames(String[] names, String[] expected) {\n        int size = names.length;\n        SortedSet<ZNodeName> nodeNames = new TreeSet<ZNodeName>();\n        for (String name : names) {\n            nodeNames.add(new ZNodeName(name));\n        }\n        assertEquals(\"The SortedSet does not have the expected size!\", nodeNames.size(), expected.length);\n\n        int index = 0;\n        for (ZNodeName nodeName : nodeNames) {\n            String name = nodeName.getName();\n            assertEquals(\"Node \" + index, expected[index++], name);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/recipes/queue/README.txt",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n1) This queue interface recipe implements the queue recipe\nmentioned in ../../../docs/recipes.[html,pdf].\nA more detailed explanation is at http://www.cloudera.com/blog/2009/05/28/building-a-distributed-concurrent-queue-with-apache-zookeeper/\n\n2) This recipe does not handle KeeperException.ConnectionLossException or ZCONNECTIONLOSS. It will only work correctly once ZOOKEEPER-22 https://issues.apache.org/jira/browse/ZOOKEEPER-22 is resolved.\n\n3) To compile the queue java recipe you can just run ant jar from \nthis directory. \nPlease report any bugs on the jira \n\nhttp://issues.apache.org/jira/browse/ZOOKEEPER\n\n  \n"
  },
  {
    "path": "src/recipes/queue/build.xml",
    "content": "<!--\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n-->\n\n<project name=\"queue\" default=\"jar\">\n  <import file=\"../build-recipes.xml\"/>\n    <property name=\"test.main.classes\" value=\"${zk.root}/build/test/classes\"/>\n    <property name=\"test.build.dir\" value=\"${build.test}\" />\n    <property name=\"test.src.dir\" value=\"test\"/>\n    <property name=\"test.log.dir\" value=\"${test.build.dir}/logs\" />\n    <property name=\"test.data.dir\" value=\"${test.build.dir}/data\" />\n    <property name=\"test.data.upgrade.dir\" value=\"${test.data.dir}/upgrade\" />\n    <property name=\"test.tmp.dir\" value=\"${test.build.dir}/tmp\" />\n    <property name=\"test.output\" value=\"no\" />\n    <property name=\"test.timeout\" value=\"900000\" />\n    <property name=\"test.junit.output.format\" value=\"plain\" />\n    <property name=\"test.junit.fork.mode\" value=\"perTest\" />\n    <property name=\"test.junit.printsummary\" value=\"yes\" />\n    <property name=\"test.junit.haltonfailure\" value=\"no\" />\n    <property name=\"test.junit.maxmem\" value=\"512m\" />\n\n  <target name=\"setjarname\">\n    <property name=\"jarname\"\n              value=\"${build.dir}/zookeeper-${version}-recipes-${name}.jar\"/>\n  </target>\n\n  <!-- Override jar target to specify main class -->\n  <target name=\"jar\" depends=\"checkMainCompiled, setjarname, compile\">\n    <echo message=\"recipes: ${name}\"/>\n\n    <jar jarfile=\"${jarname}\">\n      <fileset file=\"${zk.root}/LICENSE.txt\" />\n      <fileset dir=\"${build.classes}\"/>\n      <fileset dir=\"${build.test}\"/>\n    </jar>\n  </target>\n\n\t<target name=\"test\" depends=\"compile-test,test-init,test-category,junit.run\" />\n\n\t<target name=\"compile-test\" depends=\"compile\">\n  \t\t<property name=\"target.jdk\" value=\"${ant.java.version}\" />\t\n\t\t<property name=\"src.test.local\" location=\"${basedir}/test\" />\n\t\t<mkdir dir=\"${build.test}\"/>\n\t\t<javac srcdir=\"${src.test.local}\" \n\t\t\tdestdir=\"${build.test}\" \n\t\t\ttarget=\"${target.jdk}\" \n\t\t\tdebug=\"on\" >\n\t\t\t<classpath refid=\"classpath\" />\n                        <classpath>\n                        <pathelement path=\"${test.main.classes}\"/>\n                        </classpath>\n\t\t</javac>\n\t</target>\n\t\n    <target name=\"test-init\" depends=\"jar,compile-test\">\n        <delete dir=\"${test.log.dir}\" />\n        <delete dir=\"${test.tmp.dir}\" />\n        <delete dir=\"${test.data.dir}\" />\n        <mkdir dir=\"${test.log.dir}\" />\n        <mkdir dir=\"${test.tmp.dir}\" />\n        <mkdir dir=\"${test.data.dir}\" />\n    </target>\n\n\t<target name=\"test-category\">\n         <property name=\"test.category\" value=\"\"/>\n    </target>\n\n\t<target name=\"junit.run\">\n\t\t<echo message=\"${test.src.dir}\" />\n        <junit showoutput=\"${test.output}\"\n               printsummary=\"${test.junit.printsummary}\"\n               haltonfailure=\"${test.junit.haltonfailure}\"\n               fork=\"yes\"\n               forkmode=\"${test.junit.fork.mode}\"\n               maxmemory=\"${test.junit.maxmem}\"\n               dir=\"${basedir}\" timeout=\"${test.timeout}\"\n               errorProperty=\"tests.failed\" failureProperty=\"tests.failed\">\n          <sysproperty key=\"build.test.dir\" value=\"${test.tmp.dir}\" />\n          <sysproperty key=\"test.data.dir\" value=\"${test.data.dir}\" />\n          <sysproperty key=\"log4j.configuration\"\n                    value=\"file:${basedir}/conf/log4j.properties\" />\n          <classpath refid=\"classpath\"/>\n          <classpath>\n             <pathelement path=\"${build.test}\" />\n             <pathelement path=\"${test.main.classes}\"/>\n          </classpath>\n          <formatter type=\"${test.junit.output.format}\" />\n          <batchtest todir=\"${test.log.dir}\" unless=\"testcase\">\n              <fileset dir=\"${test.src.dir}\"\n                     includes=\"**/*${test.category}Test.java\"/>\n          </batchtest>\n          <batchtest todir=\"${test.log.dir}\" if=\"testcase\">\n              <fileset dir=\"${test.src.dir}\" includes=\"**/${testcase}.java\"/>\n          </batchtest>\n       </junit>\n            <fail if=\"tests.failed\">Tests failed!</fail>\n    </target>\n\n  <target name=\"package\" depends=\"jar, zookeeperbuildrecipes.package\"\n          unless=\"skip.recipes\">\n\n    <copy file=\"${basedir}/build.xml\" todir=\"${dist.dir}${package.share}/recipes/${name}\"/>\n\n    <mkdir dir=\"${dist.dir}${package.share}/recipes/${name}/test\"/>\n    <copy todir=\"${dist.dir}${package.share}/recipes/${name}/test\">\n      <fileset dir=\"${basedir}/test\"/>\n    </copy>\n    <mkdir dir=\"${dist.dir}${package.share}/recipes/${name}/src\"/>\n    <copy todir=\"${dist.dir}${package.share}/recipes/${name}/src\">\n      <fileset dir=\"${basedir}/src\"/>\n    </copy>\n  </target>\n\n</project>\n\n"
  },
  {
    "path": "src/recipes/queue/src/c/INSTALL",
    "content": "Installation Instructions\n*************************\n\nCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,\n2006 Free Software Foundation, Inc.\n\nThis file is free documentation; the Free Software Foundation gives\nunlimited permission to copy, distribute and modify it.\n\nBasic Installation\n==================\n\nBriefly, the shell commands `./configure; make; make install' should\nconfigure, build, and install this package.  The following\nmore-detailed instructions are generic; see the `README' file for\ninstructions specific to this package.\n\n   The `configure' shell script attempts to guess correct values for\nvarious system-dependent variables used during compilation.  It uses\nthose values to create a `Makefile' in each directory of the package.\nIt may also create one or more `.h' files containing system-dependent\ndefinitions.  Finally, it creates a shell script `config.status' that\nyou can run in the future to recreate the current configuration, and a\nfile `config.log' containing compiler output (useful mainly for\ndebugging `configure').\n\n   It can also use an optional file (typically called `config.cache'\nand enabled with `--cache-file=config.cache' or simply `-C') that saves\nthe results of its tests to speed up reconfiguring.  Caching is\ndisabled by default to prevent problems with accidental use of stale\ncache files.\n\n   If you need to do unusual things to compile the package, please try\nto figure out how `configure' could check whether to do them, and mail\ndiffs or instructions to the address given in the `README' so they can\nbe considered for the next release.  If you are using the cache, and at\nsome point `config.cache' contains results you don't want to keep, you\nmay remove or edit it.\n\n   The file `configure.ac' (or `configure.in') is used to create\n`configure' by a program called `autoconf'.  You need `configure.ac' if\nyou want to change it or regenerate `configure' using a newer version\nof `autoconf'.\n\nThe simplest way to compile this package is:\n\n  1. `cd' to the directory containing the package's source code and type\n     `./configure' to configure the package for your system.\n\n     Running `configure' might take a while.  While running, it prints\n     some messages telling which features it is checking for.\n\n  2. Type `make' to compile the package.\n\n  3. Optionally, type `make check' to run any self-tests that come with\n     the package.\n\n  4. Type `make install' to install the programs and any data files and\n     documentation.\n\n  5. You can remove the program binaries and object files from the\n     source code directory by typing `make clean'.  To also remove the\n     files that `configure' created (so you can compile the package for\n     a different kind of computer), type `make distclean'.  There is\n     also a `make maintainer-clean' target, but that is intended mainly\n     for the package's developers.  If you use it, you may have to get\n     all sorts of other programs in order to regenerate files that came\n     with the distribution.\n\nCompilers and Options\n=====================\n\nSome systems require unusual options for compilation or linking that the\n`configure' script does not know about.  Run `./configure --help' for\ndetails on some of the pertinent environment variables.\n\n   You can give `configure' initial values for configuration parameters\nby setting variables in the command line or in the environment.  Here\nis an example:\n\n     ./configure CC=c99 CFLAGS=-g LIBS=-lposix\n\n   *Note Defining Variables::, for more details.\n\nCompiling For Multiple Architectures\n====================================\n\nYou can compile the package for more than one kind of computer at the\nsame time, by placing the object files for each architecture in their\nown directory.  To do this, you can use GNU `make'.  `cd' to the\ndirectory where you want the object files and executables to go and run\nthe `configure' script.  `configure' automatically checks for the\nsource code in the directory that `configure' is in and in `..'.\n\n   With a non-GNU `make', it is safer to compile the package for one\narchitecture at a time in the source code directory.  After you have\ninstalled the package for one architecture, use `make distclean' before\nreconfiguring for another architecture.\n\nInstallation Names\n==================\n\nBy default, `make install' installs the package's commands under\n`/usr/local/bin', include files under `/usr/local/include', etc.  You\ncan specify an installation prefix other than `/usr/local' by giving\n`configure' the option `--prefix=PREFIX'.\n\n   You can specify separate installation prefixes for\narchitecture-specific files and architecture-independent files.  If you\npass the option `--exec-prefix=PREFIX' to `configure', the package uses\nPREFIX as the prefix for installing programs and libraries.\nDocumentation and other data files still use the regular prefix.\n\n   In addition, if you use an unusual directory layout you can give\noptions like `--bindir=DIR' to specify different values for particular\nkinds of files.  Run `configure --help' for a list of the directories\nyou can set and what kinds of files go in them.\n\n   If the package supports it, you can cause programs to be installed\nwith an extra prefix or suffix on their names by giving `configure' the\noption `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.\n\nOptional Features\n=================\n\nSome packages pay attention to `--enable-FEATURE' options to\n`configure', where FEATURE indicates an optional part of the package.\nThey may also pay attention to `--with-PACKAGE' options, where PACKAGE\nis something like `gnu-as' or `x' (for the X Window System).  The\n`README' should mention any `--enable-' and `--with-' options that the\npackage recognizes.\n\n   For packages that use the X Window System, `configure' can usually\nfind the X include and library files automatically, but if it doesn't,\nyou can use the `configure' options `--x-includes=DIR' and\n`--x-libraries=DIR' to specify their locations.\n\nSpecifying the System Type\n==========================\n\nThere may be some features `configure' cannot figure out automatically,\nbut needs to determine by the type of machine the package will run on.\nUsually, assuming the package is built to be run on the _same_\narchitectures, `configure' can figure that out, but if it prints a\nmessage saying it cannot guess the machine type, give it the\n`--build=TYPE' option.  TYPE can either be a short name for the system\ntype, such as `sun4', or a canonical name which has the form:\n\n     CPU-COMPANY-SYSTEM\n\nwhere SYSTEM can have one of these forms:\n\n     OS KERNEL-OS\n\n   See the file `config.sub' for the possible values of each field.  If\n`config.sub' isn't included in this package, then this package doesn't\nneed to know the machine type.\n\n   If you are _building_ compiler tools for cross-compiling, you should\nuse the option `--target=TYPE' to select the type of system they will\nproduce code for.\n\n   If you want to _use_ a cross compiler, that generates code for a\nplatform different from the build platform, you should specify the\n\"host\" platform (i.e., that on which the generated programs will\neventually be run) with `--host=TYPE'.\n\nSharing Defaults\n================\n\nIf you want to set default values for `configure' scripts to share, you\ncan create a site shell script called `config.site' that gives default\nvalues for variables like `CC', `cache_file', and `prefix'.\n`configure' looks for `PREFIX/share/config.site' if it exists, then\n`PREFIX/etc/config.site' if it exists.  Or, you can set the\n`CONFIG_SITE' environment variable to the location of the site script.\nA warning: not all `configure' scripts look for a site script.\n\nDefining Variables\n==================\n\nVariables not defined in a site shell script can be set in the\nenvironment passed to `configure'.  However, some packages may run\nconfigure again during the build, and the customized values of these\nvariables may be lost.  In order to avoid this problem, you should set\nthem in the `configure' command line, using `VAR=value'.  For example:\n\n     ./configure CC=/usr/local2/bin/gcc\n\ncauses the specified `gcc' to be used as the C compiler (unless it is\noverridden in the site shell script).\n\nUnfortunately, this technique does not work for `CONFIG_SHELL' due to\nan Autoconf bug.  Until the bug is fixed you can use this workaround:\n\n     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash\n\n`configure' Invocation\n======================\n\n`configure' recognizes the following options to control how it operates.\n\n`--help'\n`-h'\n     Print a summary of the options to `configure', and exit.\n\n`--version'\n`-V'\n     Print the version of Autoconf used to generate the `configure'\n     script, and exit.\n\n`--cache-file=FILE'\n     Enable the cache: use and save the results of the tests in FILE,\n     traditionally `config.cache'.  FILE defaults to `/dev/null' to\n     disable caching.\n\n`--config-cache'\n`-C'\n     Alias for `--cache-file=config.cache'.\n\n`--quiet'\n`--silent'\n`-q'\n     Do not print messages saying which checks are being made.  To\n     suppress all normal output, redirect it to `/dev/null' (any error\n     messages will still be shown).\n\n`--srcdir=DIR'\n     Look for the package's source code in directory DIR.  Usually\n     `configure' can determine that directory automatically.\n\n`configure' also accepts some other, not widely useful, options.  Run\n`configure --help' for more details.\n\n"
  },
  {
    "path": "src/recipes/queue/src/c/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/recipes/queue/src/c/Makefile.am",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ninclude $(top_srcdir)/aminclude.am\n\nAM_CFLAGS = -Wall -fPIC -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated \\\n  -I$(top_srcdir)/include -I/usr/include \nAM_CPPFLAGS = -Wall -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated\\\n  -I${top_srcdir}/include -I/usr/include\nEXTRA_DIST = LICENSE\nlib_LTLIBRARIES = libzooqueue.la\nlibzooqueue_la_SOURCES = src/zoo_queue.c include/zoo_queue.h\nlibzooqueue_la_CPPFLAGS = -DDLOPEN_MODULE\nlibzooqueue_la_LDFLAGS = -version-info 0:1:0\n\n#run the tests now\n\nTEST_SOURCES = tests/TestDriver.cc tests/TestClient.cc tests/Util.cc \n\n\ncheck_PROGRAMS = zkqueuetest\nnodist_zkqueuetest_SOURCES = ${TEST_SOURCES}\nzkqueuetest_LDADD =  ${ZOOKEEPER_LD} libzooqueue.la -lpthread  ${CPPUNIT_LIBS}\nzkqueuetest_CXXFLAGS = -DUSE_STATIC_LIB ${CPPUNIT_CFLAGS}\n\nrun-check: check\n\t./zkqueuetest ${TEST_OPTIONS}\n\nclean-local: clean-check\n\t${RM} ${DX_CLEANFILES}\n\nclean-check:\n\t${RM} ${nodist_zkqueuetest_OBJECTS} \n"
  },
  {
    "path": "src/recipes/queue/src/c/README.txt",
    "content": "                     Zookeeper C queue client library \n\n\nINSTALLATION\n\nIf you're building the client from a source checkout you need to\nfollow the steps outlined below. If you're building from a release\ntar downloaded from Apache please skip to step 2.\n\nThis recipe does not handle ZCONNECTIONLOSS. It will only work correctly once ZOOKEEPER-22 https://issues.apache.org/jira/browse/ZOOKEEPER-22 is resolved.\n\n1) make sure that you compile the main zookeeper c client library.\n \n2) change directory to src/recipes/queue/src/c \n    and do a \"autoreconf -if\" to bootstrap\n   autoconf, automake and libtool. Please make sure you have autoconf\n   version 2.59 or greater installed.\n3) do a \"./configure [OPTIONS]\" to generate the makefile. See INSTALL\n   for general information about running configure.\n\n4) do a \"make\" or \"make install\" to build the libraries and install them. \n   Alternatively, you can also build and run a unit test suite (and\n   you probably should).  Please make sure you have cppunit-1.10.x or\n   higher installed before you execute step 4.  Once ./configure has\n   finished, do a \"make run-check\". It will build the libraries, build\n   the tests and run them.\n5) to generate doxygen documentation do a \"make doxygen-doc\". All\n   documentations will be placed to a new subfolder named docs. By\n   default only HTML documentation is generated.  For information on\n   other document formats please use \"./configure --help\"\n"
  },
  {
    "path": "src/recipes/queue/src/c/acinclude.m4",
    "content": "# This file is part of Autoconf.                       -*- Autoconf -*-\n\n# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Autoconf macro files.\n\n# Generate automatic documentation using Doxygen. Works in concert with the\n# aminclude.m4 file and a compatible doxygen configuration file. Defines the\n# following public macros:\n#\n# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.\n# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,\n# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'\n# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',\n# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment\n# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'\n# paper size.\n#\n# By default, HTML, PDF and PS documentation is generated as this seems to be\n# the most popular and portable combination. MAN pages created by Doxygen are\n# usually problematic, though by picking an appropriate subset and doing some\n# massaging they might be better than nothing. CHM and RTF are specific for MS\n# (note that you can't generate both HTML and CHM at the same time). The XML is\n# rather useless unless you apply specialized post-processing to it.\n#\n# The macro mainly controls the default state of the feature. The use can\n# override the default by specifying --enable or --disable. The macros ensure\n# that contradictory flags are not given (e.g., --enable-doxygen-html and\n# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)\n# Finally, each feature will be automatically disabled (with a warning) if the\n# required programs are missing.\n#\n# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with\n# the following parameters: a one-word name for the project for use as a\n# filename base etc., an optional configuration file name (the default is\n# 'Doxyfile', the same as Doxygen's default), and an optional output directory\n# name (the default is 'doxygen-doc').\n\n## ----------##\n## Defaults. ##\n## ----------##\n\nDX_ENV=\"\"\nAC_DEFUN([DX_FEATURE_doc],  ON)\nAC_DEFUN([DX_FEATURE_dot],  ON)\nAC_DEFUN([DX_FEATURE_man],  OFF)\nAC_DEFUN([DX_FEATURE_html], ON)\nAC_DEFUN([DX_FEATURE_chm],  OFF)\nAC_DEFUN([DX_FEATURE_chi],  OFF)\nAC_DEFUN([DX_FEATURE_rtf],  OFF)\nAC_DEFUN([DX_FEATURE_xml],  OFF)\nAC_DEFUN([DX_FEATURE_pdf],  ON)\nAC_DEFUN([DX_FEATURE_ps],   ON)\n\n## --------------- ##\n## Private macros. ##\n## --------------- ##\n\n# DX_ENV_APPEND(VARIABLE, VALUE)\n# ------------------------------\n# Append VARIABLE=\"VALUE\" to DX_ENV for invoking doxygen.\nAC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], [\"$DX_ENV $1='$2'\"])])\n\n# DX_DIRNAME_EXPR\n# ---------------\n# Expand into a shell expression prints the directory part of a path.\nAC_DEFUN([DX_DIRNAME_EXPR],\n         [[expr \".$1\" : '\\(\\.\\)[^/]*$' \\| \"x$1\" : 'x\\(.*\\)/[^/]*$']])\n\n# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)\n# -------------------------------------\n# Expands according to the M4 (static) status of the feature.\nAC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])\n\n# DX_REQUIRE_PROG(VARIABLE, PROGRAM)\n# ----------------------------------\n# Require the specified program to be found for the DX_CURRENT_FEATURE to work.\nAC_DEFUN([DX_REQUIRE_PROG], [\nAC_PATH_TOOL([$1], [$2])\nif test \"$DX_FLAG_$[DX_CURRENT_FEATURE$$1]\" = 1; then\n    AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])\n    AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\nfi\n])\n\n# DX_TEST_FEATURE(FEATURE)\n# ------------------------\n# Expand to a shell expression testing whether the feature is active.\nAC_DEFUN([DX_TEST_FEATURE], [test \"$DX_FLAG_$1\" = 1])\n\n# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)\n# -------------------------------------------------\n# Verify that a required features has the right state before trying to turn on\n# the DX_CURRENT_FEATURE.\nAC_DEFUN([DX_CHECK_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" \\\n|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,\n                            requires, contradicts) doxygen-DX_CURRENT_FEATURE])\n])\n\n# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)\n# ----------------------------------------------------------\n# Turn off the DX_CURRENT_FEATURE if the required feature is off.\nAC_DEFUN([DX_CLEAR_DEPEND], [\ntest \"$DX_FLAG_$1\" = \"$2\" || AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)\n])\n\n# DX_FEATURE_ARG(FEATURE, DESCRIPTION,\n#                CHECK_DEPEND, CLEAR_DEPEND,\n#                REQUIRE, DO-IF-ON, DO-IF-OFF)\n# --------------------------------------------\n# Parse the command-line option controlling a feature. CHECK_DEPEND is called\n# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),\n# otherwise CLEAR_DEPEND is called to turn off the default state if a required\n# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional\n# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and\n# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.\nAC_DEFUN([DX_ARG_ABLE], [\n    AC_DEFUN([DX_CURRENT_FEATURE], [$1])\n    AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])\n    AC_ARG_ENABLE(doxygen-$1,\n                  [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],\n                                                      [--enable-doxygen-$1]),\n                                  DX_IF_FEATURE([$1], [don't $2], [$2]))],\n                  [\ncase \"$enableval\" in\n#(\ny|Y|yes|Yes|YES)\n    AC_SUBST([DX_FLAG_$1], 1)\n    $3\n;; #(\nn|N|no|No|NO)\n    AC_SUBST([DX_FLAG_$1], 0)\n;; #(\n*)\n    AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])\n;;\nesac\n], [\nAC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])\n$4\n])\nif DX_TEST_FEATURE([$1]); then\n    $5\n    :\nfi\nif DX_TEST_FEATURE([$1]); then\n    AM_CONDITIONAL(DX_COND_$1, :)\n    $6\n    :\nelse\n    AM_CONDITIONAL(DX_COND_$1, false)\n    $7\n    :\nfi\n])\n\n## -------------- ##\n## Public macros. ##\n## -------------- ##\n\n# DX_XXX_FEATURE(DEFAULT_STATE)\n# -----------------------------\nAC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc],  [$1])])\nAC_DEFUN([DX_MAN_FEATURE],     [AC_DEFUN([DX_FEATURE_man],  [$1])])\nAC_DEFUN([DX_HTML_FEATURE],    [AC_DEFUN([DX_FEATURE_html], [$1])])\nAC_DEFUN([DX_CHM_FEATURE],     [AC_DEFUN([DX_FEATURE_chm],  [$1])])\nAC_DEFUN([DX_CHI_FEATURE],     [AC_DEFUN([DX_FEATURE_chi],  [$1])])\nAC_DEFUN([DX_RTF_FEATURE],     [AC_DEFUN([DX_FEATURE_rtf],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])\nAC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])\nAC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])\n\n# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])\n# ---------------------------------------------------------\n# PROJECT also serves as the base name for the documentation files.\n# The default CONFIG-FILE is \"Doxyfile\" and OUTPUT-DOC-DIR is \"doxygen-doc\".\nAC_DEFUN([DX_INIT_DOXYGEN], [\n\n# Files:\nAC_SUBST([DX_PROJECT], [$1])\nAC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])\nAC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])\n\n# Environment variables used inside doxygen.cfg:\nDX_ENV_APPEND(SRCDIR, $srcdir)\nDX_ENV_APPEND(PROJECT, $DX_PROJECT)\nDX_ENV_APPEND(DOCDIR, $DX_DOCDIR)\nDX_ENV_APPEND(VERSION, $PACKAGE_VERSION)\n\n# Doxygen itself:\nDX_ARG_ABLE(doc, [generate any doxygen documentation],\n            [],\n            [],\n            [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)\n             DX_REQUIRE_PROG([DX_PERL], perl)],\n            [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])\n\n# Dot for graphics:\nDX_ARG_ABLE(dot, [generate graphics for doxygen documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_DOT], dot)],\n            [DX_ENV_APPEND(HAVE_DOT, YES)\n             DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],\n            [DX_ENV_APPEND(HAVE_DOT, NO)])\n\n# Man pages generation:\nDX_ARG_ABLE(man, [generate doxygen manual pages],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_MAN, YES)],\n            [DX_ENV_APPEND(GENERATE_MAN, NO)])\n\n# RTF file generation:\nDX_ARG_ABLE(rtf, [generate doxygen RTF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_RTF, YES)],\n            [DX_ENV_APPEND(GENERATE_RTF, NO)])\n\n# XML file generation:\nDX_ARG_ABLE(xml, [generate doxygen XML documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_XML, YES)],\n            [DX_ENV_APPEND(GENERATE_XML, NO)])\n\n# (Compressed) HTML help generation:\nDX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_HHC], hhc)],\n            [DX_ENV_APPEND(HHC_PATH, $DX_HHC)\n             DX_ENV_APPEND(GENERATE_HTML, YES)\n             DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],\n            [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])\n\n# Seperate CHI file generation.\nDX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],\n            [DX_CHECK_DEPEND(chm, 1)],\n            [DX_CLEAR_DEPEND(chm, 1)],\n            [],\n            [DX_ENV_APPEND(GENERATE_CHI, YES)],\n            [DX_ENV_APPEND(GENERATE_CHI, NO)])\n\n# Plain HTML pages generation:\nDX_ARG_ABLE(html, [generate doxygen plain HTML documentation],\n            [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],\n            [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],\n            [],\n            [DX_ENV_APPEND(GENERATE_HTML, YES)],\n            [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])\n\n# PostScript file generation:\nDX_ARG_ABLE(ps, [generate doxygen PostScript documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_LATEX], latex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_DVIPS], dvips)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# PDF file generation:\nDX_ARG_ABLE(pdf, [generate doxygen PDF documentation],\n            [DX_CHECK_DEPEND(doc, 1)],\n            [DX_CLEAR_DEPEND(doc, 1)],\n            [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)\n             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)\n             DX_REQUIRE_PROG([DX_EGREP], egrep)])\n\n# LaTeX generation for PS and/or PDF:\nif DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then\n    AM_CONDITIONAL(DX_COND_latex, :)\n    DX_ENV_APPEND(GENERATE_LATEX, YES)\nelse\n    AM_CONDITIONAL(DX_COND_latex, false)\n    DX_ENV_APPEND(GENERATE_LATEX, NO)\nfi\n\n# Paper size for PS and/or PDF:\nAC_ARG_VAR(DOXYGEN_PAPER_SIZE,\n           [a4wide (default), a4, letter, legal or executive])\ncase \"$DOXYGEN_PAPER_SIZE\" in\n#(\n\"\")\n    AC_SUBST(DOXYGEN_PAPER_SIZE, \"\")\n;; #(\na4wide|a4|letter|legal|executive)\n    DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)\n;; #(\n*)\n    AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])\n;;\nesac\n\n#For debugging:\n#echo DX_FLAG_doc=$DX_FLAG_doc\n#echo DX_FLAG_dot=$DX_FLAG_dot\n#echo DX_FLAG_man=$DX_FLAG_man\n#echo DX_FLAG_html=$DX_FLAG_html\n#echo DX_FLAG_chm=$DX_FLAG_chm\n#echo DX_FLAG_chi=$DX_FLAG_chi\n#echo DX_FLAG_rtf=$DX_FLAG_rtf\n#echo DX_FLAG_xml=$DX_FLAG_xml\n#echo DX_FLAG_pdf=$DX_FLAG_pdf\n#echo DX_FLAG_ps=$DX_FLAG_ps\n#echo DX_ENV=$DX_ENV\n])\n"
  },
  {
    "path": "src/recipes/queue/src/c/aminclude.am",
    "content": "# Copyright (C) 2004 Oren Ben-Kiki\n# This file is distributed under the same terms as the Automake macro files.\n\n# Generate automatic documentation using Doxygen. Goals and variables values\n# are controlled by the various DX_COND_??? conditionals set by autoconf.\n#\n# The provided goals are:\n# doxygen-doc: Generate all doxygen documentation.\n# doxygen-run: Run doxygen, which will generate some of the documentation\n#              (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post\n#              processing required for the rest of it (PS, PDF, and some MAN).\n# doxygen-man: Rename some doxygen generated man pages.\n# doxygen-ps: Generate doxygen PostScript documentation.\n# doxygen-pdf: Generate doxygen PDF documentation.\n#\n# Note that by default these are not integrated into the automake goals. If\n# doxygen is used to generate man pages, you can achieve this integration by\n# setting man3_MANS to the list of man pages generated and then adding the\n# dependency:\n#\n#   $(man3_MANS): doxygen-doc\n#\n# This will cause make to run doxygen and generate all the documentation.\n#\n# The following variable is intended for use in Makefile.am:\n#\n# DX_CLEANFILES = everything to clean.\n#\n# This is usually added to MOSTLYCLEANFILES.\n\n## --------------------------------- ##\n## Format-independent Doxygen rules. ##\n## --------------------------------- ##\n\nif DX_COND_doc\n\n## ------------------------------- ##\n## Rules specific for HTML output. ##\n## ------------------------------- ##\n\nif DX_COND_html\n\nDX_CLEAN_HTML = @DX_DOCDIR@/html\n\nendif DX_COND_html\n\n## ------------------------------ ##\n## Rules specific for CHM output. ##\n## ------------------------------ ##\n\nif DX_COND_chm\n\nDX_CLEAN_CHM = @DX_DOCDIR@/chm\n\nif DX_COND_chi\n\nDX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi\n\nendif DX_COND_chi\n\nendif DX_COND_chm\n\n## ------------------------------ ##\n## Rules specific for MAN output. ##\n## ------------------------------ ##\n\nif DX_COND_man\n\nDX_CLEAN_MAN = @DX_DOCDIR@/man\n\nendif DX_COND_man\n\n## ------------------------------ ##\n## Rules specific for RTF output. ##\n## ------------------------------ ##\n\nif DX_COND_rtf\n\nDX_CLEAN_RTF = @DX_DOCDIR@/rtf\n\nendif DX_COND_rtf\n\n## ------------------------------ ##\n## Rules specific for XML output. ##\n## ------------------------------ ##\n\nif DX_COND_xml\n\nDX_CLEAN_XML = @DX_DOCDIR@/xml\n\nendif DX_COND_xml\n\n## ----------------------------- ##\n## Rules specific for PS output. ##\n## ----------------------------- ##\n\nif DX_COND_ps\n\nDX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps\n\nDX_PS_GOAL = doxygen-ps\n\ndoxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps\n\n@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_LATEX) refman.tex; \\\n\t$(MAKEINDEX_PATH) refman.idx; \\\n\t$(DX_LATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_LATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\t$(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi\n\nendif DX_COND_ps\n\n## ------------------------------ ##\n## Rules specific for PDF output. ##\n## ------------------------------ ##\n\nif DX_COND_pdf\n\nDX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf\n\nDX_PDF_GOAL = doxygen-pdf\n\ndoxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf\n\n@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag\n\tcd @DX_DOCDIR@/latex; \\\n\trm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\t$(DX_MAKEINDEX) refman.idx; \\\n\t$(DX_PDFLATEX) refman.tex; \\\n\tcountdown=5; \\\n\twhile $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\\n\t                  refman.log > /dev/null 2>&1 \\\n\t   && test $$countdown -gt 0; do \\\n\t    $(DX_PDFLATEX) refman.tex; \\\n\t    countdown=`expr $$countdown - 1`; \\\n\tdone; \\\n\tmv refman.pdf ../@PACKAGE@.pdf\n\nendif DX_COND_pdf\n\n## ------------------------------------------------- ##\n## Rules specific for LaTeX (shared for PS and PDF). ##\n## ------------------------------------------------- ##\n\nif DX_COND_latex\n\nDX_CLEAN_LATEX = @DX_DOCDIR@/latex\n\nendif DX_COND_latex\n\n.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\ndoxygen-run: @DX_DOCDIR@/@PACKAGE@.tag\n\ndoxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)\n\n@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)\n\trm -rf @DX_DOCDIR@\n\t$(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)\n\nDX_CLEANFILES = \\\n    @DX_DOCDIR@/@PACKAGE@.tag \\\n    -r \\\n    $(DX_CLEAN_HTML) \\\n    $(DX_CLEAN_CHM) \\\n    $(DX_CLEAN_CHI) \\\n    $(DX_CLEAN_MAN) \\\n    $(DX_CLEAN_RTF) \\\n    $(DX_CLEAN_XML) \\\n    $(DX_CLEAN_PS) \\\n    $(DX_CLEAN_PDF) \\\n    $(DX_CLEAN_LATEX)\n\nendif DX_COND_doc\n"
  },
  {
    "path": "src/recipes/queue/src/c/c-doc.Doxyfile",
    "content": "# Doxyfile 1.4.7\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project\n#\n# All text after a hash (#) is considered a comment and will be ignored\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \")\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \n# by quotes) that should identify the project.\n\nPROJECT_NAME = $(PROJECT)-$(VERSION)\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. \n# This could be handy for archiving the generated documentation or \n# if some version control system is used.\n\nPROJECT_NUMBER = \n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \n# base path where the generated documentation will be put. \n# If a relative path is entered, it will be relative to the location \n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY = $(DOCDIR)\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \n# 4096 sub-directories (in 2 levels) under the output directory of each output \n# format and will distribute the generated files over these directories. \n# Enabling this option can be useful when feeding doxygen a huge amount of \n# source files, where putting all generated files in the same directory would \n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all \n# documentation generated by doxygen is written. Doxygen will use this \n# information to generate all constant output in the proper language. \n# The default language is English, other supported languages are: \n# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \n# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \n# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \n# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \n# Swedish, and Ukrainian.\n\nOUTPUT_LANGUAGE = English\n\n# This tag can be used to specify the encoding used in the generated output. \n# The encoding is not always determined by the language that is chosen, \n# but also whether or not the output is meant for Windows or non-Windows users. \n# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \n# forces the Windows encoding (this is the default for the Windows binary), \n# whereas setting the tag to NO uses a Unix-style encoding (the default for \n# all platforms other than Windows).\n\nUSE_WINDOWS_ENCODING = NO\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n# include brief member descriptions after the members that are listed in \n# the file and class documentation (similar to JavaDoc). \n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n# the brief description of a member or function before the detailed description. \n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator \n# that is used to form the text in various listings. Each string \n# in this list, if found as the leading text of the brief description, will be \n# stripped from the text and the result after processing the whole list, is \n# used as the annotated text. Otherwise, the brief description is used as-is. \n# If left blank, the following values are used (\"$name\" is automatically \n# replaced with the name of the entity): \"The $name class\" \"The $name widget\" \n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\" \n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF = \n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n# Doxygen will generate a detailed section even if there is only a brief \n# description.\n\nALWAYS_DETAILED_SEC = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all \n# inherited members of a class in the documentation of that class as if those \n# members were ordinary class members. Constructors, destructors and assignment \n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n# path before files name in the file list and in the header files. If set \n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES = YES\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n# can be used to strip a user-defined part of the path. Stripping is \n# only done if one of the specified strings matches the left-hand part of \n# the path. The tag can be used to show relative paths in the file list. \n# If left blank the directory from which doxygen is run is used as the \n# path to strip.\n\nSTRIP_FROM_PATH = \n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \n# the path mentioned in the documentation of a class, which tells \n# the reader which header file to include in order to use a class. \n# If left blank only the name of the header file containing the class \n# definition is used. Otherwise one should specify the include paths that \n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH = \n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n# (but less readable) file names. This can be useful is your file systems \n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n# will interpret the first line (until the first dot) of a JavaDoc-style \n# comment as the brief description. If set to NO, the JavaDoc \n# comments will behave just like the Qt-style comments (thus requiring an \n# explicit @brief command for a brief description.\n\nJAVADOC_AUTOBRIEF = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n# treat a multi-line C++ special comment block (i.e. a block of //! or /// \n# comments) as a brief description. This used to be the default behaviour. \n# The new default is to treat a multi-line C++ comment block as a detailed \n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the DETAILS_AT_TOP tag is set to YES then Doxygen \n# will output the detailed description near the top, like JavaDoc.\n# If set to NO, the detailed description appears after the member \n# documentation.\n\nDETAILS_AT_TOP = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n# member inherits the documentation from any documented member that it \n# re-implements.\n\nINHERIT_DOCS = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce \n# a new page for each member. If set to NO, the documentation of a member will \n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. \n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE = 8\n\n# This tag can be used to specify a number of aliases that acts \n# as commands in the documentation. An alias has the form \"name=value\". \n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n# put the command \\sideeffect (or @sideeffect) in the documentation, which \n# will result in a user-defined paragraph with heading \"Side Effects:\". \n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES = \n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C \n# sources only. Doxygen will then generate output that is more tailored for C. \n# For instance, some of the names that are used will be different. The list \n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java \n# sources only. Doxygen will then generate output that is more tailored for Java. \n# For instance, namespaces will be presented as packages, qualified scopes \n# will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA = NO\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to \n# include (a tag file for) the STL sources as input, then you should \n# set this tag to YES in order to let doxygen match functions declarations and \n# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. \n# func(std::string) {}). This also make the inheritance and collaboration \n# diagrams that involve STL classes more complete and accurate.\n\nBUILTIN_STL_SUPPORT = NO\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n# tag is set to YES, then doxygen will reuse the documentation of the first \n# member in the group (if any) for the other members of the group. By default \n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n# the same type (for instance a group of public functions) to be put as a \n# subgroup of that type (e.g. under the Public Functions section). Set it to \n# NO to prevent subgrouping. Alternatively, this can be done per class using \n# the \\nosubgrouping command.\n\nSUBGROUPING = YES\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \n# documentation are documented, even if no documentation was available. \n# Private class members and static file members will be hidden unless \n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \n# will be included in the documentation.\n\nEXTRACT_PRIVATE = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file \n# will be included in the documentation.\n\nEXTRACT_STATIC = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \n# defined locally in source files will be included in the documentation. \n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES = YES\n\n# This flag is only useful for Objective-C code. When set to YES local \n# methods, which are defined in the implementation section but not in \n# the interface are included in the documentation. \n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \n# undocumented members of documented classes, files or namespaces. \n# If set to NO (the default) these members will be included in the \n# various overviews, but no documentation section is generated. \n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \n# undocumented classes that are normally visible in the class hierarchy. \n# If set to NO (the default) these classes will be included in the various \n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \n# friend (class|struct|union) declarations. \n# If set to NO (the default) these declarations will be included in the \n# documentation.\n\nHIDE_FRIEND_COMPOUNDS = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \n# documentation blocks found inside the body of a function. \n# If set to NO (the default) these blocks will be appended to the \n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS = NO\n\n# The INTERNAL_DOCS tag determines if documentation \n# that is typed after a \\internal command is included. If the tag is set \n# to NO (the default) then the documentation will be excluded. \n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \n# file names in lower-case letters. If set to YES upper-case letters are also \n# allowed. This is useful if you have classes or files whose names only differ \n# in case and if your file system supports case sensitive file names. Windows \n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \n# will show members with their full class and namespace scopes in the \n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \n# will put a list of the files that are included by a file in the documentation \n# of that file.\n\nSHOW_INCLUDE_FILES = NO\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \n# is inserted in the documentation for inline members.\n\nINLINE_INFO = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \n# will sort the (detailed) documentation of file and class members \n# alphabetically by member name. If set to NO the members will appear in \n# declaration order.\n\nSORT_MEMBER_DOCS = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \n# brief documentation of file, namespace and class members alphabetically \n# by member name. If set to NO (the default) the members will appear in \n# declaration order.\n\nSORT_BRIEF_DOCS = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \n# sorted by fully-qualified names, including namespaces. If set to \n# NO (the default), the class list will be sorted only by class name, \n# not including the namespace part. \n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the \n# alphabetical list.\n\nSORT_BY_SCOPE_NAME = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or \n# disable (NO) the todo list. This list is created by putting \\todo \n# commands in the documentation.\n\nGENERATE_TODOLIST = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or \n# disable (NO) the test list. This list is created by putting \\test \n# commands in the documentation.\n\nGENERATE_TESTLIST = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or \n# disable (NO) the bug list. This list is created by putting \\bug \n# commands in the documentation.\n\nGENERATE_BUGLIST = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \n# disable (NO) the deprecated list. This list is created by putting \n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST = YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional \n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS = \n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \n# the initial value of a variable or define consists of for it to appear in \n# the documentation. If the initializer consists of more lines than specified \n# here it will be hidden. Use a value of 0 to hide initializers completely. \n# The appearance of the initializer of individual variables and defines in the \n# documentation can be controlled using \\showinitializer or \\hideinitializer \n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \n# at the bottom of the documentation of classes and structs. If set to YES the \n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES = YES\n\n# If the sources in your project are distributed over multiple directories \n# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \n# in the documentation. The default is NO.\n\nSHOW_DIRECTORIES = NO\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that \n# doxygen should invoke to get the current version for each file (typically from the \n# version control system). Doxygen will invoke the program by executing (via \n# popen()) the command <command> <input-file>, where <command> is the value of \n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file \n# provided by doxygen. Whatever the program writes to standard output \n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER = \n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated \n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are \n# generated by doxygen. Possible values are YES and NO. If left blank \n# NO is used.\n\nWARNINGS = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \n# potential errors in the documentation, such as not documenting some \n# parameters in a documented function, or documenting parameters that \n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR = YES\n\n# This WARN_NO_PARAMDOC option can be abled to get warnings for \n# functions that are documented, but have no documentation for their parameters \n# or return value. If set to NO (the default) doxygen will only warn about \n# wrong or incomplete parameter documentation, but not about the absence of \n# documentation.\n\nWARN_NO_PARAMDOC = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that \n# doxygen can produce. The string should contain the $file, $line, and $text \n# tags, which will be replaced by the file and line number from which the \n# warning originated and the warning text. Optionally the format may contain \n# $version, which will be replaced by the version of the file (if it could \n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning \n# and error messages should be written. If left blank the output is written \n# to stderr.\n\nWARN_LOGFILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain \n# documented source files. You may enter file names like \"myfile.cpp\" or \n# directories like \"/usr/src/myproject\". Separate the files or directories \n# with spaces.\n\nINPUT = include/zoo_queue.h\n\n# If the value of the INPUT tag contains directories, you can use the \n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank the following patterns are tested: \n# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx \n# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py\n\nFILE_PATTERNS = \n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories \n# should be searched for input files as well. Possible values are YES and NO. \n# If left blank NO is used.\n\nRECURSIVE = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should \n# excluded from the INPUT source files. This way you can easily exclude a \n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n\nEXCLUDE = \n\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or \n# directories that are symbolic links (a Unix filesystem feature) are excluded \n# from the input.\n\nEXCLUDE_SYMLINKS = NO\n\n# If the value of the INPUT tag contains directories, you can use the \n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \n# certain files from those directories. Note that the wildcards are matched \n# against the file with absolute path, so to exclude all test directories \n# for example use the pattern */test/*\n\nEXCLUDE_PATTERNS = \n\n# The EXAMPLE_PATH tag can be used to specify one or more files or \n# directories that contain example code fragments that are included (see \n# the \\include command).\n\nEXAMPLE_PATH = \n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the \n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n# and *.h) to filter out the source-files in the directories. If left \n# blank all files are included.\n\nEXAMPLE_PATTERNS = \n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \n# searched for input files to be used with the \\include or \\dontinclude \n# commands irrespective of the value of the RECURSIVE tag. \n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or \n# directories that contain image that are included in the documentation (see \n# the \\image command).\n\nIMAGE_PATH = \n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should \n# invoke to filter for each input file. Doxygen will invoke the filter program \n# by executing (via popen()) the command <filter> <input-file>, where <filter> \n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \n# input file. Doxygen will then use the output that the filter program writes \n# to standard output.  If FILTER_PATTERNS is specified, this tag will be \n# ignored.\n\nINPUT_FILTER = \n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \n# basis.  Doxygen will compare the file name with each pattern and apply the \n# filter if there is a match.  The filters are a list of the form: \n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \n# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \n# is applied to all files.\n\nFILTER_PATTERNS = \n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \n# INPUT_FILTER) will be used to filter the input files when producing source \n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will \n# be generated. Documented entities will be cross-referenced with these sources. \n# Note: To get rid of all source code in the generated output, make sure also \n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body \n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \n# doxygen to hide any special comment blocks from generated source code \n# fragments. Normal C and C++ comments will always remain visible.\n\nSTRIP_CODE_COMMENTS = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES (the default) \n# then for each documented function all documented \n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES (the default) \n# then for each documented function all documented entities \n# called/used by that function will be listed.\n\nREFERENCES_RELATION = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n# link to the source code.  Otherwise they will link to the documentstion.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code \n# will point to the HTML generated by the htags(1) tool instead of doxygen \n# built-in source browser. The htags tool is part of GNU's global source \n# tagging system (see http://www.gnu.org/software/global/global.html). You \n# will need version 4.8.6 or higher.\n\nUSE_HTAGS = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \n# will generate a verbatim copy of the header file for each class for \n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \n# of all compounds will be generated. Enable this if the project \n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX = 5\n\n# In case all classes in a project start with a common prefix, all \n# classes will be put under the same header in the alphabetical index. \n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX = \n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \n# generate HTML output.\n\nGENERATE_HTML = $(GENERATE_HTML)\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard header.\n\nHTML_HEADER = \n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for \n# each generated HTML page. If it is left blank doxygen will generate a \n# standard footer.\n\nHTML_FOOTER = \n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \n# style sheet that is used by each HTML page. It can be used to \n# fine-tune the look of the HTML output. If the tag is left blank doxygen \n# will generate a default style sheet. Note that doxygen will try to copy \n# the style sheet file to the HTML output directory, so don't put your own \n# stylesheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET = \n\n# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \n# files or namespaces will be aligned in HTML using tables. If set to \n# NO a bullet list will be used.\n\nHTML_ALIGN_MEMBERS = YES\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files \n# will be generated that can be used as input for tools like the \n# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP = $(GENERATE_HTMLHELP)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \n# be used to specify the file name of the resulting .chm file. You \n# can add a path in front of the file if the result should not be \n# written to the html output directory.\n\nCHM_FILE = ../$(PROJECT).chm\n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \n# be used to specify the location (absolute path including file name) of \n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION = $(HHC_PATH)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \n# controls if a separate .chi index file is generated (YES) or that \n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI = $(GENERATE_CHI)\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \n# controls whether a binary table of contents is generated (YES) or a \n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members \n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND = NO\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \n# top of each HTML page. The value NO (the default) enables the index and \n# the value YES disables it.\n\nDISABLE_INDEX = NO\n\n# This tag can be used to set the number of enum values (range [1..20]) \n# that doxygen will group on one line in the generated HTML documentation.\n\nENUM_VALUES_PER_LINE = 4\n\n# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\n# generated containing a tree-like index structure (just like the one that \n# is generated for HTML Help). For this to work a browser that supports \n# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \n# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \n# probably better off using the HTML help feature.\n\nGENERATE_TREEVIEW = NO\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \n# used to set the initial width (in pixels) of the frame in which the tree \n# is shown.\n\nTREEVIEW_WIDTH = 250\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \n# generate Latex output.\n\nGENERATE_LATEX = $(GENERATE_LATEX)\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \n# invoked. If left blank `latex' will be used as the default command name.\n\nLATEX_CMD_NAME = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \n# generate index for LaTeX. If left blank `makeindex' will be used as the \n# default command name.\n\nMAKEINDEX_CMD_NAME = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \n# LaTeX documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_LATEX = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used \n# by the printer. Possible values are: a4, a4wide, letter, legal and \n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE = $(PAPER_SIZE)\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES = \n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \n# the generated latex document. The header should contain everything until \n# the first chapter. If it is left blank doxygen will generate a \n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER = \n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \n# is prepared for conversion to pdf (using ps2pdf). The pdf file will \n# contain links (just like the HTML output) instead of page references \n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS = NO\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \n# plain latex in the generated Makefile. Set this option to YES to get a \n# higher quality PDF documentation.\n\nUSE_PDFLATEX = $(GENERATE_PDF)\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode. \n# command to the generated LaTeX files. This will instruct LaTeX to keep \n# running if errors occur, instead of asking the user for help. \n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not \n# include the index chapters (such as File Index, Compound Index, etc.) \n# in the output.\n\nLATEX_HIDE_INDICES = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \n# The RTF output is optimized for Word 97 and may not look very pretty with \n# other RTF readers or editors.\n\nGENERATE_RTF = $(GENERATE_RTF)\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \n# RTF documents. This may be useful for small projects and may help to \n# save some trees in general.\n\nCOMPACT_RTF = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \n# will contain hyperlink fields. The RTF file will \n# contain links (just like the HTML output) instead of page references. \n# This makes the output suitable for online browsing using WORD or other \n# programs which support those fields. \n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's \n# config file, i.e. a series of assignments. You only have to provide \n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE = \n\n# Set optional variables used in the generation of an rtf document. \n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE = \n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \n# generate man pages\n\nGENERATE_MAN = $(GENERATE_MAN)\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT = man\n\n# The MAN_EXTENSION tag determines the extension that is added to \n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \n# then it will generate one additional man file for each entity \n# documented in the real man page(s). These additional files \n# only source the real man page, but without them the man command \n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will \n# generate an XML file that captures the structure of \n# the code including all documentation.\n\nGENERATE_XML = $(GENERATE_XML)\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. \n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_SCHEMA = \n\n# The XML_DTD tag can be used to specify an XML DTD, \n# which can be used by a validating XML parser to check the \n# syntax of the XML files.\n\nXML_DTD = \n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \n# dump the program listings (including syntax highlighting \n# and cross-referencing information) to the XML output. Note that \n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \n# generate an AutoGen Definitions (see autogen.sf.net) file \n# that captures the structure of the code including all \n# documentation. Note that this feature is still experimental \n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will \n# generate a Perl module file that captures the structure of \n# the code including all documentation. Note that this \n# feature is still experimental and incomplete at the \n# moment.\n\nGENERATE_PERLMOD = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \n# the necessary Makefile rules, Perl scripts and LaTeX code to be able \n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \n# nicely formatted so it can be parsed by a human reader.  This is useful \n# if you want to understand what is going on.  On the other hand, if this \n# tag is set to NO the size of the Perl module output will be much smaller \n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY = YES\n\n# The names of the make variables in the generated doxyrules.make file \n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \n# This is useful so different doxyrules.make files included by the same \n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor   \n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \n# evaluate all C-preprocessor directives found in the sources and include \n# files.\n\nENABLE_PREPROCESSING = YES\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \n# names in the source code. If set to NO (the default) only conditional \n# compilation will be performed. Macro expansion can be done in a controlled \n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \n# then the macro expansion is limited to the macros specified with the \n# PREDEFINED and EXPAND_AS_DEFINED tags.\n\nEXPAND_ONLY_PREDEF = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \n# in the INCLUDE_PATH (see below) will be search if a #include is found.\n\nSEARCH_INCLUDES = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that \n# contain include files that are not input files but should be processed by \n# the preprocessor.\n\nINCLUDE_PATH = \n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \n# patterns (like *.h and *.hpp) to filter out the header-files in the \n# directories. If left blank, the patterns specified with FILE_PATTERNS will \n# be used.\n\nINCLUDE_FILE_PATTERNS = \n\n# The PREDEFINED tag can be used to specify one or more macro names that \n# are defined before the preprocessor is started (similar to the -D option of \n# gcc). The argument of the tag is a list of macros of the form: name \n# or name=definition (no spaces). If the definition and the = are \n# omitted =1 is assumed. To prevent a macro definition from being \n# undefined via #undef or recursively expanded use the := operator \n# instead of the = operator.\n\nPREDEFINED = \n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \n# this tag can be used to specify a list of macro names that should be expanded. \n# The macro definition that is found in the sources will be used. \n# Use the PREDEFINED tag if you want to use a different macro definition.\n\nEXPAND_AS_DEFINED = \n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \n# doxygen's preprocessor will remove all function-like macros that are alone \n# on a line, have an all uppercase name, and do not end with a semicolon. Such \n# function macros are typically used for boiler-plate code, and will confuse \n# the parser if not removed.\n\nSKIP_FUNCTION_MACROS = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references   \n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles. \n# Optionally an initial location of the external documentation \n# can be added for each tagfile. The format of a tag file without \n# this location is as follows: \n#   TAGFILES = file1 file2 ... \n# Adding location for the tag files is done as follows: \n#   TAGFILES = file1=loc1 \"file2 = loc2\" ... \n# where \"loc1\" and \"loc2\" can be relative or absolute paths or \n# URLs. If a location is present for each tag, the installdox tool \n# does not have to be run to correct the links.\n# Note that each tag file must have a unique name\n# (where the name does NOT include the path)\n# If a tag file is not located in the directory in which doxygen \n# is run, you must also specify the path to the tagfile here.\n\nTAGFILES = \n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create \n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag\n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed \n# in the class index. If set to NO only the inherited external classes \n# will be listed.\n\nALLEXTERNALS = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \n# in the modules index. If set to NO, only the current project's groups will \n# be listed.\n\nEXTERNAL_GROUPS = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script \n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool   \n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base \n# or super classes. Setting the tag to NO turns the diagrams off. Note that \n# this option is superseded by the HAVE_DOT option below. This is only a \n# fallback. It is recommended to install and use dot, since it yields more \n# powerful graphs.\n\nCLASS_DIAGRAMS = YES\n\n# If set to YES, the inheritance and collaboration graphs will hide \n# inheritance and usage relations if the target is undocumented \n# or is not a class.\n\nHIDE_UNDOC_RELATIONS = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \n# available from the path. This tool is part of Graphviz, a graph visualization \n# toolkit from AT&T and Lucent Bell Labs. The other options in this section \n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT = $(HAVE_DOT)\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect inheritance relations. Setting this tag to YES will force the \n# the CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for each documented class showing the direct and \n# indirect implementation dependencies (inheritance, containment, and \n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen \n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \n# collaboration diagrams in a style similar to the OMG's Unified Modeling \n# Language.\n\nUML_LOOK = NO\n\n# If set to YES, the inheritance and collaboration graphs will show the \n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \n# tags are set to YES then doxygen will generate a graph for each documented \n# file showing the direct and indirect include dependencies of the file with \n# other documented files.\n\nINCLUDE_GRAPH = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \n# documented header file showing the documented files that directly or \n# indirectly include this file.\n\nINCLUDED_BY_GRAPH = YES\n\n# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a call dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable call graphs for selected \n# functions only using the \\callgraph command.\n\nCALL_GRAPH = NO\n\n# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will \n# generate a caller dependency graph for every global function or class method. \n# Note that enabling this option will significantly increase the time of a run. \n# So in most cases it will be better to enable caller graphs for selected \n# functions only using the \\callergraph command.\n\nCALLER_GRAPH = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \n# will graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY = YES\n\n# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \n# then doxygen will show the dependencies a directory has on other directories \n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \n# generated by dot. Possible values are png, jpg, or gif\n# If left blank png will be used.\n\nDOT_IMAGE_FORMAT = png\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be \n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH = $(DOT_PATH)\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that \n# contain dot files that are included in the documentation (see the \n# \\dotfile command).\n\nDOTFILE_DIRS = \n\n# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_WIDTH = 1024\n\n# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \n# (in pixels) of the graphs generated by dot. If a graph becomes larger than \n# this value, doxygen will try to truncate the graph, so that it fits within \n# the specified constraint. Beware that most browsers cannot cope with very \n# large images.\n\nMAX_DOT_GRAPH_HEIGHT = 1024\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \n# graphs generated by dot. A depth value of 3 means that only nodes reachable \n# from the root by following a path via at most 3 edges will be shown. Nodes \n# that lay further from the root node will be omitted. Note that setting this \n# option to 1 or 2 may greatly reduce the computation time needed for large \n# code bases. Also note that a graph may be further truncated if the graph's \n# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH \n# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), \n# the graph is not depth-constrained.\n\nMAX_DOT_GRAPH_DEPTH = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent \n# background. This is disabled by default, which results in a white background. \n# Warning: Depending on the platform used, enabling this option may lead to \n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to \n# read).\n\nDOT_TRANSPARENT = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output \n# files in one run (i.e. multiple -o and -T options on the command line). This \n# makes dot run faster, but since only newer versions of dot (>1.8.10) \n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \n# generate a legend page explaining the meaning of the various boxes and \n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \n# remove the intermediate dot files that are used to generate \n# the various graphs.\n\nDOT_CLEANUP = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to the search engine   \n#---------------------------------------------------------------------------\n\n# The SEARCHENGINE tag specifies whether or not a search engine should be \n# used. If set to NO the values of all tags below this one will be ignored.\n\nSEARCHENGINE = NO\n"
  },
  {
    "path": "src/recipes/queue/src/c/configure.ac",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ(2.59)\n\nAC_INIT([zooqueue], [3.2.0])\n\nAC_CONFIG_SRCDIR([include/zoo_queue.h])\n\nPACKAGE=zooqueue\nVERSION=1.0\n\nAC_SUBST(PACKAGE)\nAC_SUBST(VERSION)\n\nBUILD_PATH=\"`pwd`\"\n\n# Checks for programs.\nAC_LANG_CPLUSPLUS\n\nAM_INIT_AUTOMAKE([-Wall foreign])\n# Checks for libraries.\n\n#initialize Doxygen support\nDX_HTML_FEATURE(ON)\nDX_CHM_FEATURE(OFF)\nDX_CHI_FEATURE(OFF)\nDX_MAN_FEATURE(OFF)\nDX_RTF_FEATURE(OFF)\nDX_XML_FEATURE(OFF)\nDX_PDF_FEATURE(OFF)\nDX_PS_FEATURE(OFF)\nDX_INIT_DOXYGEN([zookeeper-queues],[c-doc.Doxyfile],[docs])\n\n  \nZOOKEEPER_PATH=${BUILD_PATH}/../../../../../src/c\nZOOKEEPER_LD=-L${BUILD_PATH}/../../../../../src/c\\ -lzookeeper_mt\n\nAC_SUBST(ZOOKEEPER_PATH)\nAC_SUBST(ZOOKEEPER_LD)\n\n# Checks for header files.\nAC_HEADER_DIRENT\nAC_HEADER_STDC\nAC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h])\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_HEADER_STDBOOL\nAC_C_CONST\nAC_TYPE_UID_T\nAC_C_INLINE\nAC_TYPE_OFF_T\nAC_TYPE_SIZE_T\nAC_STRUCT_ST_BLOCKS\nAC_HEADER_TIME\nAC_C_VOLATILE\nAC_PROG_CC\nAC_PROG_LIBTOOL\n#check for cppunit \nAM_PATH_CPPUNIT(1.10.2)\n# Checks for library functions.\nAC_FUNC_UTIME_NULL\nAC_CHECK_FUNCS([gettimeofday memset mkdir rmdir strdup strerror strstr strtol strtoul strtoull utime])\n\nAC_CONFIG_FILES([Makefile])\nAC_OUTPUT\nAC_C_VOLATILE\n"
  },
  {
    "path": "src/recipes/queue/src/c/include/zoo_queue.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ZOOKEEPER_QUEUE_H_\n#define ZOOKEEPER_QUEUE_H_\n\n#include <zookeeper.h>\n#include <pthread.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/** \n * \\file zoo_queue.h\n * \\brief zookeeper recipe for queues.\n */\n\n\nstruct zkr_queue {\n    zhandle_t *zh;\n    char *path;\n    struct ACL_vector *acl;\n    pthread_mutex_t pmutex;\n    char *node_name;\n    int node_name_length;\n    char *cached_create_path;\n};\n\ntypedef struct zkr_queue zkr_queue_t;\n\n\n/**\n * \\brief initializes a zookeeper queue\n *\n * this method instantiates a zookeeper queue\n * \\param queue the zookeeper queue to initialize\n * \\param zh the zookeeper handle to use\n * \\param path the path in zookeeper to use for the queue \n * \\param acl the acl to use in zookeeper.\n * \\return return 0 if successful.  \n */\nZOOAPI int zkr_queue_init(zkr_queue_t *queue, zhandle_t* zh, char* path, struct ACL_vector *acl);\n\n/**\n * \\brief adds an element to a zookeeper queue\n *\n * this method adds an element to the back of a zookeeper queue.\n * \\param queue the zookeeper queue to add the element to\n * \\param data a pointer to a data buffer\n * \\param buffer_len the length of the buffer\n * \\return returns 0 (ZOK) if successful, otherwise returns a zookeeper error code.\n */\nZOOAPI int zkr_queue_offer(zkr_queue_t *queue, const char *data, int buffer_len);\n\n/**\n * \\brief returns the head of a zookeeper queue \n *\n * this method returns the head of a zookeeper queue without removing it.\n * \\param queue the zookeeper queue to add the element to\n * \\param buffer a pointer to a data buffer\n * \\param buffer_len a pointer to the length of the buffer\n * \\return returns 0 (ZOK) and sets *buffer_len to the length of data written if successful (-1 if the queue is empty). Otherwise it will set *buffer_len to -1 and return a zookeeper error code. \n */\nZOOAPI int zkr_queue_element(zkr_queue_t *queue, char *buffer, int *buffer_len);\n\n/**\n * \\brief returns the head of a zookeeper queue \n *\n * this method returns the head of a zookeeper queue without removing it.\n * \\param queue the zookeeper queue to get the head of\n * \\param buffer a pointer to a data buffer\n * \\param buffer_len a pointer to the length of the buffer\n * \\return returns 0 (ZOK) and sets *buffer_len to the length of data written if successful (-1 if the queue is empty). Otherwise it will set *buffer_len to -1 and return a zookeeper error code. \n */\nZOOAPI int zkr_queue_remove(zkr_queue_t *queue, char *buffer, int *buffer_len);\n\n/**\n * \\brief removes and returns the head of a zookeeper queue, blocks if necessary \n *\n * this method returns the head of a zookeeper queue without removing it.\n * \\param queue the zookeeper queue to remove and return the head of \n * \\param buffer a pointer to a data buffer\n * \\param buffer_len a pointer to the length of the buffer\n * \\return returns 0 (ZOK) and sets *buffer_len to the length of data written if successful. Otherwise it will set *buffer_len to -1 and return a zookeeper error code. \n */\nZOOAPI int zkr_queue_take(zkr_queue_t *queue, char *buffer, int *buffer_len);\n\n/**\n * \\brief destroys a zookeeper queue structure \n *\n * this destroys a zookeeper queue structure, this is only a local operation and will not affect\n * the state of the queue on the zookeeper server.\n * \\param queue the zookeeper queue to destroy\n */\nvoid zkr_queue_destroy(zkr_queue_t *queue);\n\n\n#ifdef __cplusplus\n}\n#endif\n#endif  //ZOOKEEPER_QUEUE_H_\n"
  },
  {
    "path": "src/recipes/queue/src/c/src/zoo_queue.c",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifdef DLL_EXPORT\n#define USE_STATIC_LIB\n#endif\n\n#if defined(__CYGWIN__)\n#define USE_IPV6\n#endif\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <zookeeper_log.h>\n#include <time.h>\n#include <sys/time.h>\n#include <sys/socket.h>\n#include <limits.h>\n#include <zoo_queue.h>\n#include <stdbool.h>\n#ifdef HAVE_SYS_UTSNAME_H\n#include <sys/utsname.h>\n#endif\n\n#ifdef HAVE_GETPWUID_R\n#include <pwd.h>\n#endif\n\n#define IF_DEBUG(x) if (logLevel==ZOO_LOG_LEVEL_DEBUG) {x;}\n\n\nstatic void free_String_vector(struct String_vector *v) {\n    if (v->data) {\n        int32_t i;\n        for (i=0; i<v->count; i++) {\n            free(v->data[i]);\n        }\n        free(v->data);\n        v->data = 0;\n    }\n}\n\n\nstatic int vstrcmp(const void* str1, const void* str2) {\n    const char **a = (const char**)str1;\n    const char **b = (const char**) str2;\n    return strcmp(*a, *b); \n}\n\nstatic void sort_children(struct String_vector *vector) {\n    qsort( vector->data, vector->count, sizeof(char*), &vstrcmp);\n}\n\n\nstatic void concat_path_nodename_n(char *buffer, int len, const char *path, const char *node_name){\n    snprintf(buffer, len, \"%s/%s\", path, node_name); \n}\n\nstatic char *concat_path_nodename(const char *path, const char *node_name){\n    int node_path_length = strlen(path) + 1+ strlen(node_name) +1;\n    char *node_path = (char *) malloc(node_path_length * sizeof(char));\n    concat_path_nodename_n(node_path, node_path_length, path, node_name);\n    return node_path;\n}  \n\n\nstatic void zkr_queue_cache_create_path(zkr_queue_t *queue){\n    if(queue->cached_create_path != NULL){\n        free(queue->cached_create_path);\n    }\n    queue->cached_create_path = concat_path_nodename(queue->path, queue->node_name);\n}\n\nZOOAPI int zkr_queue_init(zkr_queue_t *queue, zhandle_t* zh, char* path, struct ACL_vector *acl){\n    queue->zh = zh;\n    queue->path = path;\n    queue->node_name = \"qn-\";\n    queue->node_name_length = strlen(queue->node_name);\n    queue->cached_create_path = NULL;\n    queue->acl = acl;\n    pthread_mutex_init(&(queue->pmutex), NULL);\n    zkr_queue_cache_create_path(queue);\n    return 0;\n}\n\nstatic ZOOAPI int create_queue_root(zkr_queue_t *queue){\n    return zoo_create(queue->zh, queue->path, NULL, 0, queue->acl, 0, NULL, 0 );\n}\n\nstatic int valid_child_name(zkr_queue_t *queue, const char *child_name){\n    return strncmp(queue->node_name, child_name, queue->node_name_length);\n}\n\nZOOAPI int zkr_queue_offer(zkr_queue_t *queue, const char *data, int buffer_len){\n    for(;;){\n        int rc = zoo_create(queue->zh, queue->cached_create_path, data, buffer_len, queue->acl, ZOO_SEQUENCE, NULL, 0 );\n        switch(rc){\n            int create_root_rc;\n        case ZNONODE:\n            create_root_rc = create_queue_root(queue);\n            switch(create_root_rc){\n            case ZNODEEXISTS:\n            case ZOK:\n                break;\n            default:\n                return create_root_rc; \n            }\n            break;\n        default:\n            return rc;\n        }\n    }\n}\n\n\nZOOAPI int zkr_queue_element(zkr_queue_t *queue, char *buffer, int *buffer_len){\n    int path_length = strlen(queue->path);\n    for(;;){\n        struct String_vector stvector;\n        struct String_vector *vector = &stvector;\n        /*Get sorted children*/\n        int get_children_rc = zoo_get_children(queue->zh, queue->path, 0, vector);\n        switch(get_children_rc){\n        case ZOK:\n            break;\n        case ZNONODE:\n            *buffer_len = -1;\n            return ZOK;\n        default:\n            return get_children_rc;\n        }\n        if(stvector.count == 0){\n            *buffer_len = -1;\n            return ZOK;\n        }\n\n        sort_children(vector);\n        /*try all*/\n        int i;\n        for(i=0; i < stvector.count; i++){\n            char *child_name = stvector.data[i];\n            int child_path_length = path_length + 1 + strlen(child_name) +1; \n            char child_path[child_path_length];\n            concat_path_nodename_n(child_path, child_path_length, queue->path, child_name);\n            int get_rc = zoo_get(queue->zh, child_path, 0, buffer, buffer_len, NULL);\n            switch(get_rc){\n            case ZOK:\n                free_String_vector(vector);\n                return ZOK;\n            case ZNONODE:\n                break;\n            default:\n                free_String_vector(vector);\n                return get_rc;\n            }\n        }\n    \n        free_String_vector(vector);\n    }\n}\n\nZOOAPI int zkr_queue_remove(zkr_queue_t *queue, char *buffer, int *buffer_len){\n    int path_length = strlen(queue->path);\n    for(;;){\n        struct String_vector stvector;\n        struct String_vector *vector = &stvector;\n        /*Get sorted children*/\n        int get_children_rc = zoo_get_children(queue->zh, queue->path, 0, &stvector);\n        switch(get_children_rc){\n        case ZOK:\n            break;\n        case ZNONODE:\n            *buffer_len = -1;\n            return ZOK;\n            \n        default:\n            *buffer_len = -1;\n            return get_children_rc;\n        }\n        if(stvector.count == 0){\n            *buffer_len = -1;\n            return ZOK;\n        }\n\n        sort_children(vector);\n        /*try all*/\n        int i;\n        for( i=0; i < stvector.count; i++){\n            char *child_name = stvector.data[i];\n            int child_path_length = path_length + 1 + strlen(child_name) +1; \n            char child_path[child_path_length];\n            concat_path_nodename_n(child_path, child_path_length, queue->path, child_name);\n            int get_rc = zoo_get(queue->zh, child_path, 0, buffer, buffer_len, NULL);\n            switch(get_rc){\n                int delete_rc;\n            case ZOK:\n                delete_rc = zoo_delete(queue->zh, child_path, -1);\n                switch(delete_rc){\n                case ZOK:\n                    free_String_vector(vector);\n                    return delete_rc;\n                case ZNONODE:\n                    break;\n                default:\n                    free_String_vector(vector);\n                    *buffer_len = -1;\n                    return delete_rc;\n                }\n                break;\n            case ZNONODE:\n                break;\n            default:\n                free_String_vector(vector);\n                *buffer_len = -1;\n                return get_rc;\n            }\n        }\n        free_String_vector(vector);\n    }\n}\n\n/**\n * The take_latch structure roughly emulates a Java CountdownLatch with 1 as the initial value.\n * It is meant to be used by a setter thread and a waiter thread.\n * \n * This latch is specialized to be used with the queue, all latches created for the same queue structure will use the same mutex.\n *\n * The setter thread at some point will call take_latch_setter_trigger_latch() on the thread.\n *\n * The waiter thread creates the latch and at some point either calls take_latch_waiter_await()s or take_latch_waiter_mark_unneeded()s it.\n * The await function will return after the setter thread has triggered the latch.\n * The mark unneeded function will return immediately and avoid some unneeded initialization.\n *\n * Whichever thread is last to call their required function disposes of the latch.\n *\n * The latch may disposed if no threads will call the waiting, marking, or triggering functions using take_latch_destroy_syncrhonized().\n */\n\nstruct take_latch {\n    enum take_state {take_init, take_waiting, take_triggered, take_not_needed} state;\n    pthread_cond_t latch_condition;\n    zkr_queue_t *queue;\n};\n\n\ntypedef struct take_latch take_latch_t;  \n\n\nstatic void take_latch_init( take_latch_t *latch, zkr_queue_t *queue){\n    pthread_mutex_t *mutex = &(queue->pmutex);\n    pthread_mutex_lock(mutex);\n    latch->state = take_init;\n    latch->queue = queue;\n    pthread_mutex_unlock(mutex);\n}\n\nstatic take_latch_t *create_take_latch(zkr_queue_t *queue){\n    take_latch_t *new_take_latch = (take_latch_t *) malloc(sizeof(take_latch_t));\n    take_latch_init(new_take_latch, queue);\n    return new_take_latch;\n}\n\n\n//Only call this when you own the mutex\nstatic void take_latch_destroy_unsafe(take_latch_t *latch){\n    if(latch->state == take_waiting){\n        pthread_cond_destroy(&(latch->latch_condition));\n    }\n    free(latch);\n}\n\nstatic void take_latch_destroy_synchronized(take_latch_t *latch){\n    pthread_mutex_t *mutex = &(latch->queue->pmutex);\n    pthread_mutex_lock(mutex);\n    take_latch_destroy_unsafe(latch);\n    pthread_mutex_unlock(mutex);\n}\n\nstatic void take_latch_setter_trigger_latch(take_latch_t *latch){\n    pthread_mutex_t *mutex = &(latch->queue->pmutex);\n    pthread_mutex_lock(mutex);\n    switch(latch->state){\n    case take_init:\n        latch->state = take_triggered;\n        break;\n    case take_not_needed:\n        take_latch_destroy_unsafe(latch);\n        break;\n    case take_triggered:\n        LOG_DEBUG((\"Error! Latch was triggered twice.\"));\n        break;\n    case take_waiting:\n        pthread_cond_signal(&(latch->latch_condition));\n        break;\n    }\n    pthread_mutex_unlock(mutex);\n}\n\nstatic void take_latch_waiter_await(take_latch_t *latch){\n    pthread_mutex_t *mutex = &(latch->queue->pmutex);\n    pthread_mutex_lock(mutex);\n    switch(latch->state){\n    case take_init:\n        pthread_cond_init(&(latch->latch_condition),NULL);\n        latch->state = take_waiting;\n        pthread_cond_wait(&(latch->latch_condition),mutex);\n        take_latch_destroy_unsafe(latch);\n        break;\n    case take_waiting:\n        LOG_DEBUG((\"Error! Called await twice.\"));\n        break;\n    case take_not_needed:\n        LOG_DEBUG((\"Error! Waiting after marking not needed.\"));\n        break;\n    case take_triggered:\n        take_latch_destroy_unsafe(latch);\n        break;\n    }\n    pthread_mutex_unlock(mutex);\n}\n\nstatic void take_latch_waiter_mark_unneeded(take_latch_t *latch){\n    pthread_mutex_t *mutex = &(latch->queue->pmutex);\n    pthread_mutex_lock(mutex);\n    switch(latch->state){\n    case take_init:\n        latch->state = take_not_needed;\n        break;\n    case take_waiting:\n        LOG_DEBUG((\"Error! Can't mark unneeded after waiting.\"));\n        break;\n    case take_not_needed:\n        LOG_DEBUG((\"Marked unneeded twice.\"));\n        break;\n    case take_triggered:\n        take_latch_destroy_unsafe(latch);\n        break;\n    }\n    pthread_mutex_unlock(mutex);\n}\n\nstatic void take_watcher(zhandle_t *zh, int type, int state, const char *path, void *watcherCtx){\n    take_latch_t *latch = (take_latch_t *) watcherCtx;\n    take_latch_setter_trigger_latch(latch);\n}\n\n\n\nZOOAPI int zkr_queue_take(zkr_queue_t *queue, char *buffer, int *buffer_len){\n    int path_length = strlen(queue->path);\ntake_attempt:    \n    for(;;){\n        struct String_vector stvector;\n        struct String_vector *vector = &stvector;\n        /*Get sorted children*/\n        take_latch_t *take_latch = create_take_latch(queue);\n        int get_children_rc = zoo_wget_children(queue->zh, queue->path, take_watcher, take_latch, &stvector);\n        switch(get_children_rc){\n        case ZOK:\n            break;\n            int create_queue_rc;\n        case ZNONODE:\n            take_latch_destroy_synchronized(take_latch);\n            create_queue_rc = create_queue_root(queue);\n            switch(create_queue_rc){\n            case ZNODEEXISTS:\n            case ZOK:\n                goto take_attempt;\n            default:\n                *buffer_len = -1;\n                return create_queue_rc;\n            }\n        default:\n            take_latch_destroy_synchronized(take_latch);\n            *buffer_len = -1;\n            return get_children_rc;\n        }\n        if(stvector.count == 0){\n            take_latch_waiter_await(take_latch);\n        }else{\n            take_latch_waiter_mark_unneeded(take_latch);\n        }\n\n        sort_children(vector);\n        /*try all*/\n        int i;\n        for( i=0; i < stvector.count; i++){\n            char *child_name = stvector.data[i];\n            int child_path_length = path_length + 1 + strlen(child_name) +1; \n            char child_path[child_path_length];\n            concat_path_nodename_n(child_path, child_path_length, queue->path, child_name);\n            int get_rc = zoo_get(queue->zh, child_path, 0, buffer, buffer_len, NULL);\n            switch(get_rc){\n                int delete_rc;\n            case ZOK:\n                delete_rc = zoo_delete(queue->zh, child_path, -1);\n                switch(delete_rc){\n                case ZOK:\n                    free_String_vector(vector);\n                    return delete_rc;\n                case ZNONODE:\n                    break;\n                default:\n                    free_String_vector(vector);\n                    *buffer_len = -1;\n                    return delete_rc;\n                }\n                break;\n            case ZNONODE:\n                break;\n            default:\n                free_String_vector(vector);\n                *buffer_len = -1;\n                return get_rc;\n            }\n        }\n        free_String_vector(vector);\n    }\n}\n\nZOOAPI void zkr_queue_destroy(zkr_queue_t *queue){\n    pthread_mutex_destroy(&(queue->pmutex));\n    if(queue->cached_create_path != NULL){\n        free(queue->cached_create_path);\n    }\n}\n"
  },
  {
    "path": "src/recipes/queue/src/c/tests/TestClient.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cppunit/extensions/HelperMacros.h>\n\n#include <pthread.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <sys/select.h>\n#include <cppunit/TestAssert.h>\n\n\nusing namespace std;\n\n#include <cstring>\n#include <list>\n\n#include <zookeeper.h>\n#include <zoo_queue.h>\n\nstatic void yield(zhandle_t *zh, int i)\n{\n    sleep(i);\n}\n\ntypedef struct evt {\n    string path;\n    int type;\n} evt_t;\n\ntypedef struct watchCtx {\nprivate:\n    list<evt_t> events;\npublic:\n    bool connected;\n    zhandle_t *zh;\n    \n    watchCtx() {\n        connected = false;\n        zh = 0;\n    }\n    ~watchCtx() {\n        if (zh) {\n            zookeeper_close(zh);\n            zh = 0;\n        }\n    }\n\n    evt_t getEvent() {\n        evt_t evt;\n        evt = events.front();\n        events.pop_front();\n        return evt;\n    }\n\n    int countEvents() {\n        int count;\n        count = events.size();\n        return count;\n    }\n\n    void putEvent(evt_t evt) {\n        events.push_back(evt);\n    }\n\n    bool waitForConnected(zhandle_t *zh) {\n        time_t expires = time(0) + 10;\n        while(!connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return connected;\n    }\n    bool waitForDisconnected(zhandle_t *zh) {\n        time_t expires = time(0) + 15;\n        while(connected && time(0) < expires) {\n            yield(zh, 1);\n        }\n        return !connected;\n    }\n} watchctx_t; \n\nextern \"C\" {\n    \n    const char *thread_test_string=\"Hello World!\";\n   \n    void *offer_thread_shared_queue(void *queue_handle){\n        zkr_queue_t *queue = (zkr_queue_t *) queue_handle;\n\n        int test_string_buffer_length = strlen(thread_test_string) + 1;\n        int offer_rc = zkr_queue_offer(queue, thread_test_string, test_string_buffer_length);\n        pthread_exit(NULL);\n    }\n    \n    void *take_thread_shared_queue(void *queue_handle){\n        zkr_queue_t *queue = (zkr_queue_t *) queue_handle;\n\n        int test_string_buffer_length = strlen(thread_test_string) + 1;\n        int receive_buffer_capacity = test_string_buffer_length;\n        int receive_buffer_length = receive_buffer_capacity;\n        char *receive_buffer = (char *) malloc(sizeof(char) * receive_buffer_capacity);\n\n        int remove_rc = zkr_queue_take(queue, receive_buffer, &receive_buffer_length);\n        switch(remove_rc){\n        case ZOK:\n            pthread_exit(receive_buffer);\n        default:\n            free(receive_buffer);\n            pthread_exit(NULL);\n        }\n    }\n    \n    int valid_test_string(void *result){\n        char *result_string = (char *) result;\n        return !strncmp(result_string, thread_test_string, strlen(thread_test_string));\n    }\n}\n\nclass Zookeeper_queuetest : public CPPUNIT_NS::TestFixture\n{\n    CPPUNIT_TEST_SUITE(Zookeeper_queuetest);\n    CPPUNIT_TEST(testInitDestroy);\n    CPPUNIT_TEST(testOffer1);\n    CPPUNIT_TEST(testOfferRemove1);\n    CPPUNIT_TEST(testOfferRemove2);\n    CPPUNIT_TEST(testOfferRemove3);\n    CPPUNIT_TEST(testOfferRemove4);\n    CPPUNIT_TEST(testOfferRemove5);\n    CPPUNIT_TEST(testOfferRemove6);\n    CPPUNIT_TEST(testOfferTake1);\n    CPPUNIT_TEST(testOfferTake2);\n    CPPUNIT_TEST(testOfferTake3);\n    CPPUNIT_TEST(testOfferTake4);\n    CPPUNIT_TEST(testOfferTake5);\n    CPPUNIT_TEST(testOfferTake6);\n    CPPUNIT_TEST_SUITE_END();\n\n    static void watcher(zhandle_t *, int type, int state, const char *path,void*v){\n        watchctx_t *ctx = (watchctx_t*)v;\n\n        if (state == ZOO_CONNECTED_STATE) {\n            ctx->connected = true;\n        } else {\n            ctx->connected = false;\n        }\n        if (type != ZOO_SESSION_EVENT) {\n            evt_t evt;\n            evt.path = path;\n            evt.type = type;\n            ctx->putEvent(evt);\n        }\n    }\n\n    static const char hostPorts[];\n\n    const char *getHostPorts() {\n        return hostPorts;\n    }\n\n    zhandle_t *createClient(watchctx_t *ctx) {\n        zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0,\n                                       ctx, 0);\n        ctx->zh = zk;\n        sleep(1);\n        return zk;\n    }\n    \npublic:\n\n#define ZKSERVER_CMD \"./tests/zkServer.sh\"\n\n    void setUp()\n        {\n            char cmd[1024];\n            sprintf(cmd, \"%s startClean %s\", ZKSERVER_CMD, getHostPorts());\n            CPPUNIT_ASSERT(system(cmd) == 0);\n        }\n    \n\n    void startServer() {\n        char cmd[1024];\n        sprintf(cmd, \"%s start %s\", ZKSERVER_CMD, getHostPorts());\n        CPPUNIT_ASSERT(system(cmd) == 0);\n    }\n\n    void stopServer() {\n        tearDown();\n    }\n\n    void tearDown()\n        {\n            char cmd[1024];\n            sprintf(cmd, \"%s stop %s\", ZKSERVER_CMD, getHostPorts());\n            CPPUNIT_ASSERT(system(cmd) == 0);\n        }\n\n    void initializeQueuesAndHandles(int num_clients, zhandle_t *zoohandles[], \n                                    watchctx_t ctxs[], zkr_queue_t queues[], char *path){\n        int i;\n        for(i=0; i< num_clients; i++){\n            zoohandles[i] = createClient(&ctxs[i]);\n            zkr_queue_init(&queues[i], zoohandles[i], path, &ZOO_OPEN_ACL_UNSAFE);\n        }\n    }\n\n    void cleanUpQueues(int num_clients, zkr_queue_t queues[]){\n        int i;\n        for(i=0; i < num_clients; i++){\n            zkr_queue_destroy(&queues[i]);\n        }\n    }\n\n    void testInitDestroy(){\n        int num_clients = 1;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n        char *path= (char *)\"/testInitDestroy\";\n\n        int i;\n        for(i=0; i< num_clients; i++){\n            zoohandles[i] = createClient(&ctxs[i]);\n            zkr_queue_init(&queues[i], zoohandles[i], path, &ZOO_OPEN_ACL_UNSAFE);\n        }\n    \n        for(i=0; i< num_clients; i++){\n            zkr_queue_destroy(&queues[i]);\n        }\n    \n    }\n\n    void testOffer1(){\n        int num_clients = 1;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n        char *path= (char *)\"/testOffer1\";\n\n        initializeQueuesAndHandles(num_clients, zoohandles, ctxs, queues, path);\n\n        const char *test_string=\"Hello World!\";\n        int test_string_length = strlen(test_string);\n        int test_string_buffer_length = test_string_length + 1;\n        char buffer[test_string_buffer_length];\n\n        int offer_rc = zkr_queue_offer(&queues[0], test_string, test_string_buffer_length);\n        CPPUNIT_ASSERT(offer_rc == ZOK);\n\n        int removed_element_buffer_length = test_string_buffer_length;\n        int remove_rc = zkr_queue_remove(&queues[0], buffer, &removed_element_buffer_length);\n        CPPUNIT_ASSERT(remove_rc == ZOK);\n        CPPUNIT_ASSERT(removed_element_buffer_length == test_string_buffer_length);\n        CPPUNIT_ASSERT(strncmp(test_string,buffer,test_string_length)==0);\n\n        cleanUpQueues(num_clients,queues);\n    }\n\n    void create_n_remove_m(char *path, int n, int m){\n        int num_clients = 2;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n    \n        initializeQueuesAndHandles(num_clients, zoohandles, ctxs, queues, path);\n\n        int i;\n        int max_digits = sizeof(int)*3;\n        const char *test_string = \"Hello World!\";\n        int buffer_length = strlen(test_string) + max_digits + 1;\n        char correct_buffer[buffer_length];\n        char receive_buffer[buffer_length];\n\n        for(i = 0; i < n; i++){\n            snprintf(correct_buffer, buffer_length, \"%s%d\", test_string,i);\n            int offer_rc = zkr_queue_offer(&queues[0], correct_buffer, buffer_length);\n            CPPUNIT_ASSERT(offer_rc == ZOK);\n        }\n        printf(\"Offers\\n\");\n        for(i=0; i<m ;i++){\n            snprintf(correct_buffer, buffer_length, \"%s%d\", test_string,i);\n            int receive_buffer_length=buffer_length;\n            int remove_rc = zkr_queue_remove(&queues[1], receive_buffer, &receive_buffer_length);\n            CPPUNIT_ASSERT(remove_rc == ZOK);\n            if(i >=n){\n                CPPUNIT_ASSERT(receive_buffer_length == -1);\n            }else{\n                CPPUNIT_ASSERT(strncmp(correct_buffer,receive_buffer, buffer_length)==0);\n            }\n        }\n\n        cleanUpQueues(num_clients,queues);\n    }\n\n    void testOfferRemove1(){\n        create_n_remove_m((char *)\"/testOfferRemove1\", 0,1);\n    }\n\n    void testOfferRemove2(){\n        create_n_remove_m((char *)\"/testOfferRemove2\", 1,1);\n    }\n\n    void testOfferRemove3(){\n        create_n_remove_m((char *)\"/testOfferRemove3\", 10,1);\n    }\n    \n    void testOfferRemove4(){\n        create_n_remove_m((char *)\"/testOfferRemove4\", 10,10);\n    }\n\n    void testOfferRemove5(){\n        create_n_remove_m((char *)\"/testOfferRemove5\", 10,5);\n    }\n\n    void testOfferRemove6(){\n        create_n_remove_m((char *)\"/testOfferRemove6\", 10,11);\n    }\n\n    void create_n_take_m(char *path, int n, int m){\n        CPPUNIT_ASSERT(m<=n);\n        int num_clients = 2;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n    \n        initializeQueuesAndHandles(num_clients, zoohandles, ctxs, queues, path);\n\n        int i;\n        int max_digits = sizeof(int)*3;\n        const char *test_string = \"Hello World!\";\n        int buffer_length = strlen(test_string) + max_digits + 1;\n        char correct_buffer[buffer_length];\n        char receive_buffer[buffer_length];\n\n        for(i = 0; i < n; i++){\n            snprintf(correct_buffer, buffer_length, \"%s%d\", test_string,i);\n            int offer_rc = zkr_queue_offer(&queues[0], correct_buffer, buffer_length);\n            CPPUNIT_ASSERT(offer_rc == ZOK);\n        }\n        printf(\"Offers\\n\");\n        for(i=0; i<m ;i++){\n            snprintf(correct_buffer, buffer_length, \"%s%d\", test_string,i);\n            int receive_buffer_length=buffer_length;\n            int remove_rc = zkr_queue_take(&queues[1], receive_buffer, &receive_buffer_length);\n            CPPUNIT_ASSERT(remove_rc == ZOK);\n            if(i >=n){\n                CPPUNIT_ASSERT(receive_buffer_length == -1);\n            }else{\n                CPPUNIT_ASSERT(strncmp(correct_buffer,receive_buffer, buffer_length)==0);\n            }\n        }\n\n        cleanUpQueues(num_clients,queues);\n    }\n\n    void testOfferTake1(){\n        create_n_take_m((char *)\"/testOfferTake1\", 2,1);\n    }\n\n    void testOfferTake2(){\n        create_n_take_m((char *)\"/testOfferTake2\", 1,1);\n    }\n\n    void testOfferTake3(){\n        create_n_take_m((char *)\"/testOfferTake3\", 10,1);\n    }\n    \n    void testOfferTake4(){\n        create_n_take_m((char *)\"/testOfferTake4\", 10,10);\n    }\n\n    void testOfferTake5(){\n        create_n_take_m((char *)\"/testOfferTake5\", 10,5);\n    }\n\n    void testOfferTake6(){\n        create_n_take_m((char *)\"/testOfferTake6\", 12,11);\n    }\n\n    void testTakeThreaded(){\n        int num_clients = 1;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n        char *path=(char *)\"/testTakeThreaded\";\n    \n        initializeQueuesAndHandles(num_clients, zoohandles, ctxs, queues, path);\n        pthread_t take_thread;\n\n        pthread_create(&take_thread, NULL, take_thread_shared_queue, (void *) &queues[0]);\n\n        usleep(1000);\n\n        pthread_t offer_thread;\n        pthread_create(&offer_thread, NULL, offer_thread_shared_queue, (void *) &queues[0]);\n        pthread_join(offer_thread, NULL);\n\n        void *take_thread_result;\n        pthread_join(take_thread, &take_thread_result);\n        CPPUNIT_ASSERT(take_thread_result != NULL);\n        CPPUNIT_ASSERT(valid_test_string(take_thread_result));\n\n        cleanUpQueues(num_clients,queues);\n    }\n\n    void testTakeThreaded2(){\n        int num_clients = 1;\n        watchctx_t ctxs[num_clients];\n        zhandle_t *zoohandles[num_clients];\n        zkr_queue_t queues[num_clients];\n        char *path=(char *)\"/testTakeThreaded2\";\n    \n        initializeQueuesAndHandles(num_clients, zoohandles, ctxs, queues, path);\n\n        int take_attempts;\n        int num_take_attempts = 2;\n        for(take_attempts=0; take_attempts < num_take_attempts; take_attempts++){ \n            pthread_t take_thread;\n    \n            pthread_create(&take_thread, NULL, take_thread_shared_queue, (void *) &queues[0]);\n    \n            usleep(1000);\n    \n            pthread_t offer_thread;\n            pthread_create(&offer_thread, NULL, offer_thread_shared_queue, (void *) &queues[0]);\n            pthread_join(offer_thread, NULL);\n    \n            void *take_thread_result;\n            pthread_join(take_thread, &take_thread_result);\n            CPPUNIT_ASSERT(take_thread_result != NULL);\n            CPPUNIT_ASSERT(valid_test_string(take_thread_result));\n\n        }\n        cleanUpQueues(num_clients,queues);\n    }\n};\n\nconst char Zookeeper_queuetest::hostPorts[] = \"127.0.0.1:22181\";\nCPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_queuetest);\n"
  },
  {
    "path": "src/recipes/queue/src/c/tests/TestDriver.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <string>\n#include <cppunit/TestRunner.h>\n#include <cppunit/CompilerOutputter.h>\n#include <cppunit/TestResult.h>\n#include <cppunit/TestResultCollector.h>\n#include <cppunit/TextTestProgressListener.h>\n#include <cppunit/BriefTestProgressListener.h>\n#include <cppunit/extensions/TestFactoryRegistry.h>\n#include <stdexcept>\n#include <cppunit/Exception.h>\n#include <cppunit/TestFailure.h>\n#include <cppunit/XmlOutputter.h>\n#include <fstream>\n\n#include \"Util.h\"\n\nusing namespace std;\n\nCPPUNIT_NS_BEGIN\n\nclass EclipseOutputter: public CompilerOutputter\n{\npublic:\n  EclipseOutputter(TestResultCollector *result,ostream &stream):\n        CompilerOutputter(result,stream,\"%p:%l: \"),stream_(stream)\n    {\n    }\n    virtual void printFailedTestName( TestFailure *failure ){}\n    virtual void printFailureMessage( TestFailure *failure )\n    {\n      stream_<<\": \";\n      Message msg = failure->thrownException()->message();\n      stream_<< msg.shortDescription();\n\n      string text;\n      for(int i=0; i<msg.detailCount();i++){\n          text+=msg.detailAt(i);\n          if(i+1!=msg.detailCount())\n              text+=\", \";\n      }\n      if(text.length()!=0)\n          stream_ <<\" [\"<<text<<\"]\";\n      stream_<<\"\\n\";\n    }\n    ostream& stream_;\n};\n\nCPPUNIT_NS_END\n\nint main( int argc, char* argv[] ) { \n   // if command line contains \"-ide\" then this is the post build check\n   // => the output must be in the compiler error format.\n   //bool selfTest = (argc > 1) && (std::string(\"-ide\") == argv[1]);\n   globalTestConfig.addConfigFromCmdLine(argc,argv);\n\n   // Create the event manager and test controller\n   CPPUNIT_NS::TestResult controller;\n   // Add a listener that colllects test result\n   CPPUNIT_NS::TestResultCollector result;\n   controller.addListener( &result );\n   \n   // Add a listener that print dots as tests run.\n   // CPPUNIT_NS::TextTestProgressListener progress;\n   CPPUNIT_NS::BriefTestProgressListener progress;\n   controller.addListener( &progress );\n \n   CPPUNIT_NS::TestRunner runner;\n   runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );\n \n   try\n   {\n     cout << \"Running \"  <<  globalTestConfig.getTestName();\n     runner.run( controller, globalTestConfig.getTestName());\n     cout<<endl;\n\n     // Print test in a compiler compatible format.\n     CPPUNIT_NS::EclipseOutputter outputter( &result,cout);\n     outputter.write(); \n\n // Uncomment this for XML output\n#ifdef ENABLE_XML_OUTPUT\n     std::ofstream file( \"tests.xml\" );\n     CPPUNIT_NS::XmlOutputter xml( &result, file );\n     xml.setStyleSheet( \"report.xsl\" );\n     xml.write();\n     file.close();\n#endif\n   }\n   catch ( std::invalid_argument &e )  // Test path not resolved\n   {\n     cout<<\"\\nERROR: \"<<e.what()<<endl;\n     return 0;\n   }\n\n   return result.wasSuccessful() ? 0 : 1;\n }\n"
  },
  {
    "path": "src/recipes/queue/src/c/tests/Util.cc",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"Util.h\"\n\nconst std::string EMPTY_STRING;\n\nTestConfig globalTestConfig;\n\nvoid millisleep(int ms){\n    timespec ts;\n    ts.tv_sec=ms/1000;\n    ts.tv_nsec=(ms%1000)*1000000; // to nanoseconds\n    nanosleep(&ts,0);\n}\n"
  },
  {
    "path": "src/recipes/queue/src/c/tests/Util.h",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UTIL_H_\n#define UTIL_H_\n\n#include <map>\n#include <vector>\n#include <string>\n\n// number of elements in array\n#define COUNTOF(array) sizeof(array)/sizeof(array[0])\n\n#define DECLARE_WRAPPER(ret,sym,sig) \\\n    extern \"C\" ret __real_##sym sig; \\\n    extern \"C\" ret __wrap_##sym sig\n\n#define CALL_REAL(sym,params) \\\n    __real_##sym params\n\n// must include \"src/zookeeper_log.h\" to be able to use this macro\n#define TEST_TRACE(x) \\\n    log_message(3,__LINE__,__func__,format_log_message x)\n\nextern const std::string EMPTY_STRING;\n\n// *****************************************************************************\n// A bit of wizardry to get to the bare type from a reference or a pointer \n// to the type\ntemplate <class T>\nstruct TypeOp {\n    typedef T BareT;\n    typedef T ArgT;\n};\n\n// partial specialization for reference types\ntemplate <class T>\nstruct TypeOp<T&>{\n    typedef T& ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// partial specialization for pointers\ntemplate <class T>\nstruct TypeOp<T*>{\n    typedef T* ArgT;\n    typedef typename TypeOp<T>::BareT BareT;\n};\n\n// *****************************************************************************\n// Container utilities\n\ntemplate <class K, class V>\nvoid putValue(std::map<K,V>& map,const K& k, const V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        map.insert(typename Map::value_type(k,v));\n    else\n        map[k]=v;\n}\n\ntemplate <class K, class V>\nbool getValue(const std::map<K,V>& map,const K& k,V& v){\n    typedef std::map<K,V> Map;\n    typename Map::const_iterator it=map.find(k);\n    if(it==map.end())\n        return false;\n    v=it->second;\n    return true;\n}\n\n// *****************************************************************************\n// misc utils\n\n// millisecond sleep\nvoid millisleep(int ms);\n// evaluate given predicate until it returns true or the timeout \n// (in millis) has expired\ntemplate<class Predicate>\nint ensureCondition(const Predicate& p,int timeout){\n    int elapsed=0;\n    while(!p() && elapsed<timeout){\n        millisleep(2);\n        elapsed+=2;\n    }\n    return elapsed;\n};\n\n// *****************************************************************************\n// test global configuration data \nclass TestConfig{\n    typedef std::vector<std::string> CmdLineOptList;\npublic:\n    typedef CmdLineOptList::const_iterator const_iterator;\n    TestConfig(){}\n    ~TestConfig(){}\n    void addConfigFromCmdLine(int argc, char* argv[]){\n        if(argc>=2)\n            testName_=argv[1];\n        for(int i=2; i<argc;++i)\n            cmdOpts_.push_back(argv[i]);\n    }\n    const_iterator getExtraOptBegin() const {return cmdOpts_.begin();}\n    const_iterator getExtraOptEnd() const {return cmdOpts_.end();}\n    size_t getExtraOptCount() const {\n        return cmdOpts_.size();\n    }\n    const std::string& getTestName() const {\n        return testName_==\"all\"?EMPTY_STRING:testName_;\n    }\nprivate:\n    CmdLineOptList cmdOpts_;\n    std::string testName_;\n};\n\nextern TestConfig globalTestConfig;\n\n#endif /*UTIL_H_*/\n"
  },
  {
    "path": "src/recipes/queue/src/c/tests/zkServer.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nif [ \"x$1\" == \"x\" ]\nthen\n\techo \"USAGE: $0 startClean|start|stop hostPorts\"\n\texit 2\nfi\n\nif [ \"x$1\" == \"xstartClean\" ]\nthen\n\trm -rf /tmp/zkdata\nfi\n\n# Make sure nothing is left over from before\nif [ -r \"/tmp/zk.pid\" ]\nthen\npid=`cat /tmp/zk.pid`\nkill -9 $pid\nrm -f /tmp/zk.pid\nfi\n\nbase_dir=\"../../../../..\"\n\nCLASSPATH=\"$CLASSPATH:${base_dir}/build/classes\"\nCLASSPATH=\"$CLASSPATH:${base_dir}/conf\"\n\nfor f in \"${base_dir}\"/zookeeper-*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$f\"\ndone\n\nfor i in \"${base_dir}\"/build/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nfor i in \"${base_dir}\"/src/java/lib/*.jar\ndo\n    CLASSPATH=\"$CLASSPATH:$i\"\ndone\n\nCLASSPATH=\"$CLASSPATH:${CLOVER_HOME}/lib/clover.jar\"\n\ncase $1 in\nstart|startClean)\n\tmkdir -p /tmp/zkdata\n\tjava -cp $CLASSPATH org.apache.zookeeper.server.ZooKeeperServerMain 22181 /tmp/zkdata &> /tmp/zk.log &\n        echo $! > /tmp/zk.pid\n        sleep 5\n\t;;\nstop)\n\t# Already killed above\n\t;;\n*)\n\techo \"Unknown command \" + $1\n\texit 2\nesac\n\n"
  },
  {
    "path": "src/recipes/queue/src/java/org/apache/zookeeper/recipes/queue/DistributedQueue.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.zookeeper.recipes.queue;\n\nimport java.util.List;\nimport java.util.NoSuchElementException;\nimport java.util.TreeMap;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * \n * A <a href=\"package.html\">protocol to implement a distributed queue</a>.\n * \n */\n\npublic class DistributedQueue {\n    private static final Logger LOG = LoggerFactory.getLogger(DistributedQueue.class);\n\n    private final String dir;\n\n    private ZooKeeper zookeeper;\n    private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;\n\n    private final String prefix = \"qn-\";\n\n\n    public DistributedQueue(ZooKeeper zookeeper, String dir, List<ACL> acl){\n        this.dir = dir;\n\n        if(acl != null){\n            this.acl = acl;\n        }\n        this.zookeeper = zookeeper;\n\n    }\n\n\n\n    /**\n     * Returns a Map of the children, ordered by id.\n     * @param watcher optional watcher on getChildren() operation.\n     * @return map from id to child name for all children\n     */\n    private TreeMap<Long,String> orderedChildren(Watcher watcher) throws KeeperException, InterruptedException {\n        TreeMap<Long,String> orderedChildren = new TreeMap<Long,String>();\n\n        List<String> childNames = null;\n        try{\n            childNames = zookeeper.getChildren(dir, watcher);\n        }catch (KeeperException.NoNodeException e){\n            throw e;\n        }\n\n        for(String childName : childNames){\n            try{\n                //Check format\n                if(!childName.regionMatches(0, prefix, 0, prefix.length())){\n                    LOG.warn(\"Found child node with improper name: \" + childName);\n                    continue;\n                }\n                String suffix = childName.substring(prefix.length());\n                Long childId = new Long(suffix);\n                orderedChildren.put(childId,childName);\n            }catch(NumberFormatException e){\n                LOG.warn(\"Found child node with improper format : \" + childName + \" \" + e,e);\n            }\n        }\n\n        return orderedChildren;\n    }\n\n    /**\n     * Find the smallest child node.\n     * @return The name of the smallest child node.\n     */\n    private String smallestChildName() throws KeeperException, InterruptedException {\n        long minId = Long.MAX_VALUE;\n        String minName = \"\";\n\n        List<String> childNames = null;\n\n        try{\n            childNames = zookeeper.getChildren(dir, false);\n        }catch(KeeperException.NoNodeException e){\n            LOG.warn(\"Caught: \" +e,e);\n            return null;\n        }\n\n        for(String childName : childNames){\n            try{\n                //Check format\n                if(!childName.regionMatches(0, prefix, 0, prefix.length())){\n                    LOG.warn(\"Found child node with improper name: \" + childName);\n                    continue;\n                }\n                String suffix = childName.substring(prefix.length());\n                long childId = Long.parseLong(suffix);\n                if(childId < minId){\n                    minId = childId;\n                    minName = childName;\n                }\n            }catch(NumberFormatException e){\n                LOG.warn(\"Found child node with improper format : \" + childName + \" \" + e,e);\n            }\n        }\n\n\n        if(minId < Long.MAX_VALUE){\n            return minName;\n        }else{\n            return null;\n        }\n    }\n\n    /**\n     * Return the head of the queue without modifying the queue.\n     * @return the data at the head of the queue.\n     * @throws NoSuchElementException\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public byte[] element() throws NoSuchElementException, KeeperException, InterruptedException {\n        TreeMap<Long,String> orderedChildren;\n\n        // element, take, and remove follow the same pattern.\n        // We want to return the child node with the smallest sequence number.\n        // Since other clients are remove()ing and take()ing nodes concurrently, \n        // the child with the smallest sequence number in orderedChildren might be gone by the time we check.\n        // We don't call getChildren again until we have tried the rest of the nodes in sequence order.\n        while(true){\n            try{\n                orderedChildren = orderedChildren(null);\n            }catch(KeeperException.NoNodeException e){\n                throw new NoSuchElementException();\n            }\n            if(orderedChildren.size() == 0 ) throw new NoSuchElementException();\n\n            for(String headNode : orderedChildren.values()){\n                if(headNode != null){\n                    try{\n                        return zookeeper.getData(dir+\"/\"+headNode, false, null);\n                    }catch(KeeperException.NoNodeException e){\n                        //Another client removed the node first, try next\n                    }\n                }\n            }\n\n        }\n    }\n\n\n    /**\n     * Attempts to remove the head of the queue and return it.\n     * @return The former head of the queue\n     * @throws NoSuchElementException\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public byte[] remove() throws NoSuchElementException, KeeperException, InterruptedException {\n        TreeMap<Long,String> orderedChildren;\n        // Same as for element.  Should refactor this.\n        while(true){\n            try{\n                orderedChildren = orderedChildren(null);\n            }catch(KeeperException.NoNodeException e){\n                throw new NoSuchElementException();\n            }\n            if(orderedChildren.size() == 0) throw new NoSuchElementException();\n\n            for(String headNode : orderedChildren.values()){\n                String path = dir +\"/\"+headNode;\n                try{\n                    byte[] data = zookeeper.getData(path, false, null);\n                    zookeeper.delete(path, -1);\n                    return data;\n                }catch(KeeperException.NoNodeException e){\n                    // Another client deleted the node first.\n                }\n            }\n\n        }\n    }\n\n    private class LatchChildWatcher implements Watcher {\n\n        CountDownLatch latch;\n\n        public LatchChildWatcher(){\n            latch = new CountDownLatch(1);\n        }\n\n        public void process(WatchedEvent event){\n            LOG.debug(\"Watcher fired on path: \" + event.getPath() + \" state: \" + \n                    event.getState() + \" type \" + event.getType());\n            latch.countDown();\n        }\n        public void await() throws InterruptedException {\n            latch.await();\n        }\n    }\n\n    /**\n     * Removes the head of the queue and returns it, blocks until it succeeds.\n     * @return The former head of the queue\n     * @throws NoSuchElementException\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public byte[] take() throws KeeperException, InterruptedException {\n        TreeMap<Long,String> orderedChildren;\n        // Same as for element.  Should refactor this.\n        while(true){\n            LatchChildWatcher childWatcher = new LatchChildWatcher();\n            try{\n                orderedChildren = orderedChildren(childWatcher);\n            }catch(KeeperException.NoNodeException e){\n                zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);\n                continue;\n            }\n            if(orderedChildren.size() == 0){\n                childWatcher.await();\n                continue;\n            }\n\n            for(String headNode : orderedChildren.values()){\n                String path = dir +\"/\"+headNode;\n                try{\n                    byte[] data = zookeeper.getData(path, false, null);\n                    zookeeper.delete(path, -1);\n                    return data;\n                }catch(KeeperException.NoNodeException e){\n                    // Another client deleted the node first.\n                }\n            }\n        }\n    }\n\n    /**\n     * Inserts data into queue.\n     * @param data\n     * @return true if data was successfully added\n     */\n    public boolean offer(byte[] data) throws KeeperException, InterruptedException{\n        for(;;){\n            try{\n                zookeeper.create(dir+\"/\"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);\n                return true;\n            }catch(KeeperException.NoNodeException e){\n                zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);\n            }\n        }\n\n    }\n\n    /**\n     * Returns the data at the first element of the queue, or null if the queue is empty.\n     * @return data at the first element of the queue, or null.\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public byte[] peek() throws KeeperException, InterruptedException{\n        try{\n            return element();\n        }catch(NoSuchElementException e){\n            return null;\n        }\n    }\n\n\n    /**\n     * Attempts to remove the head of the queue and return it. Returns null if the queue is empty.\n     * @return Head of the queue or null.\n     * @throws KeeperException\n     * @throws InterruptedException\n     */\n    public byte[] poll() throws KeeperException, InterruptedException {\n        try{\n            return remove();\n        }catch(NoSuchElementException e){\n            return null;\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "src/recipes/queue/test/org/apache/zookeeper/recipes/queue/DistributedQueueTest.java",
    "content": "/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.zookeeper.recipes.queue;\n\nimport java.util.NoSuchElementException;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.test.ClientBase;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n\n\npublic class DistributedQueueTest extends ClientBase {\n\n    @After\n    public void tearDown() throws Exception {\n        super.tearDown();\n        LOG.info(\"FINISHED \" + getTestName());\n    }\n\n\n    @Test\n    public void testOffer1() throws Exception {\n        String dir = \"/testOffer1\";\n        String testString = \"Hello World\";\n        final int num_clients = 1;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        queueHandles[0].offer(testString.getBytes());\n\n        byte dequeuedBytes[] = queueHandles[0].remove();\n        Assert.assertEquals(new String(dequeuedBytes), testString);\n    }\n\n    @Test\n    public void testOffer2() throws Exception {\n        String dir = \"/testOffer2\";\n        String testString = \"Hello World\";\n        final int num_clients = 2;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        queueHandles[0].offer(testString.getBytes());\n\n        byte dequeuedBytes[] = queueHandles[1].remove();\n        Assert.assertEquals(new String(dequeuedBytes), testString);\n    }\n\n    @Test\n    public void testTake1() throws Exception {\n        String dir = \"/testTake1\";\n        String testString = \"Hello World\";\n        final int num_clients = 1;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        queueHandles[0].offer(testString.getBytes());\n\n        byte dequeuedBytes[] = queueHandles[0].take();\n        Assert.assertEquals(new String(dequeuedBytes), testString);\n    }\n\n\n\n    @Test\n    public void testRemove1() throws Exception{\n        String dir = \"/testRemove1\";\n        String testString = \"Hello World\";\n        final int num_clients = 1;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        try{\n            queueHandles[0].remove();\n        }catch(NoSuchElementException e){\n            return;\n        }\n        Assert.assertTrue(false);\n    }\n\n    public void createNremoveMtest(String dir,int n,int m) throws Exception{\n        String testString = \"Hello World\";\n        final int num_clients = 2;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        for(int i=0; i< n; i++){\n            String offerString = testString + i;\n            queueHandles[0].offer(offerString.getBytes());\n        }\n\n        byte data[] = null;\n        for(int i=0; i<m; i++){\n            data=queueHandles[1].remove();\n        }\n        Assert.assertEquals(new String(data), testString+(m-1));\n    }\n\n    @Test\n    public void testRemove2() throws Exception{\n        createNremoveMtest(\"/testRemove2\",10,2);\n    }\n    @Test\n    public void testRemove3() throws Exception{\n        createNremoveMtest(\"/testRemove3\",1000,1000);\n    }\n\n    public void createNremoveMelementTest(String dir,int n,int m) throws Exception{\n        String testString = \"Hello World\";\n        final int num_clients = 2;\n        ZooKeeper clients[] = new ZooKeeper[num_clients];\n        DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        for(int i=0; i< n; i++){\n            String offerString = testString + i;\n            queueHandles[0].offer(offerString.getBytes());\n        }\n\n        byte data[] = null;\n        for(int i=0; i<m; i++){\n            data=queueHandles[1].remove();\n        }\n        Assert.assertEquals(new String(queueHandles[1].element()), testString+m);\n    }\n\n    @Test\n    public void testElement1() throws Exception {\n        createNremoveMelementTest(\"/testElement1\",1,0);\n    }\n\n    @Test\n    public void testElement2() throws Exception {\n        createNremoveMelementTest(\"/testElement2\",10,2);\n    }\n\n    @Test\n    public void testElement3() throws Exception {\n        createNremoveMelementTest(\"/testElement3\",1000,500);\n    }\n\n    @Test\n    public void testElement4() throws Exception {\n        createNremoveMelementTest(\"/testElement4\",1000,1000-1);\n    }\n\n    @Test\n    public void testTakeWait1() throws Exception{\n        String dir = \"/testTakeWait1\";\n        final String testString = \"Hello World\";\n        final int num_clients = 1;\n        final ZooKeeper clients[] = new ZooKeeper[num_clients];\n        final DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n\n        final byte[] takeResult[] = new byte[1][];\n        Thread takeThread = new Thread(){\n            public void run(){\n                try{\n                    takeResult[0] = queueHandles[0].take();\n                }catch(KeeperException e){\n\n                }catch(InterruptedException e){\n\n                }\n            }\n        };\n        takeThread.start();\n\n        Thread.sleep(1000);\n        Thread offerThread= new Thread() {\n            public void run(){\n                try {\n                    queueHandles[0].offer(testString.getBytes());\n                } catch (KeeperException e) {\n\n                } catch (InterruptedException e) {\n\n                }\n            }\n        };\n        offerThread.start();\n        offerThread.join();\n\n        takeThread.join();\n\n        Assert.assertTrue(takeResult[0] != null);\n        Assert.assertEquals(new String(takeResult[0]), testString);\n    }\n\n    @Test\n    public void testTakeWait2() throws Exception{\n        String dir = \"/testTakeWait2\";\n        final String testString = \"Hello World\";\n        final int num_clients = 1;\n        final ZooKeeper clients[] = new ZooKeeper[num_clients];\n        final DistributedQueue queueHandles[] = new DistributedQueue[num_clients];\n        for(int i=0; i < clients.length; i++){\n            clients[i] = createClient();\n            queueHandles[i] = new DistributedQueue(clients[i], dir, null);\n        }\n        int num_attempts =2;\n        for(int i=0; i< num_attempts; i++){\n            final byte[] takeResult[] = new byte[1][];\n            final String threadTestString = testString + i;\n            Thread takeThread = new Thread(){\n                public void run(){\n                    try{\n                        takeResult[0] = queueHandles[0].take();\n                    }catch(KeeperException e){\n\n                    }catch(InterruptedException e){\n\n                    }\n                }\n            };\n            takeThread.start();\n\n            Thread.sleep(1000);\n            Thread offerThread= new Thread() {\n                public void run(){\n                    try {\n                        queueHandles[0].offer(threadTestString.getBytes());\n                    } catch (KeeperException e) {\n\n                    } catch (InterruptedException e) {\n\n                    }\n                }\n            };\n            offerThread.start();\n            offerThread.join();\n\n            takeThread.join();\n\n            Assert.assertTrue(takeResult[0] != null);\n            Assert.assertEquals(new String(takeResult[0]), threadTestString);\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/zookeeper.jute",
    "content": "/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nmodule org.apache.zookeeper.data {\n    class Id {\n        ustring scheme;\n        ustring id;\n    }\n    class ACL {\n        int perms;\n        Id id;\n    }\n    // information shared with the client\n    class Stat {\n        long czxid;      // created zxid\n        long mzxid;      // last modified zxid\n        long ctime;      // created\n        long mtime;      // last modified\n        int version;     // version\n        int cversion;    // child version\n        int aversion;    // acl version\n        long ephemeralOwner; // owner id if ephemeral, 0 otw\n        int dataLength;  //length of the data in the node\n        int numChildren; //number of children of this node\n        long pzxid;      // last modified children\n    }\n    // information explicitly stored by the server persistently\n    class StatPersisted {\n        long czxid;      // created zxid\n        long mzxid;      // last modified zxid\n        long ctime;      // created\n        long mtime;      // last modified\n        int version;     // version\n        int cversion;    // child version\n        int aversion;    // acl version\n        long ephemeralOwner; // owner id if ephemeral, 0 otw\n        long pzxid;      // last modified children\n    }\n\n   // information explicitly stored by the version 1 database of servers \n   class StatPersistedV1 {\n       long czxid; //created zxid\n       long mzxid; //last modified zxid\n       long ctime; //created\n       long mtime; //last modified\n       int version; //version\n       int cversion; //child version\n       int aversion; //acl version\n       long ephemeralOwner; //owner id if ephemeral. 0 otw\n    }\n}\n\nmodule org.apache.zookeeper.proto {\n    class ConnectRequest {\n        int protocolVersion;\n        long lastZxidSeen;\n        int timeOut;\n        long sessionId;\n        buffer passwd;\n    }\n    class ConnectResponse {\n        int protocolVersion;\n        int timeOut;\n        long sessionId;\n        buffer passwd;\n    }\n    class SetWatches {\n        long relativeZxid;\n        vector<ustring>dataWatches;\n        vector<ustring>existWatches;\n        vector<ustring>childWatches;\n    }        \n    class RequestHeader {\n        int xid;\n        int type;\n    }\n    class MultiHeader {\n        int type;\n        boolean done;\n        int err;\n    }\n    class AuthPacket {\n        int type;\n        ustring scheme;\n        buffer auth;\n    }\n    class ReplyHeader {\n        int xid;\n        long zxid;\n        int err;\n    }\n    class GetDataRequest {\n        ustring path;\n        boolean watch;\n    }\n    class SetDataRequest {\n        ustring path;\n        buffer data;\n        int version;\n    }\n    class SetDataResponse {\n        org.apache.zookeeper.data.Stat stat;\n    }\n    class GetSASLRequest {\n        buffer token;\n    }\n    class SetSASLRequest {\n        buffer token;\n    }\n    class SetSASLResponse {\n        buffer token;\n    }\n    class CreateRequest {\n        ustring path;\n        buffer data;\n        vector<org.apache.zookeeper.data.ACL> acl;\n        int flags;\n    }\n    class DeleteRequest {\n        ustring path;\n        int version;\n    }\n    class GetChildrenRequest {\n        ustring path;\n        boolean watch;\n    }\n    class GetChildren2Request {\n        ustring path;\n        boolean watch;\n    }\n    class CheckVersionRequest {\n        ustring path;\n        int version;\n    }\n    class GetMaxChildrenRequest {\n        ustring path;\n    }\n    class GetMaxChildrenResponse {\n        int max;\n    }\n    class SetMaxChildrenRequest {\n        ustring path;\n        int max;\n    }\n    class SyncRequest {\n        ustring path;\n    }\n    class SyncResponse {\n        ustring path;\n    }\n    class GetACLRequest {\n        ustring path;\n    }\n    class SetACLRequest {\n        ustring path;\n        vector<org.apache.zookeeper.data.ACL> acl;\n        int version;\n    }\n    class SetACLResponse {\n        org.apache.zookeeper.data.Stat stat;\n    }\n    class WatcherEvent {\n        int type;  // event type\n        int state; // state of the Keeper client runtime\n        ustring path;\n    }\n    class ErrorResponse {\n        int err;\n    }\n    class CreateResponse {\n        ustring path;\n    }\n    class ExistsRequest {\n        ustring path;\n        boolean watch;\n    }\n    class ExistsResponse {\n        org.apache.zookeeper.data.Stat stat;\n    }\n    class GetDataResponse {\n        buffer data;\n        org.apache.zookeeper.data.Stat stat;\n    }\n    class GetChildrenResponse {\n        vector<ustring> children;\n    }\n    class GetChildren2Response {\n        vector<ustring> children;\n        org.apache.zookeeper.data.Stat stat;\n    }\n    class GetACLResponse {\n        vector<org.apache.zookeeper.data.ACL> acl;\n        org.apache.zookeeper.data.Stat stat;\n    }\n}\n\nmodule org.apache.zookeeper.server.quorum {\n    class LearnerInfo {\n        long serverid;\n        int protocolVersion;\n    }\n    class QuorumPacket {\n        int type; // Request, Ack, Commit, Ping\n        long zxid;\n        buffer data; // Only significant when type is request\n        vector<org.apache.zookeeper.data.Id> authinfo;\n    }\n    class QuorumAuthPacket {\n        long magic;\n        int status;\n        buffer token;\n    }\n}\n\nmodule org.apache.zookeeper.server.persistence {\n    class FileHeader {\n        int magic;\n        int version;\n        long dbid;\n    }\n}\n\nmodule org.apache.zookeeper.txn {\n    class TxnHeader {\n        long clientId;\n        int cxid;\n        long zxid;\n        long time;\n        int type;\n    }\n    class CreateTxnV0 {\n        ustring path;\n        buffer data;\n        vector<org.apache.zookeeper.data.ACL> acl;\n        boolean ephemeral;\n    }\n    class CreateTxn {\n        ustring path;\n        buffer data;\n        vector<org.apache.zookeeper.data.ACL> acl;\n        boolean ephemeral;\n        int parentCVersion;\n    }\n    class DeleteTxn {\n        ustring path;\n    }\n    class SetDataTxn {\n        ustring path;\n        buffer data;\n        int version;\n    }\n    class CheckVersionTxn {\n        ustring path;\n        int version;\n    }\n    class SetACLTxn {\n        ustring path;\n        vector<org.apache.zookeeper.data.ACL> acl;\n        int version;\n    }\n    class SetMaxChildrenTxn {\n        ustring path;\n        int max;\n    }\n    class CreateSessionTxn {\n        int timeOut;\n    }\n    class ErrorTxn {\n        int err;\n    }\n    class Txn {\n        int type;\n        buffer data;\n    }\n    class MultiTxn {\n        vector<org.apache.zookeeper.txn.Txn> txns;\n    }\n}\n"
  }
]